Search code examples
apacheluamod-lua

Read response body in Apache mod_lua


I'm prototyping a simple "output" filter with Apache + mod_lua. How can I read response body, at the end of other native output filters applied, via LUA? For example, can I get the actual response that will be sent to the client?


Solution

  • The manual has some good guidance on this:

    http://httpd.apache.org/docs/current/mod/mod_lua.html#modifying_buckets

    Modifying contents with Lua filters Filter functions implemented via LuaInputFilter or LuaOutputFilter are designed as three-stage non-blocking functions using coroutines to suspend and resume a function as buckets are sent down the filter chain. The core structure of such a function is:

    function filter(r)
        -- Our first yield is to signal that we are ready to receive buckets.
        -- Before this yield, we can set up our environment, check for conditions,
        -- and, if we deem it necessary, decline filtering a request alltogether:
        if something_bad then
            return -- This would skip this filter.
        end
        -- Regardless of whether we have data to prepend, a yield MUST be called here.
        -- Note that only output filters can prepend data. Input filters must use the 
        -- final stage to append data to the content.
        coroutine.yield([optional header to be prepended to the content])
    
        -- After we have yielded, buckets will be sent to us, one by one, and we can 
        -- do whatever we want with them and then pass on the result.
        -- Buckets are stored in the global variable 'bucket', so we create a loop
        -- that checks if 'bucket' is not nil:
        while bucket ~= nil do
            local output = mangle(bucket) -- Do some stuff to the content
            coroutine.yield(output) -- Return our new content to the filter chain
        end
    
        -- Once the buckets are gone, 'bucket' is set to nil, which will exit the 
        -- loop and land us here. Anything extra we want to append to the content
        -- can be done by doing a final yield here. Both input and output filters 
        -- can append data to the content in this phase.
        coroutine.yield([optional footer to be appended to the content])
    end