Actions
ModMagnetExamples » History » Revision 1
Revision 1/32
| Next »
gstrauss, 2021-08-20 18:08
- Table of contents
- lua examples of lighttpd modules
lua examples of lighttpd modules¶
mod_magnet with lua scripts can allow for customized alternatives to many lighttpd modules.
The following are simple examples to demonstrate, but are not full reimplementations.
(examples below use mod_magnet API since lighttpd 1.4.60)
lua mod_access¶
-- reject access to paths ending in ~ or .inc local path = lighty.r.req_attr["uri.path"] if (string.match(path, "~$") or string.match(path, "%.inc$")) then return 403 end
lua mod_alias¶
local req_attr = lighty.r.req_attr local path = req_attr["physical.path"] if (not path) then return 0 end local plen = path:len() local basedir = req_attr["physical.basedir"] local blen = basedir:len() if (string.match(basedir, "/$")) then blen = blen - 1 end if (0 == plen or plen < blen) then return 0 end local url_fspath = string.sub(path, blen+1, -1) -- remap /basedir/cgi-bin/ to alternative filesystem path if (string.match(url_fspath, "^/cgi-bin/")) then -- prefix match and replacement should both end in slash ('/') or both not local match_len = 9 -- length of "/cgi-bin/" req_attr["physical.basedir"] = "/var/www/servers/www.example.org/cgi-bin/" req_attr["physical.path"] = "/var/www/servers/www.example.org/cgi-bin/" .. string.sub(url_fspath, match_len+1, -1) end
lua mod_auth¶
-- There are many many many different ways to implement mod_auth. -- This is a simplistic example of HTTP Basic auth. -- Arbitrarily complex auth could be implemented in lua. local realm = "secure" local r = lighty.r function check_user_pass(user, pass) -- (trivially) hard-code valid username and password (and realm) -- (This should be replaced by something more appropriate for your system) -- (could be table or could be read from an external file or database or ...) -- (lighttpd mod_auth is much more advanced) if (realm == "secure" and user == "admin" and pass == "supersecretpass") then return true else return false end end function unauthorized() r.resp_header["WWW-Authenticate"] = 'Basic realm="' .. realm .. '", charset="UTF-8"' return 401 -- 401 Unauthorized end local authorization = r.req_header["Authorization"] if (not authorization) then return unauthorized() end local b64auth = string.match(authorization, "^Basic%s+([%w+/=]+)") if (not b64auth) then return unauthorized() end -- translate base64std dict to base64url dict (for lighty.c.b64dec()) b64auth = string.gsub(b64auth, "%+", "-") b64auth = string.gsub(b64auth, "/", "_") b64auth = string.gsub(b64auth, "=", ".") -- base64 decode into username:password string local auth = lighty.c.b64dec(b64auth) if (not auth) then return unauthorized() end local user, pass = string.match(auth, "^([^:]+):(.*)$") if (not user) then return unauthorized() end -- check authentication if (not check_user_pass(user, pass)) return unauthorized() end -- check authorization -- (could see if authenticated user is authorized to access requested URI) -- authenticated and (optionally) authorized r.req_env["REMOTE_USER"] = user r.req_env["AUTH_TYPE"] = "Basic"
lua mod_dirlisting¶
local r = lighty.r local path = r.req_attr["physical.path"] -- check that path ends in '/' if (not path or not string.match(path, "/$")) then return 0 end -- check that path exists and is a directory local st = lighty.c.stat(path) if (not st or not st.is_dir) then return 0 end -- list filenames in directory local name for name in lighty.c.readdir(path) do r.resp_body:add({name, "\n"}) end r.resp_header["Content-Type"] = "text/plain" return 200
lua mod_evhost¶
local server_root = "/var/www/servers/" local req_attr = lighty.r.req_attr local host = req_attr["uri.authority"] if (not host) then return 0 end local shard = string.match(host, "(%w)[^.]*%.[^.%]]+$") if (not shard) then return 0 end local docroot = server_root .. shard .. "/" .. host local st = lighty.c.stat(docroot) if (not st or not st.is_dir) then return 0 end req_attr["physical.doc_root"] = docroot req_attr["physical.basedir"] = docroot req_attr["physical.path"] = docroot .. req_attr["physical.rel-path"]
lua mod_expire¶
local path = lighty.r.req_attr["physical.path"] if (not path) then return 0 end local suffix = string.match(path, "(%.[^./]*)$") if (suffix == ".html") then lighty.r.resp_header["Cache-Control"] = "max-age=" .. (os.time()+300) return 0 end if (suffix == ".css" or suffix == ".js") then lighty.r.resp_header["Cache-Control"] = "max-age=" .. (os.time()+3600) return 0 end if (suffix == ".jpg") then lighty.r.resp_header["Cache-Control"] = "max-age=" .. (os.time()+86400) return 0 end
lua mod_extforward¶
local r = lighty.r local req_header = r.req_header local xffor = req_header["X-Forwarded-For"] if (xffor) then local req_attr = r.req_attr req_attr["request.remote-addr"] = xffor local xfport = req_header["X-Forwarded-Port"] if (xfport) then req_attr["request.remote-port"] = xfport end local xfproto = req_header["X-Forwarded-Proto"] if (xfproto) then req_attr["uri.scheme"] = xfproto end end
lua mod_flv_streaming¶
$HTTP["url"] =~ "\.flv$" { magnet.attract-physical-path-to = ("/path/to/flv-streaming.lua") }
-- lua implementation of lighttpd mod_flv_streaming -- -- Aside: it is baffling why FLV streaming is not simply an HTTP Range request -- -- Potential (trivial) enhancements (exercise left to the reader): -- - could call lighty.stat(lighty.env["physical.path"]) -- - check that file exists -- - check start/end offsets local r = lighty.r -- check that target file ends in ".flv" -- (comment out; already checked in lighttpd.conf condition in sample conf) --if (".flv" ~= string.sub(r.req_attr["physical.path"], -4)) then -- return 0 --end -- split the query-string and look for start and end offsets (0-based) local qs = lighty.c.urldec_query(r.req_attr["query-string"]) if (qs["start"] == nil) then return 0 end local start = tonumber(qs["start"]) local len = qs["end"] ~= nil and (tonumber(qs["end"]) + 1 - start) or -1 if (start <= 0) then -- let other modules handle request (e.g. mod_staticfile) return 0 end -- send FLV response r.resp_header["Content-Type"] = "video/x-flv" r.resp_body:set({ "FLV\1\1\0\0\0\9\0\0\0\9", -- FLV header { filename = r.req_attr["physical.path"], offset = start, length = len } }) return 200
lua mod_indexfile¶
local req_attr = lighty.r.req_attr local path = req_attr["physical.path"] -- check that path ends in '/' if (not path or not string.match(path, "/$")) then return 0 end -- check for index.php then index.html local indexfiles = { "index.php", "index.html" } for _, file in ipairs(indexfiles) do if (lighty.c.stat(path .. file) then req_attr["physical.path"] = path .. file req_attr["uri.path"] = req_attr["uri.path"] .. file return 0 -- let mod_staticfile or other module handle the file end done
lua mod_redirect¶
-- redirect http to https if (lighty.r.req_attr["uri.scheme"] == "http") then local r = lighty.r r.resp_header["Location"] = "https://" .. r.req_attr["uri.authority"] .. r.req_attr["request.uri"] return 302 end
lua mod_rewrite¶
-- redirect if file does not exist (not file, not directory, not anything else) -- (This script must be called from magnet.attract-physical-path-to hook) if (not lighty.c.stat(lighty.r.req_attr["physical.path"])) then local req_attr = lighty.r.req_attr local query = req_attr["uri.query"] req_attr["request.uri"] = "/index.php?path=" .. req_attr["uri.path-raw"] .. (query and ("&" .. query) or "") return lighty.REQUEST_RESTART end
lua mod_secdownload¶
-- extract tokens from url-path local req_attr = lighty.r.req_attr local mac, protected_path, tsstr, rel_path = string.match(req_attr["uri.path"], "^/download/([%w_-]+)(/(%x+)(/.*))$") if (not mac) then return 0 end local ts = tonumber(tsstr, 16) if (not ts) then return 0 end -- validate timestamp local timeout = 600 -- (10 mins) validity window local t = os.time() if (((t > ts) and (t - ts) or (ts - t)) > timeout) then return 410 -- 410 Gone; URI will never be valid again end -- validate MAC local secret = "12345-bad-secret" -- you MUST customize this local li = lighty.c local hash = li.b64enc(li.hmac("sha256", secret, protected_path)) if (not li.digest_eq(hash, mac)) then return 403 -- 403 Forbidden end -- remap to alternative filesystem path local doc_root = "/var/www/servers/www.example.org/download" req_attr["physical.doc_root"] = docroot req_attr["physical.basedir"] = docroot req_attr["physical.path"] = docroot .. rel_path req_attr["physical.rel-path"] = rel_path -- let mod_staticfile or other module handle the file
lua mod_setenv¶
-- examples local r = lighty.r r.req_header["DNT"] = "1" r.req_env["TMOUT"] = "3" r.resp_header["Cache-Control"] = "max-age=0"
lua mod_simple_vhost¶
local server_root = "/var/www/servers/" local docroot = nil local req_attr = lighty.r.req_attr local host = string.match(req_attr["uri.authority"], "^(%w[^:/]*)") if (host) then docroot = server_root .. host local st = lighty.c.stat(docroot) if (not st or not st.is_dir) then docroot = nil end end if (not docroot) then -- set default docroot docroot = server_root .. "default.example.com" end req_attr["physical.doc_root"] = docroot req_attr["physical.basedir"] = docroot req_attr["physical.path"] = docroot .. req_attr["physical.rel-path"]
lua mod_usertrack¶
local cookies = lighty.c.cookie_tokens(lighty.r.req_header['Cookie']) if (cookies["TRACKID"]) then return 0 end -- cookie already exists -- create cookie local li = lighty.c local md = li.md("sha256", lighty.r.req_attr["uri.path"] .. "+" .. tostring(os.time()) .. tostring(li.rand())) local usertrack_cookie = "TRACKID=" .. md .. "; Path=/; Version=1; Domain=example.com; max-age=86400" local resp_header = lighty.r.resp_header local set_cookie = resp_header["Set-Cookie"] if (set_cookie) set_cookie = set_cookie .. "\r\nSet-Cookie: " resp_header["Set-Cookie"] = set_cookie .. usertrack_cookie
Updated by gstrauss over 3 years ago · 1 revisions