summary refs log tree commit
path: root/lib/rack/conditionalget.rb
diff options
context:
space:
mode:
authorJosé Valim <jose.valim@gmail.com>2010-07-18 20:00:59 +0200
committerraggi <jftucker@gmail.com>2010-07-19 20:08:29 +0100
commite344d3256f4e4b59677dcd0401b4bd4816416ae7 (patch)
tree14c56e99607b4576d3308cf508ee7b99acab932d /lib/rack/conditionalget.rb
parentc73b474525bace3f059a130b15413abd4d917086 (diff)
downloadrack-e344d3256f4e4b59677dcd0401b4bd4816416ae7.tar.gz
Make ConditionalGet middleware respect HTTP specification.
The specification says if both IF_NONE_MATCH and IF_MODIFIED_SINCE are sent, both should match in order to return 304.

Signed-off-by: raggi <jftucker@gmail.com>
Diffstat (limited to 'lib/rack/conditionalget.rb')
-rw-r--r--lib/rack/conditionalget.rb30
1 files changed, 23 insertions, 7 deletions
diff --git a/lib/rack/conditionalget.rb b/lib/rack/conditionalget.rb
index 046ebdb0..bc6c856b 100644
--- a/lib/rack/conditionalget.rb
+++ b/lib/rack/conditionalget.rb
@@ -24,7 +24,7 @@ module Rack
 
       status, headers, body = @app.call(env)
       headers = Utils::HeaderHash.new(headers)
-      if etag_matches?(env, headers) || modified_since?(env, headers)
+      if fresh?(env, headers)
         status = 304
         headers.delete('Content-Type')
         headers.delete('Content-Length')
@@ -34,14 +34,30 @@ module Rack
     end
 
   private
-    def etag_matches?(env, headers)
-      etag = headers['Etag'] and etag == env['HTTP_IF_NONE_MATCH']
+
+    def fresh?(env, headers)
+      modified_since = env['HTTP_IF_MODIFIED_SINCE']
+      none_match     = env['HTTP_IF_NONE_MATCH']
+
+      return false unless modified_since || none_match
+
+      success = true
+      success &&= modified_since?(to_rfc2822(modified_since), headers) if modified_since
+      success &&= etag_matches?(none_match, headers) if none_match
+      success
     end
 
-    def modified_since?(env, headers)
-      last_modified = headers['Last-Modified'] and
-        last_modified == env['HTTP_IF_MODIFIED_SINCE']
+    def etag_matches?(none_match, headers)
+      etag = headers['Etag'] and etag == none_match
     end
-  end
 
+    def modified_since?(modified_since, headers)
+      last_modified = to_rfc2822(headers['Last-Modified']) and
+        modified_since >= last_modified
+    end
+
+    def to_rfc2822(since)
+      Time.rfc2822(since) rescue nil
+    end
+  end
 end