使用 Lua 进行 lighttpd 请求操作¶
模块:mod_magnet
概述¶
mod_magnet 通过 Lua(编程语言)脚本实现对 lighttpd 请求处理的程序化操作。
mod_magnet Lua 示例展示了少量 Lua 代码与 lighttpd 结合的强大功能和灵活性。mod_magnet 允许您执行比在 lighttpd.conf 中更复杂的 URL 重写和缓存,包括 lighttpd 中的 .htaccess 类功能。
虽然 Lua 是一种非常强大的编程语言,但对于任何具有其他脚本语言(Python、PHP、Ruby 等)基本脚本经验的人来说,学习基本的字符串操作并将 Lua 脚本插入 lighttpd 应该相对简单。请查看此处的 Lua 示例并尝试一下!有问题?请在 lighttpd 论坛发帖。
请注意:mod_magnet 旨在进行请求操作,例如 URL 重写,并非旨在完全替代您的整个脚本环境。mod_magnet 在 lighttpd 核心中执行 Lua 脚本,这使得 Lua 脚本在 lighttpd 中运行非常快,但任何阻塞操作(例如对外部数据库的 I/O)都会暂停 lighttpd 服务器的所有其他请求。对于耗时或阻塞的 Lua 脚本,请使用 mod_fastcgi、mod_proxy 或其他动态后端,在 lighttpd 外部运行您的脚本。对于有兴趣运行耗时或阻塞的 Lua 脚本的人,一个选项是第三方 FastCGI 守护程序,例如 luafcgid。
要求¶
lighttpd 1.4.12 或更高版本,使用 --with-lua
构建
Lua >= 5.1
lighttpd.conf server.modules += ("mod_magnet")
# 注意:如果希望 mod_magnet 在其他模块生成响应之前操作请求,则 mod_magnet 必须在 server.modules 中列在其他可能处理请求的模块(例如 mod_fastcgi、mod_webdav 等)之前。
选项¶
mod_magnet 可以在请求处理的一个或多个阶段“吸引”请求。您可以为每个阶段定义多个脚本,用逗号分隔。脚本按指定顺序执行。如果脚本返回除 0 或 1xx 之外的值,则后续脚本将不会执行。请参阅下面的 返回码。出于性能原因,mod_magnet 会缓存每个编译好的脚本。对于每个请求,都会检查脚本,如果脚本已修改,则重新加载并重新编译。脚本更改会在下一个请求时生效,无需重新启动 lighttpd。
magnet.attract-raw-url-to = (...)
- 收到 HTTP 请求头之后(以及 mod_rewrite 之后)的 URL 处理magnet.attract-physical-path-to = (...)
- 文档根目录和物理路径设置为初始值之后的文件系统处理magnet.attract-response-start-to = (...)
- HTTP 状态设置之后且响应头最终确定之前(自 1.4.56 起)的响应开始
例如 magnet.attract-physical-path-to = ( "/absolute/path/to/script.lua" )
返回码¶
- 如果脚本
return 0
,或不返回任何内容(或 nil),则请求处理继续。 - 如果脚本
return lighty.RESTART_REQUEST
(当前等于 99),则请求将重新启动,重新处理请求 URI。这通常与在重写中更改["request.uri"]
属性结合使用。 - 如果脚本返回 1xx,则发送 1xx 中间响应,请求处理继续。
- 如果脚本返回 >= 200,则该值用作最终 HTTP 状态码,并最终确定响应。不再执行其他模块。
将“http”重定向到“https”的示例:(lighty.*
访问器将在下面进一步描述)
(例如 如何使用 mod_redirect 将 HTTP 请求重定向到 HTTPS)
local r = lighty.r local req_attr = r.req_attr if (req_attr["uri.scheme"] == "http") then r.resp_header["Location"] = "https://" .. req_attr["uri.authority"] .. req_attr["request.uri"] return 308 end
检测请求阶段¶
如果同一个 Lua 脚本被配置为在多个请求阶段运行,Lua 脚本可以使用 lighty.*
检测请求阶段(lighty.*
访问器将在下面进一步描述)
magnet.attract-raw-url-to
lighty.r.req_attr["physical.path"] == nil
- (自 lighttpd 1.4.65 起)
lighty.r.req_item.http_status == 0
- (lighttpd 1.4.65 之前)
lighty.r.req_attr["response.http-status"] == "0"
magnet.attract-physical-path-to
lighty.r.req_attr["physical.path"] ~= nil
- (自 lighttpd 1.4.65 起)
lighty.r.req_item.http_status == 0
- (lighttpd 1.4.65 之前)
lighty.r.req_attr["response.http-status"] == "0"
magnet.attract-response-start-to
(自 1.4.56 起)- (自 lighttpd 1.4.65 起)
lighty.r.req_item.http_status > 0
- (lighttpd 1.4.65 之前)
lighty.r.req_attr["response.http-status"] > 0
示例¶
库函数¶
mod_magnet 向脚本导出了一些附加函数pairs()
- 扩展默认的pairs()
函数(适用于 Lua 5.1)print()
- 写入 lighttpd 错误日志;用于调试很有用- 例如
print("Host: " .. lighty.r.req_header["Host"])
- 例如
print("Request-URI: " .. lighty.r.req_attr["request.uri"])
- 例如
lighty.stat()
-stat()
文件信息(推荐:lighty.c.stat()
)
mod_magnet API (lighttpd 1.4.60 及更高版本)¶
(已弃用的 lighttpd 1.4.60 之前的 mod_magnet API 仍然受支持,但应优先使用此较新的 mod_magnet API。)
lighty.r
请求对象¶
(自 lighttpd 1.4.60 起)
lighty.r |
描述 |
---|---|
lighty.r.req_header[] |
HTTP 请求头 |
lighty.r.req_attr[] |
HTTP 请求属性/组件 |
lighty.r.req_item[] |
HTTP 请求选择内部成员(自 1.4.65 起) |
lighty.r.req_env[] |
HTTP 请求环境变量 |
lighty.r.req_body.* |
HTTP 请求体属性和访问器(自 1.4.65 起) |
lighty.r.resp_header[] |
HTTP 响应头 |
lighty.r.resp_body.* |
HTTP 响应体属性和访问器 |
lighty.r
请求对象修改¶
lighty.r.req_header[]
允许获取/设置请求头
如果修改会影响配置处理,脚本应返回
lighty.RESTART_REQUEST
以使 lighttpd 重新启动修改后的请求。
lighty.r.req_header[]
与旧版 APIlighty.env[]
表不同,
后者(以前)不允许修改请求头。
注意:头策略不适用于在lighty.r.req_header[]
中设置的值;
不要设置未经验证、不信任或未标准化的值。
注意:如果使用pairs()
迭代,请不要在迭代期间将请求头设置为空白值,
否则迭代可能会跳过请求头。
lighty.r.req_attr[]
允许获取/设置请求属性,并将在下面详细介绍。
lighty.r.req_attr[]
与(命名不太清晰的)旧版 APIlighty.env[]
相同
lighty.r.req_item[]
允许(主要是)对选定的内部请求成员进行只读访问
并将在下面详细介绍。(自 1.4.65 起)
lighty.r.req_env[]
允许获取/设置请求环境变量
lighty.r.req_env[]
与旧版 APIlighty.req_env[]
相同
注意:对标准 CGI 环境变量的修改
将被重新创建 CGI 环境的后端覆盖。
但是,新变量将保留到传递给后端脚本的环境中。
lighty.r.req_body.*
添加/设置请求体内容(自 1.4.65 起)lighty.r.req_body
描述 lighty.r.req_body.len
HTTP 请求体长度
(如果没有则为 0;如果未知则为 -1;如果客户端发送 Content-Length 或请求体完成则 >= 0)lighty.r.req_body.collect
HTTP 请求体安排收集(之后请求将重新启动并重新运行脚本)
(注意:请求体卸载会禁用向后端流式传输请求;延迟连接到后端)
- 如果请求体完成,则返回 1(然后脚本可以调用r.req_body.get
)
- 如果请求体不完整,则返回 0(然后脚本应返回 0,以便脚本稍后可以重新运行)lighty.r.req_body.get
获取 HTTP 请求体(注意:将整个请求读入内存;检查 r.req_body.len
以确保合理性)
(如果请求体不完整则为 nil(请参阅r.req_body.collect
))lighty.r.req_body.add()
添加 HTTP 请求体(字符串或字符串表)
(如果使用,也应r.req_header["Content-Length"] = nil
(或设置为实际值))lighty.r.req_body.set()
设置 HTTP 请求体(字符串或字符串表)
(如果使用,也应r.req_header["Content-Length"] = nil
(或设置为实际值))lighty.r.req_body.bytes_in
从客户端接收的 HTTP 请求体字节数(由 r.req_body.set()
重置)lighty.r.req_body.bytes_out
发送到后端的 HTTP 请求体字节数(由 r.req_body.set()
重置)lighty.r.req_body.unspecified_len
HTTP/1.0 请求体字节数未指定(不是 0 长度)(仅可为 HTTP/1.0 请求设置)(自 1.4.74 起)
lighty.r.resp_header[]
允许获取/设置响应头
(某些连接级头,如 Connection 和
Transfer-Encoding 被限制修改)
lighty.r.resp_headers[]
与旧版 APIlighty.header[]
表不同,
后者被收集和延迟,在脚本退出后才应用。
注意:头策略不适用于在lighty.r.resp_header[]
中设置的值;
不要设置未经验证、不信任或未标准化的值。
对于重复的头名称,例如 Set-Cookie 或 Link,使用 "\r\nNAME:" 连接
lighty.r.resp_header["Link"] = "http://a.com/a.css\r\nLink: http:/b.com/b.js"
lighty.r.resp_body.*
添加/设置响应体内容
lighty.r.resp_body.*
与旧版 APIlighty.content[]
表不同,
后者被收集和延迟,在脚本退出后才应用。lighty.r.resp_body
描述 lighty.r.resp_body.len
HTTP 响应体长度 lighty.r.resp_body.get
获取 HTTP 响应体(注意:将整个响应读入内存;检查 r.resp_body.len
以确保合理性)(自 1.4.65 起)lighty.r.resp_body.add()
添加 HTTP 响应体(字符串或表) lighty.r.resp_body.set()
设置 HTTP 响应体(字符串或表) lighty.r.resp_body.bytes_in
排队发送的 HTTP 响应体字节数(自 1.4.65 起) lighty.r.resp_body.bytes_out
发送到客户端的 HTTP 响应体字节数(自 1.4.65 起)
-- examples local r = lighty.r local resp_header = r.resp_header resp_header["Content-Type"] = "text/html" resp_header["Cache-Control"] = "max-age=0" r.resp_body:set({'bar\n'}) -- equivalent to below 'set' -- (suggested if script run via magnet.attract-response-start-to) resp_header["Content-Length"] = nil -- alternatives r.resp_body.set({'bar\n'}) -- equivalent to above 'set' lighty.r.resp_header["Content-Type"] = "text/html" -- deprecated older syntax (API before lighttpd 1.4.60) (less clearly named) lighty.header["Content-Type"] = "text/html" lighty.content = {'bar\n'}
lighty.r.req_attr[]
可读属性¶
lighty.r.req_attr[] |
描述 |
---|---|
["uri.scheme"] |
("http", "https") |
["uri.authority"] |
URI 权限或 Host 请求头 |
["uri.path"] |
不带查询字符串的 url-path;url-path 已进行 URL 解码 |
["uri.path-raw"] |
不带查询字符串的 url-path;url-path 未进行 URL 解码 (来自 ["request.uri"] 的 url-path 组件,即不带查询字符串) |
["uri.query"] |
查询字符串;'?' 后面的 URL 部分;查询字符串未进行 URL 解码 |
["request.method"] |
请求方法(例如 GET) |
["request.protocol"] |
请求协议("HTTP/1.0", "HTTP/1.1", "HTTP/2.0") |
["request.uri"] |
mod_rewrite 规则(如果有)后的 URI,否则与 request.orig-uri 相同 |
["request.orig-uri"] |
mod_rewrite 之前的 URI;客户端发送的原始请求 URI |
["request.path-info"] |
url-path 后面的 path-info |
["request.server-addr"] |
服务器地址 |
["request.server-port"] |
服务器端口 |
["request.remote-addr"] |
远程地址 |
["request.remote-port"] |
远程端口 |
["request.server-name"] |
通常与 ["uri.authority"] 相同,除非在 lighttpd.conf 中配置了 server.name |
["request.stage"] |
内部请求阶段的字符串标签(例如用于显示;类似于 mod_status) |
["physical.doc-root"] |
文件系统文档根目录(原始) |
["physical.basedir"] |
文件系统文档根目录(与 physical.doc-root 相同,除非 mod_alias、mod_userdir 等调整) |
["physical.path"] |
请求的文件系统路径(以 physical.basedir 开头) |
["physical.rel-path"] |
请求的文件系统路径(附加到 physical.basedir 的部分) |
["response.http-status"] |
HTTP 响应状态(如果尚未设置则为 0) (已弃用;自 lighttpd 1.4.65 起替换为 lighty.r.req_item.http_status )(在 lighttpd 1.4.68 中已移除) |
["response.body-length"] |
HTTP 响应体长度 (已弃用;自 lighttpd 1.4.60 起替换为 lighty.r.resp_body.len )(在 lighttpd 1.4.68 中已移除) (除非响应体完成,否则为 nil) |
["response.body"] |
HTTP 响应体 (已弃用;自 lighttpd 1.4.65 起替换为 lighty.r.resp_body.get )(在 lighttpd 1.4.68 中已移除) (除非响应体完成,否则为 nil) (将响应复制到内存中;不应在非常大的响应上使用) |
可以使用组件重新构建完整的 URI
local req_attr = lighty.r.req_attr local query_string = req_attr["uri.query"] local url = req_attr["uri.scheme"] .. "://" .. req_attr["uri.authority"] .. req_attr["uri.path-raw"] .. (query_string and ("?" .. query_string) or "")
更多示例
-- curl "https://example.org/search.php?q=lighty" -- results in a request like: -- GET /search.php?q=lighty HTTP/1.1 -- Host: example.org local r = lighty.r local req_attr = r.req_attr local req_header = r.req_header -- scripts run via magnet.attract-raw-url-to can access the following variables: -- parts of the request-line req_attr["request.uri"] == "/search.php?q=lighty" -- HTTP request-headers req_header["Host"] == "example.org" -- parts of the URI req_attr["uri.path"] == "/search.php" req_attr["uri.path-raw"] == "/search.php" req_attr["uri.scheme"] == "https" req_attr["uri.authority"] == "example.org" req_attr["uri.query"] == "q=lighty" -- Later in the request-handling, the URL is split, cleaned up, and turned into a physical path name -- scripts run via magnet.attract-physical-path-to can access the following variables: -- filenames, pathnames req_attr["physical.path"] == "/my-docroot/search.php" req_attr["physical.rel-path"] == "/search.php" req_attr["physical.doc-root"] == "/my-docroot" req_attr["physical.basedir"] == "/my-docroot" -- same as doc-root unless changed, e.g. by mod_alias -- All of them are readable, but not all of them are writable (or have no effect if you write to them). Some examples writing changes: -- change physical-path req_attr["physical.path"] = ... -- change query-string req_attr["uri.query"] = ... -- simple rewrite req_attr["request.uri"] = ... return lighty.RESTART_REQUEST一些
lighty.r.req_attr[]
属性提供与标准 CGI/1.1 环境中相似的值lighty.r.req_attr[] |
CGI/1.1 环境变量 |
---|---|
["uri.scheme"] |
REQUEST_SCHEME |
["uri.authority"] |
SERVER_NAME |
["uri.path"] |
SCRIPT_NAME |
["uri.query"] |
QUERY_STRING |
["request.method"] |
REQUEST_METHOD |
["request.protocol"] |
SERVER_PROTOCOL |
["request.path-info"] |
PATH_INFO |
["request.remote-addr"] |
REMOTE_ADDR |
["request.remote-port"] |
REMOTE_PORT |
["request.server-addr"] |
SERVER_ADDR |
["request.server-port"] |
SERVER_PORT |
["request.server-name"] |
SERVER_NAME |
["physical.doc-root"] |
DOCUMENT_ROOT |
["physical.basedir"] |
DOCUMENT_ROOT |
["physical.path"] |
SCRIPT_FILENAME |
["physical.rel-path"] |
SCRIPT_NAME |
lighty.r.req_attr[]
可写属性¶
对特定属性或组件的修改是相当直接的接口
到 lighttpd 内部,并且不影响其他相关属性,包括
完整请求,从中可能派生出属性或组件。
这意味着什么?
这意味着:仔细测试您的脚本并验证所需行为。
如果任何修改后需要完整的请求重新处理,
例如,如果修改会影响配置处理,脚本应
返回 lighty.RESTART_REQUEST
lighty.r.req_attr[] | 描述 |
---|---|
["uri.scheme"] |
修改具有与 mod_extforward 中更改方案类似的效果 如果需要重新处理请求,则 return lighty.RESTART_REQUEST |
["uri.authority"] |
修改通常应重复到 lighty.r.req_header["Host"] 如果需要重新处理请求,则 return lighty.RESTART_REQUEST |
["uri.path"] |
不鼓励修改; 源自 ["request.uri"] ,URL 解码并简化路径;优先修改 ["request.uri"] 并 return lighty.RESTART_REQUEST |
["uri.query"] |
修改影响其他模块后续对查询字符串的使用 如果需要重新处理请求,优先修改 ["request.uri"] 并 return lighty.RESTART_REQUEST |
["request.uri"] |
修改具有与使用 mod_rewrite 类似的效果,之后应紧跟 return lighty.RESTART_REQUEST 以便 lighttpd 重新处理请求并将其 URI 重新解析为组件。 "request.uri" 可以使用组件重新构建:["request.uri"] = ["uri.path-raw"] "?" ["uri.query"] |
["request.orig-uri"] |
不鼓励修改 |
["request.path-info"] |
修改影响其他模块后续对 path-info 的使用 如果需要重新处理请求,优先修改 ["request.uri"] 并 return lighty.RESTART_REQUEST |
["request.protocol"] |
修改更改请求协议,并且只能将 "HTTP/1.1" 降级为 = "HTTP/1.0" (例如,对于发送 HTTP/1.1 请求但无法处理 Transfer-Encoding: chunked 响应的客户端) |
["request.remote-addr"] |
修改更改连接上所有后续请求的 remote_addr (!!!) 修改具有与使用 mod_extforward 类似的效果 (尽管 mod_extforward 还会额外更新转发头) 如果需要重新处理请求,则 return lighty.RESTART_REQUEST (优先使用 lighttpd 1.4.70+ 中按请求管理远程地址的 mod_extforward) |
["request.remote-port"] |
修改更改连接上所有后续请求的 remote_addr 端口 |
["physical.doc-root"] |
修改影响其他模块后续对 doc_root 的使用 (例如 mod_ssi mod_webdav(有限用作回退)) |
["physical.basedir"] |
修改影响其他模块后续对 basedir 的使用 (例如作为传递给后端脚本的 DOCUMENT_ROOT,除非在其他地方修改) |
["physical.path"] |
修改影响其他模块后续对 path 的使用 (例如 mod_staticfile 和许多其他基于文件系统的模块) 修改具有与使用 mod_alias 类似的效果 (当脚本从 magnet.attract-physical-path-to 钩子调用时) |
["physical.rel-path"] |
修改影响其他模块后续对相对路径的使用 (例如 mod_ssi mod_userdir mod_webdav) |
["physical.*"]
属性对于从 magnet.attract-physical-path-to
钩子调用的脚本是有效的。这些属性在更早的 magnet 钩子中未定义,在更晚的 magnet 钩子中几乎没有效果。
lighty.r.req_item[]
可读属性(自 1.4.65 起)¶
- req_item 提供对选定的 lighttpd 内部请求成员的原始只读访问
- req_item 值通常是整数;req_attr 值通常是字符串
- req_item 不可迭代;req_attr 可以使用 pairs() 迭代
- 取决于 Lua 脚本运行的 magnet 钩子,
req_item 值可能未设置或可能不是最终值。
lighty.r.req_item[] | (备选) | 描述 |
---|---|---|
["http_status"] |
req_item.http_status |
请求 HTTP 状态(如果尚未设置则为 0) |
["req_header_len"] |
req_item.req_header_len |
请求头长度 |
["resp_header_len"] |
req_item.resp_header_len |
响应头长度(如果尚未设置则为 0) |
["bytes_in"] |
req_item.bytes_in |
请求读取的字节数 |
["bytes_out"] |
req_item.bytes_out |
请求发送的字节数 |
["stream_id"] |
req_item.stream_id |
HTTP/2 流 ID |
["start_time"]() |
req_item.start_time() |
请求开始时间(秒,纳秒) (注意:函数需要括号 () ) |
["req_count"] |
req_item.req_count |
连接上启动的请求数 (注意:HTTP/2 流可以并行启动) |
["keep_alive"] |
req_item.keep_alive |
请求 keep-alive 状态 (1 keep-alive;0 关闭(或 HTTP/2);-1 关闭,goaway) |
lighty.r.req_item[]
可写属性(自 1.4.65 起)¶
lighty.r.req_item[] | (备选) | 描述 |
---|---|---|
["keep_alive"] |
req_item.keep_alive |
请求 keep-alive 状态(可设置为 0 或 -1) (1 keep-alive;0 关闭(或 HTTP/2);-1 关闭,goaway) |
.
lighty.server
对象¶
(自 lighttpd 1.4.65 起)
lighty.r |
描述 |
---|---|
lighty.server.irequests() |
遍历客户端请求 |
lighty.server.plugin_stats[] |
后端模块的统计信息(等同于旧版 API lighty.status ) |
lighty.server.stats[] |
服务器统计信息 |
lighty.server.irequests()
(自 1.4.65 起)¶
- 遍历客户端请求
- 注意:迭代器对象在每次迭代时都会重用
(在迭代之前复制所需的叶节点信息;只保存字符串或数字)
(迭代器对象在迭代循环外部无效;不要保存迭代器对象) - 示例:Lua mod_status、Lua mod_evasive、Lua mod_uploadprogress
lighty.server.plugin_stats[]
(自 1.4.65 起)¶
- 后端模块的统计信息
(等同于lighty.status
)
(类似于 mod_statusstatus.statistics-url
的输出) - 示例:mod_magnet 可以将统计信息添加到 mod_status 全局统计页面。
- lighttpd.conf
server.modules += ("mod_magnet", "mod_status")
status.statistics-url = "/server-counters"
magnet.attract-raw-url-to = (server.docroot + "/counter.lua")
- counter.lua
local plugin_stats = lighty.server.plugin_stats
plugin_stats["magnet.connections"] = plugin_stats["magnet.connections"] + 1
- 访问
/server-counters
的结果
magnet.connections: 7
fastcgi.backend.php-foo.0...
fastcgi.backend.php-foo.1...
fastcgi.backend.php-foo.load: 0
- lighttpd.conf
lighty.server.stats[]
(自 1.4.65 起)¶
lighty.server.stats[] | 描述 |
---|---|
clients_open |
打开的客户端连接数 |
uptime |
运行时间(秒) |
version |
版本字符串 |
.
lighty.c.*
库函数¶
(自 lighttpd 1.4.60 起)
-- digests and passwords lighty.c.time() -- seconds since 1 Jan 1970 00:00:00 (cached; faster than os.time()) lighty.c.hrtime() -- (seconds, nanoseconds) since 1 Jan 1970 00:00:00 (high resolution) (since 1.4.65) lighty.c.rand() -- generate pseudo-random number lighty.c.md() -- calculate message digest (md5,sha1,sha256,sha512) lighty.c.hmac() -- calculate HMAC (md5,sha1,sha256,sha512) lighty.c.digest_eq() -- timing-safe comparison of two hex digests lighty.c.secret_eq() -- timing-safe comparison of two strings -- decode/encode lighty.c.b64urldec() -- base64url decode (validate and decode) lighty.c.b64urlenc() -- base64url encode, no padding lighty.c.b64dec() -- base64 decode (validate and decode) lighty.c.b64enc() -- base64 encode, no padding lighty.c.hexdec() -- hex decode (validate and decode) lighty.c.hexenc() -- hex encode uc; lc w/ lua s = s:lower() lighty.c.xmlenc() -- xml-encode/html-encode: <>&'\"` lighty.c.urldec() -- url-decode lighty.c.urlenc() -- url-encode lighty.c.urldec_query() -- url-decode query-string into table (since 1.4.65) lighty.c.urlenc_query() -- url-encode query-string from table (since 1.4.65) lighty.c.urlenc_normalize() -- url-encode normalization lighty.c.fspath_simplify() -- simplify fspath (remove "/." "/.." "/../" "//") lighty.c.quoteddec() -- decode MIME quoted-string (since 1.4.65) lighty.c.quotedenc() -- encode input as MIME quoted-string (since 1.4.65) lighty.c.bsdec() -- decode backspace-escaped string (since 1.4.65) lighty.c.bsenc() -- encode CTLs and non-ASCII input as hex (\xFF) backspace-escaped string (since 1.4.65) lighty.c.bsenc_json() -- encode CTLs and non-ASCII input as json (\uFFFF) backspace-escaped string (since 1.4.66) -- misc lighty.c.cookie_tokens() -- parse HTTP Cookie header into table (since 1.4.65) lighty.c.header_tokens() -- parse HTTP header into sequence table (since 1.4.65) lighty.c.readdir() -- dir walk lighty.c.readlink() -- contents of symbolic link (since 1.4.72) lighty.c.stat() -- stat() path
消息摘要 (md) 和基于哈希的消息认证码 (HMAC)
(MD5, SHA1, SHA256, SHA512)¶
lighty.c.md("algo", "data")
lighty.c.hmac("algo", "secret", "data")
- "algo" 可以是以下之一:"md5", "sha1", "sha256", "sha512"
(只要 lighttpd 编译时包含支持这些算法的加密库) - 返回摘要的大写十六进制字符串
lighty.c.digest_eq("digest1", "digest2")
- 对两个十六进制摘要执行时间安全、不区分大小写的比较
(时间安全比较比digest1 == digest2
稍安全) - "digest1" 和 "digest2" 是十六进制字符串(二进制摘要)
- 返回布尔值 true 或 false
lighty.c.secret_eq("data1", "data2")
- 对两个字符串执行时间安全比较
(并尝试隐藏字符串长度的差异)
(时间安全比较比data1 == data2
稍安全) - "data1" 和 "data2" 是字符串
- 返回布尔值 true 或 false
解码/编码¶
lighty.c.b64urldec("base64url-string")
lighty.c.b64urlenc("string")
- base64url 解码/编码(无填充)
- RFC4648 base64url(URL 和文件名安全标准),不是 base64(标准)
https://en.wikipedia.org/wiki/Base64
lighty.c.b64dec("base64-string")
lighty.c.b64enc("string")
- base64 解码/编码(无填充)
- RFC4648 base64
https://en.wikipedia.org/wiki/Base64
lighty.c.urldec_query("query-string")
(自 1.4.65 起)lighty.c.urlenc_query("query-string")
(自 1.4.65 起)- 将查询字符串 URL 解码为表,或将表 URL 编码为查询字符串
- 如果“key”后面没有“=”,则解码后的键的表值为 “”
- 如果“key=”后面有空白值,则解码后的键的表值为 “”
- 如果值为 “” ,则编码结果为 "key="
lighty.c.quoteddec("quoted-string")
(自 1.4.65 起)quoteddec:解码输入带引号的字符串
- (移除周围的双引号,反转义带引号的对 (
string.gsub(str, '\\(["\\])?', '%1')
))
(简单的便捷函数;有关更彻底的反斜杠转义解码,请参阅lighty.c.bsdec
)
quotedenc:将输入编码为带引号的字符串 - (反斜杠转义
"
和\
为带引号的对 (string.gsub(str, '(["\\])', '\\%1')
),然后用双引号括起来)
(简单的便捷函数;有关更彻底的反斜杠转义编码,请参阅lighty.c.bsenc
)lighty.c.bsdec("escaped-string")
(自 1.4.65 起)
- (解码
\"
,\\
,\n
(以及其他知名 CTL \-转义),八进制\000
, 十六进制\xFF
, json\uFFFF
)(json 自 1.4.66 起)
(如果存在,移除输入周围的双引号)lighty.c.bsenc("string")
(自 1.4.65 起)
\xFF
) 反斜杠转义字符串(或知名 CTL \-转义,例如 \n
)- 输入中的双引号 (
"
) 和反斜杠 (\
) 也会被反斜杠转义 - 结果不包含周围的双引号;调用者应酌情添加
lighty.c.bsenc_json("string")
(自 1.4.66 起)
\uFFFF
) 反斜杠转义字符串(或知名 CTL \-转义,例如 \n
)- 杂项¶
- 结果不包含周围的双引号;调用者应酌情添加
lighty.c.bsenc_json("string")
(自 1.4.66 起)
lighty.c.cookie_tokens("cookie-string")
(自 1.4.65 起)
将 HTTP Cookie 头解析为表(注意:带引号的字符串原样保留;不解码)- local cookies = lighty.c.cookie_tokens(lighty.r.req_header['Cookie'])
local identity = lighty.c.urldec(cookies["ident"])
lighty.c.header_tokens("header-string")
(自 1.4.65 起)
- 序列表包含单词/标记和分隔符(
,
;
=
)作为单独的元素 - (可选空白 (OWS) 和错误空白 (BWS) 已移除)
local tokens = lighty.c.header_tokens(lighty.r.req_header['Accept-Encoding']) for i = 1, #tokens do tok = lighty.c.quoteddec(tokens[i]) ......... end
在
Accept-Encoding
的情况下,每个编码可能可选地包含;q=0.x
质量,
这将在tokens
表中显示为多个元素(;
q
=
0.x
)
lighty.c.readdir("/path/to/dir")
目录遍历
- 为方便起见跳过 "." 或 ".."
- for name in lighty.c.readdir("/tmp") do r.resp_body:add({name, "\n"}) end
lighty.c.readlink("/path/to/softlink")
(自 1.4.72 起)
readlink
调用中的软链接内容,未缓存- lighty.c.stat("/path")
检查文件/目录/套接字是否存在并返回其 stat()
信息
- 使用 lighttpd 内部 stat-cache
- path: (字符串) 绝对路径
- 返回:包含以下字段的表,或错误时返回 nil
- is_file
- is_dir
- is_char
- is_block
- is_socket
- is_link
- is_fifo
- st_mode
- st_mtime
- st_ctime
- st_atime
- st_uid
- st_gid
- st_size
- st_ino
- etag
- content-type
- http-response-send-file(类似于 mod_staticfile)(自 1.4.64 起)
- st_mtim()(返回秒数,纳秒)(自 1.4.65 起)
- st_ctim()(返回秒数,纳秒)(自 1.4.65 起)
- st_atim()(返回秒数,纳秒)(自 1.4.65 起)
- lighttpd.conf 配置条件等价物¶
lighttpd.conf 配置条件 mod_magnet lua 等价物
lighttpd.conf 配置条件
mod_magnet lua 等价物 | $HTTP["request-method"] |
---|---|
lighty.r.req_attr["request.method"] |
$HTTP["scheme"] |
lighty.r.req_attr["uri.scheme"] |
$HTTP["host"] |
lighty.r.req_attr["uri.authority"] |
$HTTP["url"] |
lighty.r.req_attr["uri.path"] |
lighty.r.req_attr["uri.path-raw"] $HTTP["querystring"] |
lighty.r.req_attr["uri.query"] |
$HTTP["remoteip"] |
lighty.r.req_attr["request.remote-addr"] |
lighty.r.req_attr["request.remote-port"] $SERVER["socket"] |
lighty.r.req_attr["request.server-addr"] |
lighty.r.req_attr["request.server-port"] $REQUEST_HEADER["..."] |
lighty.r.req_header["..."] |
$HTTP["cookie"] |
lighty.r.req_header["Cookie"] |
$HTTP["useragent"] |
lighty.r.req_header["User-Agent"] |
$HTTP["language"] |
lighty.r.req_header["Accept-Language"] |
$HTTP["referer"] |
lighty.r.req_header["Referer"] |
在 mod_magnet 阶段 |
lighty.r.req_attr["physical.path"] | 物理路径存在 |
lighty.c.stat(...) | 已弃用¶ |
mod_magnet API (lighttpd 1.4.60 以前版本)¶
(注意:此旧版 API 已弃用。请优先使用 lighty.r 请求对象)
lighty.*
表¶
mod_magnet 和 lighttpd 之间的大部分交互都是通过表完成的。Lua 中的表类似于哈希(Perl、Ruby)、字典(Java、Python)、关联数组(PHP)等。以下表支持 pairs()
来迭代其条目。
lighty.request[] - 某些请求头如 Host、Cookie 或 User-Agent 可用(推荐:lighty.r.req_header[]
)- lighty.req_env[] - 请求环境变量(推荐:
lighty.r.req_env[]
) - lighty.env[] - 请求属性(推荐:
lighty.r.req_attr[]
)(请参阅 lighty.r 请求对象) - lighty.header[] - 某些响应头如 Location 可用(推荐:
lighty.r.resp_header[]
) - lighty.content[] - 响应体(推荐:
lighty.r.resp_body.set()
) - lighty.status[] - 统计信息(推荐:
lighty.server.plugin_stats[]
) lighty.header[]
(推荐:lighty.r.resp_header[]
)¶
如果要为请求设置响应头,可以向 lighty.header[] 表添加字段
lighty.header["Content-Type"] = "text/html"lighty.content[]
(推荐:lighty.r.resp_body.set()
)¶
您可以生成自己的内容并将其作为响应发送。lighty.content[]
表可以包含字符串或文件信息表。脚本完成后,响应将通过按顺序连接所有表元素来生成。
字符串 - 复制到响应中
- 表 - 表示响应的文件信息
- filename = "<absolute-path>" 是必需的
- offset = <number> [默认值: 0]
- length = <number> [默认值: 文件大小]
- 这将发送文件的范围 [offset, length-1]。
(“length”参数命名不当,实际上表示范围偏移量 + 1;为了与现有脚本的历史兼容性而保持不变)
移植 mod_cml 脚本¶
lighty.content = { "<pre>", { filename = "/etc/motd" }, "</pre>" } lighty.header["Content-Type"] = "text/html" return 200
mod_cml 已被 mod_magnet 取代。
mod_cml 函数memcache_get_string()
memcache_get_long()
memcache_exists()
(以及 lighttpd.conf cml.memcache-hosts
)应替换为仅限 Lua 的解决方案- https://github.com/silentbicycle/lua-memcached
mod_cml 函数dir_files
应替换为lighty.c.readdir()
(自 1.4.60 起)
- mod_cml 中的 CACHE_HIT
- output_include = { "file1", "file2" }
return CACHE_HIT
在 mod_magnet 中变为
lighty.r.resp_body.set({ { filename = "/path/to/file1" }, { filename = "/path/to/file2"} })return 200
mod_cml 中的 CACHE_MISS
- trigger_handler = "/index.php"
return CACHE_MISS
lighty.r.req_attr["request.uri"] = "/index.php"
lighty.r.resp_body.set({ { filename = "/path/to/file1" }, { filename = "/path/to/file2"} })return lighty.RESTART_REQUEST
有问题?请在 lighttpd 论坛发帖
文件 (0)
由 Redmine © 2006-2025 Jean-Philippe Lang 提供技术支持