On Being for the Web

August 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 = ''
      end
    end
  end

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.

About

This page contains a single entry from Stefan Tilkov's Random Stuff posted on August 5, 2007 11:41 PM. The previous post in this blog was Google Spreadsheets, CSV, Venus. The next post in this blog is syx - Open Source Smalltalk. Many more can be found on the main index page or by looking through the archives.

Comments

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

Posted by: Tim Bray at August 6, 2007 5:49 AM | link

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.

Posted by: Stefan Tilkov at August 6, 2007 10:03 AM | link