项目

概况

个人资料

操作

LuaExamples

X-Sendfile 版本 1

此配置片段插入一个 Lua 过滤器,用于检查 "X-Sendfile" 头部;如果找到非空值,则将其用作文件路径名来替换内容。
缺点是,即使没有 "X-Sendfile" 头部,"XSendfile:handle" 也会为每个发送给用户的数据块调用(Lua 不读取数据,它只是转发数据块,但这仍然不够优化)。
但此过滤器可以在你的配置中的任何位置插入,甚至在内容处理器之前。

-- create new class XSendfile
local XSendfile = { }
XSendfile.__index = XSendfile

-- "classmethod" to create new instance
function XSendfile:new(vr)
--    vr:debug("New XSendfile instance")
    local o = { handling = 0  }
    setmetatable(o, self)
    return o
end

-- normal method to handle content
function XSendfile:handle(vr, outq, inq)
--    vr:debug("XSendfile:handle "..self.handling)
    if self.handling == 1 then
        -- already sent the file, ignore further input (we closed it already)
        inq:skip_all()
        return lighty.HANDLER_GO_ON
    elseif self.handling == -1 then
        -- no X-Sendfile header, so just forward content and make sure to close chunkqueues if done
        outq:steal_all(inq)
        if inq.is_closed then -- no more input from backend
            outq.is_closed = true
        elseif outq.is_closed then -- client (or other filter after us) closed stream
            inq.is_closed = true
        end
        return lighty.HANDLER_GO_ON
    else
        if outq.is_closed then -- client (or other filter after us) closed stream
            inq:skip_all()
            inq.is_closed = true
            return lighty.HANDLER_GO_ON
        end

        -- check x-sendfile header
        local xs = vr.resp.headers["X-Sendfile"]
        if xs and xs ~= "" then -- file specified
            vr.resp.headers["X-Sendfile"] = nil -- remove header from response

            -- Add checks for the pathname here

            vr:debug("XSendfile:handle: pushing file '" .. xs .. "' as content")
            outq:add({ filename = xs })
            outq.is_closed = true
            inq:skip_all()
            inq.is_closed = true
            self.handling = 1
        else
            self.handling = -1
        end
        return lighty.HANDLER_GO_ON
    end
end

actions = lighty.filter_out(XSendfile)

X-Sendfile 版本 2

此配置片段等待响应头部,然后用在 "X-Sendfile" 头部中找到的文件名替换内容(如果它不为空)。
此版本不需要太多 CPU;假定真实的后端无论如何都不会发送内容,并且文件是一步到位发送的,因此 "XFilterDrop:handle" 可能不会经常被调用。
但此版本将在操作中等待响应头部,因此在此之前你需要一个内容处理器(如静态、FastCGI 等)。

-- create new class XFilterDrop
local XFilterDrop = { }
XFilterDrop.__index = XFilterDrop

-- "classmethod" to create new instance
function XFilterDrop:new(vr)
--    vr:debug("New XSendfile instance")
    local o = { }
    setmetatable(o, self)
    return o
end

-- normal method to handle content
function XFilterDrop:handle(vr, outq, inq)
    -- drop further input (we closed it already)
    inq:skip_all()
    return lighty.HANDLER_GO_ON
end

-- create a new filter which drops all input and adds it to the vrequest
-- returns the filter object so you can insert your own content in f.out (it is already closed)
local function add_drop_filter(vr)
    local f = vr:add_filter_out(XFilterDrop:new())
    f['in'].is_closed = true
    f['in']:skip_all()
    f.out.is_closed = true
    return f
end

local function handle_x_sendfile(vr)
--    vr:debug("handle x-sendfile")
    -- wait for response
    if not vr.has_response then
        if vr.is_handled then
--            vr:debug("x-sendfile: waiting for response headers")
            return lighty.HANDLER_WAIT_FOR_EVENT
        else
--            vr:debug("No response handler yet, cannot handle X-Sendfile")
            return lighty.HANDLER_GO_ON
        end
    end
--    vr:debug("handle x-sendfile: headers available")
    -- add filter if x-sendfile header is not empty
    local xs = vr.resp.headers["X-Sendfile"]
    if xs and xs ~= "" then
        -- make sure to drop all other content from the backend
        local f = add_drop_filter(vr)

        vr.resp.headers["X-Sendfile"] = nil -- remove header from response

        -- Add checks for the pathname here

        vr:debug("XSendfile:handle: pushing file '" .. xs .. "' as content")
        f.out:add({ filename = xs })
    end
end

actions = handle_x_sendfile

更新者 stbuehler 大约 11 年前 · 4 个修订