mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-05 10:48:29 +00:00
Add HTTP/HTTPS Fetch() API to redbean
You can now say the following in your redbean Lua code: status,headers,payload = Fetch("https://foo.example") The following Lua APIs have been introduced: - Fetch(str) → str,{str:str},str - GetHttpReason(int) → str - GetHttpReason(int) → str - ProgramSslFetchVerify(bool) - ProgramSslClientVerify(bool) The following flags have been introduced: - `-j` enables client SSL verification - `-k` disables Fetch() SSL verification - `-t INT` may now be passed a negative value for keepalive Lua exceptions now invoke Cosmopolitan's garbage collector when unwinding the stack. So it's now safe to use _gc() w/ Lua 𝔱𝔥𝔯𝔬𝔴 See #97
This commit is contained in:
parent
36b2710e1a
commit
c89bc56f6a
35 changed files with 1611 additions and 591 deletions
96
tool/build/deltaify.c
Normal file
96
tool/build/deltaify.c
Normal file
|
@ -0,0 +1,96 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/sigbits.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/struct/siginfo.h"
|
||||
#include "libc/calls/ucontext.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/sysv/consts/sa.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
static int pid;
|
||||
|
||||
static void RelaySig(int sig, struct siginfo *si, struct ucontext *uc) {
|
||||
kill(pid, sig);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
FILE *f;
|
||||
char *s;
|
||||
bool ok;
|
||||
int64_t micros;
|
||||
long double t1, t2;
|
||||
int ws, pipefds[2];
|
||||
t1 = nowl();
|
||||
if (argc < 2) {
|
||||
f = stdin;
|
||||
} else {
|
||||
sigset_t block, mask;
|
||||
struct sigaction saignore = {.sa_handler = SIG_IGN};
|
||||
struct sigaction sadefault = {.sa_handler = SIG_DFL};
|
||||
struct sigaction sarelay = {.sa_sigaction = RelaySig,
|
||||
.sa_flags = SA_RESTART};
|
||||
sigemptyset(&block);
|
||||
sigaddset(&mask, SIGINT);
|
||||
sigaddset(&mask, SIGQUIT);
|
||||
sigaddset(&mask, SIGCHLD);
|
||||
sigprocmask(SIG_BLOCK, &block, &mask);
|
||||
sigaction(SIGHUP, &sarelay, 0);
|
||||
sigaction(SIGTERM, &sarelay, 0);
|
||||
sigaction(SIGINT, &saignore, 0);
|
||||
sigaction(SIGQUIT, &saignore, 0);
|
||||
CHECK_NE(-1, pipe(pipefds));
|
||||
CHECK_NE(-1, (pid = vfork()));
|
||||
if (!pid) {
|
||||
close(pipefds[0]);
|
||||
dup2(pipefds[1], 1);
|
||||
sigaction(SIGHUP, &sadefault, NULL);
|
||||
sigaction(SIGTERM, &sadefault, NULL);
|
||||
sigaction(SIGINT, &sadefault, NULL);
|
||||
sigaction(SIGQUIT, &sadefault, NULL);
|
||||
sigprocmask(SIG_SETMASK, &mask, NULL);
|
||||
execvp(argv[1], argv + 1);
|
||||
_exit(127);
|
||||
}
|
||||
close(pipefds[1]);
|
||||
sigprocmask(SIG_SETMASK, &mask, NULL);
|
||||
CHECK((f = fdopen(pipefds[0], "r")));
|
||||
CHECK_NE(-1, setvbuf(f, malloc(4096), _IOLBF, 4096));
|
||||
}
|
||||
for (;;) {
|
||||
if (!(s = xgetline(f))) break;
|
||||
t2 = nowl();
|
||||
micros = (t2 - t1) * 1e6;
|
||||
t1 = t2;
|
||||
printf("%,16ld %s", micros, s);
|
||||
free(s);
|
||||
}
|
||||
ok = !ferror(f);
|
||||
if (argc < 2) return ok ? 0 : 1;
|
||||
fclose(f);
|
||||
while (waitpid(pid, &ws, 0) == -1) CHECK_EQ(EINTR, errno);
|
||||
return !WIFEXITED(ws) ? 128 + WTERMSIG(ws) : ok ? WEXITSTATUS(ws) : 1;
|
||||
}
|
|
@ -84,12 +84,14 @@ C(sslcantciphers)
|
|||
C(sslhandshakefails)
|
||||
C(sslhandshakes)
|
||||
C(sslnociphers)
|
||||
C(sslnoclientcert)
|
||||
C(sslnoversion)
|
||||
C(sslshakemacs)
|
||||
C(ssltimeouts)
|
||||
C(sslunknownca)
|
||||
C(sslunknowncert)
|
||||
C(sslupgrades)
|
||||
C(sslverifyfailed)
|
||||
C(statfails)
|
||||
C(staticrequests)
|
||||
C(stats)
|
||||
|
|
74
tool/net/demo/fetch.lua
Normal file
74
tool/net/demo/fetch.lua
Normal file
|
@ -0,0 +1,74 @@
|
|||
-- Fetch() API Demo
|
||||
|
||||
local function WriteForm(url)
|
||||
Write('<!doctype html>\r\n')
|
||||
Write(string.format([[
|
||||
<title>redbean fetch demo</title>
|
||||
<style>
|
||||
body {
|
||||
padding: 1em;
|
||||
}
|
||||
h1 a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
h1 img {
|
||||
vertical-align: middle;
|
||||
}
|
||||
input {
|
||||
margin: 1em;
|
||||
padding: .5em;
|
||||
}
|
||||
p {
|
||||
word-break: break-word;
|
||||
}
|
||||
p span {
|
||||
display: block;
|
||||
text-indent: -1em;
|
||||
padding-left: 1em;
|
||||
}
|
||||
</style>
|
||||
<h1>
|
||||
<a href="/"><img src="/redbean.png"></a>
|
||||
<a href="fetch.lua">redbean fetch demo</a>
|
||||
</h1>
|
||||
<form action="fetch.lua" method="post">
|
||||
<input type="text" id="url" name="url" size="70"
|
||||
value="%s" placeholder="uri" autofocus>
|
||||
<input type="submit" value="fetch">
|
||||
</form>
|
||||
]], EscapeHtml(url)))
|
||||
end
|
||||
|
||||
local function main()
|
||||
if IsPublicIp(GetClientAddr()) then
|
||||
ServeError(403)
|
||||
elseif GetMethod() == 'GET' or GetMethod() == 'HEAD' then
|
||||
WriteForm("https://www.cloudflare.com/robots.txt")
|
||||
elseif GetMethod() == 'POST' then
|
||||
status, headers, payload = Fetch(GetParam('url'))
|
||||
WriteForm(GetParam('url'))
|
||||
Write('<dl>\r\n')
|
||||
Write('<dt>Status\r\n')
|
||||
Write(string.format('<dd><p>%d %s\r\n', status, GetHttpReason(status)))
|
||||
Write('<dt>Headers\r\n')
|
||||
Write('<dd><p>\r\n')
|
||||
for k,v in pairs(headers) do
|
||||
Write('<span><strong>')
|
||||
Write(EscapeHtml(k))
|
||||
Write('</strong>: ')
|
||||
Write(EscapeHtml(v))
|
||||
Write('</span>\r\n')
|
||||
end
|
||||
Write('<dt>Payload\r\n')
|
||||
Write('<dd><pre>')
|
||||
Write(EscapeHtml(VisualizeControlCodes(payload)))
|
||||
Write('</pre>\r\n')
|
||||
Write('</dl>\r\n')
|
||||
else
|
||||
ServeError(405)
|
||||
SetHeader('Allow', 'GET, HEAD, POST')
|
||||
end
|
||||
end
|
||||
|
||||
main()
|
|
@ -1,2 +1,4 @@
|
|||
StoreAsset('/hi', 'sup')
|
||||
if not IsPublicIp(GetClientAddr()) then
|
||||
StoreAsset('/hi', 'sup')
|
||||
end
|
||||
mymodule.hello()
|
||||
|
|
|
@ -34,8 +34,10 @@ FLAGS
|
|||
-b log message bodies
|
||||
-a log resource usage
|
||||
-g log handler latency
|
||||
-f log worker function calls
|
||||
-j enable ssl client verify
|
||||
-k disable ssl fetch verify
|
||||
-B use stronger cryptography
|
||||
-f log worker function calls
|
||||
-s increase silence [repeatable]
|
||||
-v increase verbosity [repeatable]
|
||||
-V increase ssl verbosity [repeatable]
|
||||
|
@ -45,8 +47,8 @@ FLAGS
|
|||
-R /X=/Y rewrites X to Y [repeatable]
|
||||
-K PATH tls private key path [repeatable]
|
||||
-C PATH tls certificate(s) path [repeatable]
|
||||
-t MS tunes read and write timeouts [def. 60000]
|
||||
-M INT tunes max message payload size [def. 65536]
|
||||
-t INT timeout ms or keepalive sec if <0 [def. 60000]
|
||||
-p PORT listen port [def. 8080; repeatable]
|
||||
-l ADDR listen addr [def. 0.0.0.0; repeatable]
|
||||
-c SEC configures static cache-control
|
||||
|
|
|
@ -50,6 +50,7 @@ TOOL_NET_DIRECTDEPS = \
|
|||
LIBC_X \
|
||||
LIBC_ZIPOS \
|
||||
NET_HTTP \
|
||||
NET_HTTPS \
|
||||
THIRD_PARTY_GDTOA \
|
||||
THIRD_PARTY_GETOPT \
|
||||
THIRD_PARTY_LUA \
|
||||
|
@ -130,6 +131,7 @@ o/$(MODE)/tool/net/redbean-demo.com: \
|
|||
tool/net/demo/seekable.txt \
|
||||
tool/net/demo/virtualbean.html \
|
||||
tool/net/demo/printpayload.lua \
|
||||
tool/net/demo/fetch.lua \
|
||||
tool/net/redbean.c \
|
||||
net/http/parsehttpmessage.c \
|
||||
net/http/parseurl.c \
|
||||
|
@ -145,10 +147,10 @@ o/$(MODE)/tool/net/redbean-demo.com: \
|
|||
@(cd o/$(MODE)/tool/net && ../../host/third_party/infozip/zip.com -qr redbean-demo.com .lua)
|
||||
@$(COMPILE) -AZIP -T$@ o/$(MODE)/host/third_party/infozip/zip.com -qj $@ tool/net/demo/hello.lua tool/net/demo/sql.lua
|
||||
@echo "<-- check out this lua server page" | $(COMPILE) -AZIP -T$@ o/$(MODE)/host/third_party/infozip/zip.com -cqj $@ tool/net/demo/redbean.lua
|
||||
@$(COMPILE) -AZIP -T$@ o/$(MODE)/host/third_party/infozip/zip.com -qj $@ tool/net/demo/404.html tool/net/favicon.ico tool/net/redbean.png tool/net/demo/redbean-form.lua tool/net/demo/redbean-xhr.lua tool/net/demo/printpayload.lua
|
||||
@$(COMPILE) -AZIP -T$@ o/$(MODE)/host/third_party/infozip/zip.com -qj $@ tool/net/demo/404.html tool/net/favicon.ico tool/net/redbean.png tool/net/demo/redbean-form.lua tool/net/demo/redbean-xhr.lua tool/net/demo/printpayload.lua tool/net/demo/fetch.lua
|
||||
@echo Uncompressed for HTTP Range requests | $(COMPILE) -AZIP -T$@ o/$(MODE)/host/third_party/infozip/zip.com -cqj0 $@ tool/net/demo/seekable.txt
|
||||
@$(COMPILE) -AZIP -T$@ o/$(MODE)/host/third_party/infozip/zip.com -q $@ tool/net/ tool/net/demo/ tool/net/demo/index.html tool/net/demo/redbean.css tool/net/redbean.c net/http/parsehttpmessage.c net/http/parseurl.c net/http/encodeurl.c test/net/http/parsehttpmessage_test.c test/net/http/parseurl_test.c
|
||||
@printf "<p>This is a live instance of <a href=https://justine.lol/redbean/>redbean</a>: a tiny multiplatform webserver that <a href=https://news.ycombinator.com/item?id=26271117>went viral</a> on hacker news a few months ago.\r\nSince then, we've added Lua dynamic serving, which also goes as fast as 1,000,000 requests per second on a core i9 (rather than a cheap virtual machine like this)\nin addition to SQLite and SSL. The text you're reading now is a PKZIP End Of Central Directory comment.\r\n<p>redbean aims to be production worthy across six operating systems, using a single executable file (this demo is hosted on FreeBSD 13). redbean has been enhanced to restore the APE header after startup.\r\nIt automatically generates this listing page based on your zip contents. If you use redbean as an application server / web development environment,\r\nthen you'll find other new and useful features like function call logging so you can get that sweet sweet microsecond scale latency." | $(COMPILE) -AZIP -T$@ o/$(MODE)/host/third_party/infozip/zip.com -z $@
|
||||
@printf "<p>Thank you for using <a href=https://justine.lol/redbean/>redbean</a> the tiniest most vertically integrated actually portable web server with superior performance." | $(COMPILE) -AZIP -T$@ o/$(MODE)/host/third_party/infozip/zip.com -z $@
|
||||
@$(COMPILE) -AMKDIR -T$@ mkdir -p o/$(MODE)/tool/net/virtualbean.justine.lol/
|
||||
@$(COMPILE) -ACP -T$@ cp tool/net/redbean.png o/$(MODE)/tool/net/virtualbean.justine.lol/redbean.png
|
||||
@$(COMPILE) -ACP -T$@ cp tool/net/demo/virtualbean.html o/$(MODE)/tool/net/virtualbean.justine.lol/index.html
|
||||
|
|
1104
tool/net/redbean.c
1104
tool/net/redbean.c
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue