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:
Justine Tunney
2021-04-20 19:14:21 -07:00
parent 26ac6871da
commit 4effa23528
74 changed files with 3710 additions and 14246 deletions

View File

@ -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()