On Being for the Web

, Aug 5, 2007

Tim Bray, talking about ETags:

What you want to do is compute the ETag based on the underlying data resources that actually drive the page creation; the input to that process, not its output. This is often going to be a small number (sometimes one) of timestamp or version fields in a database row, or metadata from the underlying filesystem. It’s also going to be application-dependent. So a framework that was really designed for the Web would expose the ETag generation to the application programmer in a way that let them be smart about conserving the resources that actually matter.

Very true; this is what Joe Gregorio wrote about a while ago. Contrary to the Tim’s impression, this seems to be exactly what Rails does:

  def handle_conditional_get!
if body.is_a?(String) && (headers['Status'] ? headers['Status'][0..2] == '200' : true)  && !body.empty?
self.headers['ETag'] ||= %("#{Digest::MD5.hexdigest(body)}")
self.headers['Cache-Control'] = 'private' if headers['Cache-Control'] == DEFAULT_HEADERS['Cache-Control']

if request.headers['HTTP_IF_NONE_MATCH'] == headers['ETag']
self.headers['Status'] = '304 Not Modified'
self.body = ''

In other words: you can set the header yourself; if you do so, it’s set and Rails will leave it as is. Back in March, I thought that it might make sense to add something in the lower layers to support this. I’m not so sure anymore; it’s probably better to leave this to the application developer.

On August 6, 2007 5:49 AM, Tim Bray said:

Um, are you sure? I’m reading that code and the first thing I see is

if body.is_a?(String) ...

which suggests that you’ve gone ahead and computed the whole result before you start thinking about conditional-get headers. My point is that the big win would be in avoiding computing the result body. But I’m still a relative Rails newb, so maybe I’m missing something obvious

On August 6, 2007 10:03 AM, Stefan Tilkov said:

First disclaimer: this is not my code, it’s taken straight from Edge Rails. What I meant is: the default code computes an ETag if it isn’t set. If you set the ETag yourself, no magic happens and it’s passed straight through.