mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-23 19:10:30 +00:00
Make more major improvements to redbean
- POSIX regular expressions for Lua - Improved protocol parsing and encoding - Additional APIs for ZIP storage retrieval - Fix st_mode issue on NT for regular files - Generalized APIs for URL and Host handling - Worked out the kinks in resource resolution - Allow for custom error pages like /404.html
This commit is contained in:
parent
26ac6871da
commit
4effa23528
74 changed files with 3710 additions and 14246 deletions
11
tool/net/404.html
Normal file
11
tool/net/404.html
Normal file
|
@ -0,0 +1,11 @@
|
|||
<!doctype html>
|
||||
<title>404 not found</title>
|
||||
|
||||
<pre aria-label="404 not found">
|
||||
_ _ ___ _ _ _ __ _
|
||||
| || | / _ \| || | _ __ ___ | |_ / _| ___ _ _ _ __ __| |
|
||||
| || |_| | | | || |_ | '_ \ / _ \| __| | |_ / _ \| | | | '_ \ / _` |
|
||||
|__ _| |_| |__ _| | | | | (_) | |_ | _| (_) | |_| | | | | (_| |
|
||||
|_| \___/ |_| |_| |_|\___/ \__| |_| \___/ \__,_|_| |_|\__,_|
|
||||
|
||||
</pre>
|
|
@ -42,6 +42,7 @@ TOOL_NET_DIRECTDEPS = \
|
|||
NET_HTTP \
|
||||
THIRD_PARTY_GETOPT \
|
||||
THIRD_PARTY_LUA \
|
||||
THIRD_PARTY_REGEX \
|
||||
THIRD_PARTY_ZLIB \
|
||||
TOOL_DECODE_LIB
|
||||
|
||||
|
@ -80,17 +81,54 @@ o/$(MODE)/tool/net/redbean.com: \
|
|||
|
||||
o/$(MODE)/tool/net/redbean-demo.com: \
|
||||
o/$(MODE)/tool/net/redbean.com \
|
||||
tool/net/redbean.mk \
|
||||
tool/net/net.mk \
|
||||
tool/net/404.html \
|
||||
tool/net/index.html \
|
||||
tool/net/redbean.css \
|
||||
tool/net/redbean.lua \
|
||||
tool/net/redbean-form.lua \
|
||||
tool/net/redbean-xhr.lua \
|
||||
$(TOOL_NET_HDRS) \
|
||||
$(TOOL_NET_SRCS)
|
||||
tool/net/seekable.txt \
|
||||
tool/net/redbean.c \
|
||||
net/http/parsehttprequest.c \
|
||||
net/http/parseurl.c \
|
||||
net/http/encodeurl.c \
|
||||
test/net/http/parsehttprequest_test.c \
|
||||
test/net/http/parseurl_test.c
|
||||
@$(COMPILE) -ACP -T$@ cp $< $@
|
||||
@$(COMPILE) -AZIP -T$@ zip -qj $@ tool/net/redbean.lua tool/net/redbean-form.lua tool/net/redbean-xhr.lua
|
||||
@$(COMPILE) -AZIP -T$@ zip -q $@ tool/net tool/net/index.html tool/net/redbean.css $(TOOL_NET_HDRS) $(TOOL_NET_SRCS)
|
||||
@$(COMPILE) -ADD -T$@ dd if=$@ of=o/$(MODE)/tool/net/.ape bs=64 count=11 conv=notrunc 2>/dev/null
|
||||
@$(COMPILE) -AZIP -T$@ zip -qj $@ o/$(MODE)/tool/net/.ape tool/net/404.html tool/net/redbean.lua tool/net/redbean-form.lua tool/net/redbean-xhr.lua
|
||||
@$(COMPILE) -AZIP -T$@ zip -qj0 $@ tool/net/seekable.txt
|
||||
@$(COMPILE) -AZIP -T$@ zip -q $@ tool/net tool/net/index.html tool/net/redbean.css tool/net/redbean.c net/http/parsehttprequest.c net/http/parseurl.c net/http/encodeurl.c test/net/http/parsehttprequest_test.c test/net/http/parseurl_test.c
|
||||
|
||||
o/$(MODE)/tool/net/redbean-static.com: \
|
||||
o/$(MODE)/tool/net/redbean-static.com.dbg \
|
||||
tool/net/favicon.ico \
|
||||
tool/net/redbean.png
|
||||
@$(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -S -O binary $< $@
|
||||
@$(COMPILE) -ADD -T$@ dd if=$@ of=o/$(MODE)/tool/net/.ape bs=64 count=11 conv=notrunc 2>/dev/null
|
||||
@$(COMPILE) -AZIP -T$@ zip -qj $@ o/$(MODE)/tool/net/.ape tool/net/favicon.ico tool/net/redbean.png
|
||||
|
||||
o/$(MODE)/tool/net/redbean-bench.com.dbg: \
|
||||
$(TOOL_NET_DEPS) \
|
||||
o/$(MODE)/tool/net/redbean.o \
|
||||
o/$(MODE)/tool/net/index.html.zip.o \
|
||||
o/$(MODE)/tool/net/redbean.lua.zip.o \
|
||||
o/$(MODE)/tool/net/net.pkg \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
@$(APELINK)
|
||||
|
||||
o/$(MODE)/tool/net/redbean-static.com.dbg: \
|
||||
$(TOOL_NET_DEPS) \
|
||||
o/$(MODE)/tool/net/redbean-static.o \
|
||||
o/$(MODE)/tool/net/net.pkg \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
@$(APELINK)
|
||||
|
||||
o/$(MODE)/tool/net/redbean-static.o: tool/net/redbean.c
|
||||
@$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.c) -DSTATIC $(OUTPUT_OPTION) $<
|
||||
|
||||
.PHONY: o/$(MODE)/tool/net
|
||||
o/$(MODE)/tool/net: \
|
||||
|
|
|
@ -8,9 +8,9 @@ local function main()
|
|||
end
|
||||
SetStatus(200)
|
||||
SetHeader('Content-Type', 'text/html; charset=utf-8')
|
||||
Write('<!doctype html>\n')
|
||||
Write('<title>redbean</title>\n')
|
||||
Write('<h3>POST Request HTML Form Handler Demo</h3>\n')
|
||||
Write('<!doctype html>\r\n')
|
||||
Write('<title>redbean</title>\r\n')
|
||||
Write('<h3>POST Request HTML Form Handler Demo</h3>\r\n')
|
||||
|
||||
Write('<p>')
|
||||
firstname = GetParam('firstname')
|
||||
|
@ -24,47 +24,47 @@ local function main()
|
|||
Write('Thank you for using redbean.')
|
||||
end
|
||||
|
||||
Write('<dl>\n')
|
||||
Write('<dl>\r\n')
|
||||
|
||||
Write('<dt>Params\n')
|
||||
Write('<dd>\n')
|
||||
Write('<dl>\n')
|
||||
Write('<dt>Params\r\n')
|
||||
Write('<dd>\r\n')
|
||||
Write('<dl>\r\n')
|
||||
params = GetParams()
|
||||
for i = 1,#params do
|
||||
Write('<dt>')
|
||||
Write(EscapeHtml(params[i][1]))
|
||||
Write('\n')
|
||||
Write('\r\n')
|
||||
if params[i][2] then
|
||||
Write('<dd>')
|
||||
Write(EscapeHtml(params[i][2]))
|
||||
Write('\n')
|
||||
Write('\r\n')
|
||||
end
|
||||
end
|
||||
Write('</dl>\n')
|
||||
Write('</dl>\r\n')
|
||||
|
||||
Write('<dt>Headers\n')
|
||||
Write('<dd>\n')
|
||||
Write('<dl>\n')
|
||||
Write('<dt>Headers\r\n')
|
||||
Write('<dd>\r\n')
|
||||
Write('<dl>\r\n')
|
||||
for k,v in pairs(GetHeaders()) do
|
||||
Write('<dt>')
|
||||
Write(EscapeHtml(k))
|
||||
Write('\n')
|
||||
Write('\r\n')
|
||||
Write('<dd>')
|
||||
Write(EscapeHtml(v))
|
||||
Write('\n')
|
||||
Write('\r\n')
|
||||
end
|
||||
Write('</dl>\n')
|
||||
Write('</dl>\r\n')
|
||||
|
||||
Write('<dt>Payload\n')
|
||||
Write('<dt>Payload\r\n')
|
||||
Write('<dd><p>')
|
||||
Write(EscapeHtml(GetPayload()))
|
||||
Write('\n')
|
||||
Write('\r\n')
|
||||
|
||||
Write('</dl>\n')
|
||||
Write('</dl>\r\n')
|
||||
|
||||
Write('<p>')
|
||||
Write('<a href="redbean.lua">Click here</a> ')
|
||||
Write('to return to the previous page.\n')
|
||||
Write('to return to the previous page.\r\n')
|
||||
end
|
||||
|
||||
main()
|
||||
|
|
1959
tool/net/redbean.c
1959
tool/net/redbean.c
File diff suppressed because it is too large
Load diff
|
@ -1,5 +1,19 @@
|
|||
-- redbean lua server page demo
|
||||
|
||||
local function DescribeIp(ip)
|
||||
Write(' <small>[')
|
||||
if IsPrivateIp(ip) then
|
||||
Write('PRIVATE')
|
||||
elseif IsTestIp(ip) then
|
||||
Write('TESTNET')
|
||||
elseif IsLocalIp(ip) then
|
||||
Write('LOCALNET')
|
||||
else
|
||||
Write('PUBLIC')
|
||||
end
|
||||
Write(']</small>')
|
||||
end
|
||||
|
||||
local function main()
|
||||
-- This is the best way to print data to the console or log file.
|
||||
Log(kLogWarn, "hello from \e[1mlua\e[0m!")
|
||||
|
@ -18,9 +32,9 @@ local function main()
|
|||
|
||||
-- Response data is buffered until the script finishes running.
|
||||
-- Compression is applied automatically, based on your headers.
|
||||
Write('<!doctype html>\n')
|
||||
Write('<title>redbean</title>\n')
|
||||
Write('<h1>redbean lua server page demo</h1>\n')
|
||||
Write('<!doctype html>\r\n')
|
||||
Write('<title>redbean</title>\r\n')
|
||||
Write('<h1>redbean lua server page demo</h1>\r\n')
|
||||
|
||||
-- Prevent caching.
|
||||
-- We need this because we're doing things like putting the client's
|
||||
|
@ -28,43 +42,49 @@ local function main()
|
|||
SetHeader('Expires', FormatHttpDateTime(GetDate()))
|
||||
SetHeader('Cache-Control', 'no-cache, must-revalidate, max-age=0')
|
||||
|
||||
-- GetParams() returns an ordered list of Request-URI query params.
|
||||
Write('<h3>request uri parameters</h3>\n')
|
||||
params = GetParams()
|
||||
if #params > 0 then
|
||||
Write('<dl>\n')
|
||||
-- Roundtripping information can make it safer.
|
||||
Write('<p>Thank you for visiting ')
|
||||
Write(EscapeHtml(EncodeUrl(ParseUrl(GetUrl()))))
|
||||
Write('\r\n')
|
||||
|
||||
-- GetParam(NAME) is the fastest easiest way to get URL and FORM params
|
||||
-- If you want the RequestURL query params specifically in full do this
|
||||
Write('<h3>request url parameters</h3>\r\n')
|
||||
params = ParseUrl(GetUrl()).params -- like GetParams() but w/o form body
|
||||
if params and #params>0 then
|
||||
Write('<dl>\r\n')
|
||||
for i = 1,#params do
|
||||
Write('<dt>')
|
||||
Write(EscapeHtml(params[i][1]))
|
||||
Write('\n')
|
||||
Write('\r\n')
|
||||
if params[i][2] then
|
||||
Write('<dd>')
|
||||
Write(EscapeHtml(params[i][2]))
|
||||
Write('\n')
|
||||
Write('\r\n')
|
||||
end
|
||||
end
|
||||
Write('</dl>\n')
|
||||
Write('</dl>\r\n')
|
||||
else
|
||||
Write('<p>\n')
|
||||
Write('<em>none</em><br>\n')
|
||||
Write('<p>\r\n')
|
||||
Write('<em>none</em><br>\r\n')
|
||||
Write('ProTip: Try <a href="')
|
||||
Write(EscapeHtml(EscapePath(GetPath()) .. '?x=hi%20there&y&z&z=' .. EscapeParam('&')))
|
||||
Write('">clicking here</a>!\n')
|
||||
Write('">clicking here</a>!\r\n')
|
||||
end
|
||||
|
||||
-- Access redbean command line arguments.
|
||||
-- These are the ones that come *after* the redbean server arguments.
|
||||
Write('<h3>command line arguments</h3>\n')
|
||||
-- redbean command line arguments
|
||||
-- these come *after* the c getopt server arguments
|
||||
Write('<h3>command line arguments</h3>\r\n')
|
||||
if #argv > 0 then
|
||||
Write('<ul>\n')
|
||||
Write('<ul>\r\n')
|
||||
for i = 1,#argv do
|
||||
Write('<li>')
|
||||
Write(EscapeHtml(argv[i]))
|
||||
Write('\n')
|
||||
Write('\r\n')
|
||||
end
|
||||
Write('</ul>\n')
|
||||
Write('</ul>\r\n')
|
||||
else
|
||||
Write('<p><em>none</em>\n')
|
||||
Write('<p><em>none</em>\r\n')
|
||||
end
|
||||
|
||||
Write([[
|
||||
|
@ -100,16 +120,227 @@ local function main()
|
|||
</script>
|
||||
]])
|
||||
|
||||
Write('<h3>extra information</h3>\n')
|
||||
Write('<dt>GetClientAddr()\n')
|
||||
Write('<h3>statistics</h3>\r\n')
|
||||
Write('<dl>\r\n')
|
||||
Write('<dt>GetStatistics().workers\r\n')
|
||||
Write('<dd>')
|
||||
Write(GetClientAddr())
|
||||
Write('\n')
|
||||
Write('<dt>GetServerAddr()\n')
|
||||
Write(tostring(GetStatistics().workers))
|
||||
Write('\r\n')
|
||||
Write('<dt>GetStatistics().requestshandled\r\n')
|
||||
Write('<dd>')
|
||||
Write(GetServerAddr())
|
||||
Write('\n')
|
||||
Write('</dl>\n')
|
||||
Write(tostring(GetStatistics().requestshandled))
|
||||
Write('\r\n')
|
||||
Write('<dt>GetStatistics().uptime\r\n')
|
||||
Write('<dd>')
|
||||
Write(tostring(GetStatistics().uptime))
|
||||
Write(' seconds\r\n')
|
||||
Write('</dl>\r\n')
|
||||
|
||||
-- fast redbean apis for accessing already parsed request data
|
||||
Write('<h3>extra information</h3>\r\n')
|
||||
Write('<dl>\r\n')
|
||||
Write('<dt>GetMethod()\r\n')
|
||||
Write('<dd>')
|
||||
Write(EscapeHtml(GetMethod())) -- & and ' are legal in http methods
|
||||
Write('\r\n')
|
||||
if GetUser() then
|
||||
Write('<dt>GetUser()\r\n')
|
||||
Write('<dd>')
|
||||
Write(EscapeHtml(GetUser()))
|
||||
Write('\r\n')
|
||||
end
|
||||
if GetScheme() then
|
||||
Write('<dt>GetScheme()\r\n')
|
||||
Write('<dd>')
|
||||
Write(GetScheme())
|
||||
Write('\r\n')
|
||||
end
|
||||
if GetPass() then
|
||||
Write('<dt>GetPass()\r\n')
|
||||
Write('<dd>')
|
||||
Write(EscapeHtml(GetPass()))
|
||||
Write('\r\n')
|
||||
end
|
||||
Write('<dt>GetHost() <small>(from HTTP Request-URL or Host header)</small>\r\n')
|
||||
Write('<dd>')
|
||||
Write(EscapeHtml(GetHost()))
|
||||
Write('\r\n')
|
||||
Write('<dt>GetPort() <small>(from HTTP Request-URL or Host header)</small>\r\n')
|
||||
Write('<dd>')
|
||||
Write(tostring(GetPort()))
|
||||
Write('\r\n')
|
||||
Write('<dt>GetPath()\r\n')
|
||||
Write('<dd>')
|
||||
Write(EscapeHtml(GetPath()))
|
||||
Write('\r\n')
|
||||
if GetFragment() then
|
||||
Write('<dt>GetFragment()\r\n')
|
||||
Write('<dd>')
|
||||
Write(EscapeHtml(GetFragment()))
|
||||
Write('\r\n')
|
||||
end
|
||||
Write('<dt>GetClientIp()\r\n')
|
||||
Write('<dd>')
|
||||
Write(FormatIp(GetClientIp()))
|
||||
DescribeIp(GetClientIp())
|
||||
Write('\r\n')
|
||||
Write('<dt>GetClientPort()\r\n')
|
||||
Write('<dd>')
|
||||
Write(tostring(GetClientPort()))
|
||||
Write('\r\n')
|
||||
Write('<dt>GetServerIp()\r\n')
|
||||
Write('<dd>')
|
||||
Write(FormatIp(GetServerIp()))
|
||||
DescribeIp(GetServerIp())
|
||||
Write('\r\n')
|
||||
Write('<dt>GetServerPort()\r\n')
|
||||
Write('<dd>')
|
||||
Write(tostring(GetServerPort()))
|
||||
Write('\r\n')
|
||||
Write('</dl>\r\n')
|
||||
|
||||
-- redbean apis for generalized parsing and encoding
|
||||
referer = GetHeader('Referer')
|
||||
if referer then
|
||||
url = ParseUrl(referer)
|
||||
if url.scheme then
|
||||
url.scheme = string.upper(url.scheme)
|
||||
end
|
||||
Write('<h3>referer url</h3>\r\n')
|
||||
Write('<p>\r\n')
|
||||
Write(EscapeHtml(EncodeUrl(url)))
|
||||
Write('<dl>\r\n')
|
||||
if url.scheme then
|
||||
Write('<dt>scheme\r\n')
|
||||
Write('<dd>\r\n')
|
||||
Write(EscapeHtml(url.scheme))
|
||||
end
|
||||
if url.user then
|
||||
Write('<dt>user\r\n')
|
||||
Write('<dd>\r\n')
|
||||
Write(EscapeHtml(url.user))
|
||||
end
|
||||
if url.pass then
|
||||
Write('<dt>pass\r\n')
|
||||
Write('<dd>\r\n')
|
||||
Write(EscapeHtml(url.pass))
|
||||
end
|
||||
if url.host then
|
||||
Write('<dt>host\r\n')
|
||||
Write('<dd>\r\n')
|
||||
Write(EscapeHtml(url.host))
|
||||
end
|
||||
if url.port then
|
||||
Write('<dt>port\r\n')
|
||||
Write('<dd>\r\n')
|
||||
Write(EscapeHtml(url.port))
|
||||
end
|
||||
if url.path then
|
||||
Write('<dt>path\r\n')
|
||||
Write('<dd>\r\n')
|
||||
Write(EscapeHtml(url.path))
|
||||
end
|
||||
if url.params then
|
||||
Write('<dt>params\r\n')
|
||||
Write('<dd>\r\n')
|
||||
Write('<dl>\r\n')
|
||||
for i = 1,#url.params do
|
||||
Write('<dt>')
|
||||
Write(EscapeHtml(url.params[i][1]))
|
||||
Write('\r\n')
|
||||
if url.params[i][2] then
|
||||
Write('<dd>')
|
||||
Write(EscapeHtml(url.params[i][2]))
|
||||
Write('\r\n')
|
||||
end
|
||||
end
|
||||
Write('</dl>\r\n')
|
||||
end
|
||||
if url.fragment then
|
||||
Write('<dt>fragment\r\n')
|
||||
Write('<dd>\r\n')
|
||||
Write(EscapeHtml(url.fragment))
|
||||
end
|
||||
Write('</dl>\r\n')
|
||||
end
|
||||
|
||||
Write('<h3>posix extended regular expressions</h3>\r\n')
|
||||
s = 'my ' .. FormatIp(GetClientIp()) .. ' ip'
|
||||
r = CompileRegex('([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})', 'e')
|
||||
m,a,b,c,d = ExecuteRegex(r, s)
|
||||
Write('<pre>\r\n')
|
||||
Write(string.format([[m,a,b,c,d = ExecuteRegex(CompileRegex('([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})', 'e'), %q)]], s))
|
||||
Write('</pre>\r\n')
|
||||
ReleaseRegex(r)
|
||||
Write('<dl>\r\n')
|
||||
Write('<dt>m\r\n')
|
||||
Write('<dd>')
|
||||
Write(EscapeHtml(tostring(m)))
|
||||
Write('\r\n')
|
||||
Write('<dt>a\r\n')
|
||||
Write('<dd>')
|
||||
Write(EscapeHtml(tostring(a)))
|
||||
Write('\r\n')
|
||||
Write('<dt>b\r\n')
|
||||
Write('<dd>')
|
||||
Write(EscapeHtml(tostring(b)))
|
||||
Write('\r\n')
|
||||
Write('<dt>c\r\n')
|
||||
Write('<dd>')
|
||||
Write(EscapeHtml(tostring(c)))
|
||||
Write('\r\n')
|
||||
Write('<dt>d\r\n')
|
||||
Write('<dd>')
|
||||
Write(EscapeHtml(tostring(d)))
|
||||
Write('\r\n')
|
||||
Write('</dl>\r\n')
|
||||
|
||||
-- redbean zip assets
|
||||
Write('<h3>zip assets</h3>\r\n')
|
||||
paths = GetZipPaths()
|
||||
if #paths > 0 then
|
||||
Write('<ul>\r\n')
|
||||
for i = 1,#paths do
|
||||
Write('<li>\r\n')
|
||||
Write('<a href="')
|
||||
Write(EscapeHtml(EscapePath(paths[i])))
|
||||
Write('">')
|
||||
Write(EscapeHtml(paths[i]))
|
||||
Write('</a>')
|
||||
if IsHiddenPath(paths[i]) then
|
||||
Write(' <small>[HIDDEN]</small>')
|
||||
end
|
||||
if not IsAcceptablePath(paths[i]) then
|
||||
Write(' <small>[BLOCKED]</small>')
|
||||
end
|
||||
if not IsCompressed(paths[i]) then
|
||||
Write(' <small>[UNCOMPRESSED]</small>')
|
||||
end
|
||||
if (GetAssetMode(paths[i]) & 0xF000) == 0x4000 then
|
||||
Write(' <small>[DIRECTORY]</small>')
|
||||
end
|
||||
Write('<br>\r\n')
|
||||
Write('Modified: ')
|
||||
Write(FormatHttpDateTime(GetLastModifiedTime(paths[i])))
|
||||
Write('<br>\r\n')
|
||||
Write('Mode: ')
|
||||
Write(string.format("0%o", GetAssetMode(paths[i])))
|
||||
Write('<br>\r\n')
|
||||
Write('Size: ')
|
||||
Write(tostring(GetAssetSize(paths[i])))
|
||||
Write('<br>\r\n')
|
||||
if GetComment(paths[i]) then
|
||||
Write('Comment: ')
|
||||
Write(EscapeHtml(GetComment(paths[i])))
|
||||
Write('<br>\r\n')
|
||||
end
|
||||
Write('\r\n')
|
||||
end
|
||||
Write('</ul>\r\n')
|
||||
else
|
||||
Write('<p><em>none</em>\r\n')
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
main()
|
||||
|
|
26
tool/net/seekable.txt
Normal file
26
tool/net/seekable.txt
Normal file
|
@ -0,0 +1,26 @@
|
|||
A
|
||||
B
|
||||
C
|
||||
D
|
||||
E
|
||||
F
|
||||
G
|
||||
H
|
||||
I
|
||||
J
|
||||
K
|
||||
L
|
||||
M
|
||||
N
|
||||
O
|
||||
P
|
||||
Q
|
||||
R
|
||||
S
|
||||
T
|
||||
U
|
||||
V
|
||||
W
|
||||
X
|
||||
Y
|
||||
Z
|
Loading…
Add table
Add a link
Reference in a new issue