Section 6.3. Filters


6.3. Filters

Sometimes you don't really want to handle a request, but you want to be able to modify the results coming in or going out of the server dynamically. Mongrel's HttpHandler classes can do this since they by default act in a chain. In this situation you are ostensibly writing a "filter," which is really just a handler that modifies its results.

This brings up another point: handlers don't have to do any processing. It's perfectly legal for them to make a decision and do nothing, allowing the remaining handlers do their thing instead.

For our first filter we're going to write a class that removes any HTTP_USER_AGENT headers coming in, and then another filter that deflate compresses (deflates) its output. First the UserAgentRemover:

class UserAgentRemover < Mongrel::HttpHandler   def process(req, resp)     if req.params.delete "HTTP_USER_AGENT"       STDERR.puts "Removed a user agent"     end   end end uri "/dumped", :handler => UserAgentRemover.new, :in_front => true


Pretty simple, we just delete it from the params hash and log a simple message. If you need to do simple logging then use STDERR since this is written to the log/mongrel.log file or the console and isn't hijacked by the framework. If you need to do serious logging then use Ruby's Logger.

The above code assumes that you put this in the mongrel.conf after the first uri call. This is why this block of code as a :in_front parameter, which tells the Configurator that you want this handler moved to the front of the chain.

Run your mongrel_rails again and hit the /dumped URI to see that HTTP_USER_AGENT is actually removed.

This ability to modify requests as they come in with simple handler chains means that you can perform security checks, clean up requests, do file processing, and other tasks prior to Rails or another framework getting the results. We'll now write another handler that does nearly the same thing but it takes results and translates them into deflate form. Add this next block to your mongrel.conf file:

[View full width]

require 'zlib' class DeflateFilter < HttpHandler def initialize(ops={}) @options = ops @always_deflate = ops[:always_deflate] || false end def process(request, response) accepts = request.params['HTTP_ACCEPT_ENCODING'] # only process if they support compression if @always_deflate or (accepts and (accepts.include? 'deflate' and not response .body_sent)) response.header['Content-Encoding'] = 'deflate' # we can't just rewind the body and gzip it since the body could be an attached file response.body.rewind gzout = StringIO.new(Zlib::Deflate.deflate(response.body.read)) gzout.rewind response.body.close response.body = gzout end end end uri "/dumped", :handler => DeflateFilter.new


Obviously this handler is more involved, but it's a good example of doing something useful with HttpHandlers as filters. Let's walk through it:

  1. It shows how to set up some default options and write your own initialize. HttpHandler is very thin and you can modify the initialize method however you want. In this case we allow a Hash parameter style and let the user configure the handler.

  2. We then peel out the encodings the client accepts so we can see if they accept "deflate."

  3. If they accept it then we set the "Content-Encoding" to "deflate" and we deflate compress the body using Ruby's Zlib::Deflate API. Notice that we have to do some shuffling of the response body. If we were to gzip the response directly, and the previous handler had attached a file to send, then we'd be gzip their files silently.

  4. Instead we deflate their file into a StringIO, detach it and send it on, closing the original.

This filter isn't put on the handler chain with :in_front so it will happen after ParamDumper. If we were to draw a picture of this setup it'd look like Figure 6.2, even though in the mongrel.conf we added them in a different order. This is necessary since, if you need to put a filter in front of say RailsHandler, then :in_front lets you do that.

Figure 6.2. Handler Chain Processing





Mongrel. Serving, Deploying, and Extending Your Ruby Applications
Mongrel. Serving, Deploying, and Extending Your Ruby Applications
ISBN: 9812836357
EAN: N/A
Year: 2006
Pages: 48

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net