That wouldn't do, and since my app is using Rack to interface to the webserver, there's a simple solution: Write a tiny Rack middleware class, just like I described in "Rewriting content types with Rack".
The great thing is that because of Rack this class can be used to add cache headers for anything from pure Rack based apps to apps using Rails, Merb, or any number of other Ruby frameworks that has Rack adapters. If you haven't looked into Rack already, do.
I added the following in a file named "cachesettings.rb":
class CacheSettings
def initialize app, pat
@app = app
@pat = pat
end
def call env
res = @app.call(env)
path = env["REQUEST_PATH"]
@pat.each do |pattern,data|
if path =~ pattern
res[1]["Cache-Control"] = data[:cache_control] if data.has_key?(:cache_control)
res[1]["Expires"] = (Time.now + data[:expires]).utc.rfc2822 if data.has_key?(:expires)
return res
end
end
res
end
end
It's pretty straightforward:
I then added it to my config.ru (the Rack config file for my app) like this:
require 'cachesettings'
use CacheSettings, {
/\/static\// =>
{ :cache_control => "max-age=86400, public",
:expires => 86400
}
}
use Rack::Static, :urls => ["/static"]
That's all there's too it - it can add cache headers to any arbitrary results. It should be obvious how to extend this to add any arbitrary headers too, or rewrite existing headers.
Useful exercises for the reader: Extend it to allow adding a Last-Modified header or Etag's.