Re: Ideas for an output filter for mod_lua

2012-08-24 Thread Daniel Gruno
On 08/23/2012 11:32 PM, Tim Bannister wrote:
 On 23 Aug 2012, at 11:45, Daniel Gruno rum...@cord.dk wrote:
 On 08/23/2012 12:02 AM, Tim Bannister wrote:
 My patch is for implementing gzip compression by httpd, not decompression, 
 but the code will look pretty similar.
 
 That's quite neat, then. I will try to make an actual implementation in Lua.
 The part I found difficult was the interaction with the second 
 transfer-encoding, “chunked”. Using gzip Transfer-Encoding: implies using 
 chunked, because we want to shorten the response and this means that the 
 Content-Length definitely doesn't match the size of the HTTP response body.
 
I took a shot at an actual compression filter in Lua today, that uses
zlib to deflate buckets and sends it as chunked data to the client.

The script I used can be found at http://apaste.info/OPHa and I've
verified that it works well for compressing text (I compressed a 50kb
html output from a Lua script down to a 5kb chunked message with 4
separate chunks due to calling r:flush() in the script)

The documentation for these new filters can be temporarily found at
http://www.humbedooh.com/mod_lua.html.en#modifying_buckets while I
polish it off for final committing (I have a bad habit of committing
stuff, then making 10 new revisions later on ;) ).

I just need to finish off some final adjustments, and I'll be committing
the Lua filter support to the trunk for review and nagging.

With regards,
Daniel.


Re: Ideas for an output filter for mod_lua

2012-08-23 Thread Daniel Gruno
On 08/23/2012 12:02 AM, Tim Bannister wrote:
 On 22 Aug 2012, at 22:25, Daniel Gruno rum...@cord.dk wrote:
 
 Would your concept meaningfully generalise beyond application-level filters?

 I'm not entirely sure what you mean by this, could you elaborate?
 If you want some more sophisticated examples of what could be achieved with 
 Lua filtering, I'd be happy to provide some more details on how this concept 
 could be utilised.
 
 I don't know if this is another way of phrasing Nick's question or not, but 
 would I be able to implement gzip Transfer-Encoding: just using Lua and this 
 new directive?
 
 I found (bug 52860) it a bit tricky to achieve in C, so I think it could be 
 harder still with the extra limitations of the Lua environment. My C code 
 uses AP_FTYPE_TRANSCODE which I think is the right choice but few modules get 
 involved at this filtering stage.
 
The filter phases are as follows (as with any other filter mod):
1) mod_lua calls a setup function before buckets are sent, to allow for
headers to be changed and data to be inserted before the actual content,
fx. appending an advertisment a'la old Geocities or some such.
2) The Lua function yields to let mod_lua know it's ready to receive buckets
3) Buckets are sent, one by one to the function, which processes them,
and again yields with the new content for each bucket.
4) once all buckets have passed through, mod_lua makes a final call with
an empty (nil) buffer, allowing the Lua script to add any additional
tail calls/data to the filter (it adds tail data by yielding with
whatever should be added). Thus, an example Lua function could be:

---
function filter(r)
-- Initial phase
r.content_type = text/plain -- set up some stuff
coroutine.yield() -- End initial phase

-- bucket phase
while (buffer) do -- for each bucket sent, do...
local output = mangle(buffer) -- transformation
coroutine.yield(output) -- Send the output down the chain
end

-- Final phase once all buckets have been sent
clean_up()
coroutine.yield(This line will be appended to all files)
end
---

So yes, theoretically you should be able to implement decompression this
way, by doing something along the lines of this (totally just making it up):

-
local zip = require zlib -- or something...
function gzip_handle(r)
r.headers_out['Transfer-Encoding'] = gzip -- or ?
do_magic_header_stuff_here() -- add header data
coroutine.yield() -- yield and wait for buckets
while (buffer) do  -- for each bucket, deflate it
local deflated = zip.deflate(buffer)
coroutine.yield(deflated) -- pass on new data
end
append_tail_to_output() -- pass on a tail if needed
end
-

I haven't tried this out with gzip, but I have tried with
base64_encoding a lot of files through a test filter that works similar
to what I wrote above. I'm using AP_FTYPE_RESOURCE for the testing, but
surely we could either change that or add some additional optional
argument to the directive to control where it should place itself.

As a 'fun' side effect of doing this in Lua, you can use the same filter
functions for both input and output filtering, as they work the same
way, although I don't know of any filters that would benefit from it ;)

In any case, I'll get started on adding an input filter hook as well,
and see if I can get it working just as well as the output filter I have
in place, and then commit something snazzy for review.

With regards,
Daniel.


Re: Ideas for an output filter for mod_lua

2012-08-23 Thread Tim Bannister
On 23 Aug 2012, at 11:45, Daniel Gruno rum...@cord.dk wrote:
 On 08/23/2012 12:02 AM, Tim Bannister wrote:
 
 I don't know if this is another way of phrasing Nick's question or not, but 
 would I be able to implement gzip Transfer-Encoding: just using Lua and this 
 new directive?
 
 I found (bug 52860) it a bit tricky to achieve in C, so I think it could be 
 harder still with the extra limitations of the Lua environment. My C code 
 uses AP_FTYPE_TRANSCODE which I think is the right choice but few modules 
 get involved at this filtering stage.
…
 So yes, theoretically you should be able to implement decompression this
 way, by doing something along the lines of this (totally just making it up):
 
 -
 local zip = require zlib -- or something...
 function gzip_handle(r)
r.headers_out['Transfer-Encoding'] = gzip -- or ?
do_magic_header_stuff_here() -- add header data
coroutine.yield() -- yield and wait for buckets
while (buffer) do  -- for each bucket, deflate it
local deflated = zip.deflate(buffer)
coroutine.yield(deflated) -- pass on new data
end
append_tail_to_output() -- pass on a tail if needed
 end
 -

My patch is for implementing gzip compression by httpd, not decompression, but 
the code will look pretty similar.

That's quite neat, then. I will try to make an actual implementation in Lua.
The part I found difficult was the interaction with the second 
transfer-encoding, “chunked”. Using gzip Transfer-Encoding: implies using 
chunked, because we want to shorten the response and this means that the 
Content-Length definitely doesn't match the size of the HTTP response body.

-- 
Tim Bannister – is...@jellybaby.net



smime.p7s
Description: S/MIME cryptographic signature


Re: Ideas for an output filter for mod_lua

2012-08-23 Thread Nick Kew
On Thu, 23 Aug 2012 22:32:20 +0100
Tim Bannister is...@jellybaby.net wrote:


 That's quite neat, then. I will try to make an actual implementation in Lua.
 The part I found difficult was the interaction with the second 
 transfer-encoding, “chunked”. Using gzip Transfer-Encoding: implies using 
 chunked, because we want to shorten the response and this means that the 
 Content-Length definitely doesn't match the size of the HTTP response body.

gzip is a content-encoding, not a transfer-encoding.

That makes it easy to implement: content filters and protocol
filters work at different levels, so can coexist without trouble.


-- 
Nick Kew


Re: Ideas for an output filter for mod_lua

2012-08-23 Thread Roy T. Fielding

On Aug 23, 2012, at 2:49 PM, Nick Kew wrote:

 On Thu, 23 Aug 2012 22:32:20 +0100
 Tim Bannister is...@jellybaby.net wrote:
 
 
 That's quite neat, then. I will try to make an actual implementation in Lua.
 The part I found difficult was the interaction with the second 
 transfer-encoding, “chunked”. Using gzip Transfer-Encoding: implies using 
 chunked, because we want to shorten the response and this means that the 
 Content-Length definitely doesn't match the size of the HTTP response body.
 
 gzip is a content-encoding, not a transfer-encoding.

It is both.  Transfer-Encoding is the correct way to implement it.

 That makes it easy to implement: content filters and protocol
 filters work at different levels, so can coexist without trouble.

Except that they aren't standards-compliant because they don't
handle etags correctly.  Content-Encoding works with more clients
but is much harder to implement correctly.

Roy



Re: Ideas for an output filter for mod_lua

2012-08-22 Thread Nick Kew

On 22 Aug 2012, at 12:00, Daniel Gruno wrote:

 So, any feedback, comments, thoughts on this?

Basic concept looks fine.  I guess we'd need more detail
to say any more about it.

Is the implementation 'clean' or does it involve hacks to core?
If what you have is pure module then I'd see no reason
not to drop mod_lua_filter (or is it mod_filter_lua?)
into trunk on CTR.

Meanwhile, some random thoughts:

Is there a deep reason to limit it to output filters, or is that
just what you happen to have implemented?

Would your concept meaningfully generalise beyond
application-level filters?

-- 
Nick Kew


Re: Ideas for an output filter for mod_lua

2012-08-22 Thread Daniel Gruno
On 08/22/2012 01:36 PM, Nick Kew wrote:
 
 Basic concept looks fine.  I guess we'd need more detail
 to say any more about it.
 
 Is the implementation 'clean' or does it involve hacks to core?
 If what you have is pure module then I'd see no reason
 not to drop mod_lua_filter (or is it mod_filter_lua?)
 into trunk on CTR.

I don't see why it should be made a separate module - it relies and
operates on the stuff already inside mod_lua, and making it a part of it
only requires adding some 50-60 lines of code (ymmv). But ideas/opinions
are of course welcome.

As for the 'cleanliness' of the code, there are no hacks, it works
similar to how the other hook functions in mod_lua work. Each call to a
Lua(In|Out)putFilter would register a new filter with a callback to fx
ap_lua_output_filter, which will then traverse a list of known
scripts/handles, find the one associated with the filter name in
question and run it, making the Lua script yield whenever it's parsed a
bucket and sending it further down the chain. Apart from the actual
bucket handling, the function and the directives behave just as the
other hooks and the LuaMapHandler does. When called, it would register a
file/function in an array, and when a call is made to that handler, it
checks to see what is being called, and finds the file/function
associated with it.

i.e. if you had two directives:
LuaOutputFilter filterA /www/filters.lua filter_a_func
LuaOutputFilter filterB /www/filters.lua filter_b_func

then an output, with any of those two filters attached, would call
ap_lua_output_filter, which would look up the filter currently being run
and then run the file/function mapped to that filter. I guess what
separates this from the other hooks the most is that it relies on
co-routines (aka non-blocking/event-based or whatever the newest buzz
word for it is) to get the job done.

 
 Meanwhile, some random thoughts:
 
 Is there a deep reason to limit it to output filters, or is that
 just what you happen to have implemented?

The same method could be applied to input filters as well, I just had an
interest in trying it out for output filters, so that's what I hacked
together before making this proposal. I'll try implementing an input
filter tomorrow.

 
 Would your concept meaningfully generalise beyond
 application-level filters?
 

I'm not entirely sure what you mean by this, could you elaborate?
If you want some more sophisticated examples of what could be achieved
with Lua filtering, I'd be happy to provide some more details on how
this concept could be utilised.

With regards,
Daniel.


Re: Ideas for an output filter for mod_lua

2012-08-22 Thread Tim Bannister
On 22 Aug 2012, at 22:25, Daniel Gruno rum...@cord.dk wrote:

 Would your concept meaningfully generalise beyond application-level filters?
 
 I'm not entirely sure what you mean by this, could you elaborate?
 If you want some more sophisticated examples of what could be achieved with 
 Lua filtering, I'd be happy to provide some more details on how this concept 
 could be utilised.

I don't know if this is another way of phrasing Nick's question or not, but 
would I be able to implement gzip Transfer-Encoding: just using Lua and this 
new directive?

I found (bug 52860) it a bit tricky to achieve in C, so I think it could be 
harder still with the extra limitations of the Lua environment. My C code uses 
AP_FTYPE_TRANSCODE which I think is the right choice but few modules get 
involved at this filtering stage.

-- 
Tim Bannister – is...@jellybaby.net



smime.p7s
Description: S/MIME cryptographic signature