Merged updates from trunk into stable branch
[feedcatcher.git] / vendor / rails / actionpack / lib / action_controller / vendor / rack-1.0 / rack / conditionalget.rb
diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/conditionalget.rb b/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.0/rack/conditionalget.rb
new file mode 100644 (file)
index 0000000..7bec824
--- /dev/null
@@ -0,0 +1,45 @@
+require 'rack/utils'
+
+module Rack
+
+  # Middleware that enables conditional GET using If-None-Match and
+  # If-Modified-Since. The application should set either or both of the
+  # Last-Modified or Etag response headers according to RFC 2616. When
+  # either of the conditions is met, the response body is set to be zero
+  # length and the response status is set to 304 Not Modified.
+  #
+  # Applications that defer response body generation until the body's each
+  # message is received will avoid response body generation completely when
+  # a conditional GET matches.
+  #
+  # Adapted from Michael Klishin's Merb implementation:
+  # http://github.com/wycats/merb-core/tree/master/lib/merb-core/rack/middleware/conditional_get.rb
+  class ConditionalGet
+    def initialize(app)
+      @app = app
+    end
+
+    def call(env)
+      return @app.call(env) unless %w[GET HEAD].include?(env['REQUEST_METHOD'])
+
+      status, headers, body = @app.call(env)
+      headers = Utils::HeaderHash.new(headers)
+      if etag_matches?(env, headers) || modified_since?(env, headers)
+        status = 304
+        body = []
+      end
+      [status, headers, body]
+    end
+
+  private
+    def etag_matches?(env, headers)
+      etag = headers['Etag'] and etag == env['HTTP_IF_NONE_MATCH']
+    end
+
+    def modified_since?(env, headers)
+      last_modified = headers['Last-Modified'] and
+        last_modified == env['HTTP_IF_MODIFIED_SINCE']
+    end
+  end
+
+end