# HG changeset patch # User Mahlon E. Smith # Date 1505322550 25200 # Wed Sep 13 10:09:10 2017 -0700 # Node ID bf37a1852e615f98a33af453394ed8ea5fa530ee # Parent 6665c33cf990ae6f9490fc713995e7f359a5d541 Add Last-Modified/If-None-Match support. This allows caching to still take place even if not using the checksum plugin. diff --git a/lib/thingfish/handler.rb b/lib/thingfish/handler.rb --- a/lib/thingfish/handler.rb +++ b/lib/thingfish/handler.rb @@ -333,7 +333,7 @@ metadata = self.metastore.fetch( uuid ) res = req.response - self.add_etag_headers( req, metadata ) + self.add_cache_headers( req, metadata ) self.add_content_disposition( res, metadata ) res.body = object @@ -356,7 +356,7 @@ res = req.response res.content_type = metadata['format'] - self.add_etag_headers( req, metadata ) + self.add_cache_headers( req, metadata ) self.add_content_disposition( res, metadata ) if object.respond_to?( :path ) @@ -716,9 +716,9 @@ ### Return a Hash of default metadata extracted from the given +request+. def extract_default_metadata( request ) return self.extract_connection_metadata( request ).merge( - 'extent' => request.headers.content_length, - 'format' => request.content_type, - 'created' => Time.now.getgm + 'extent' => request.headers.content_length, + 'format' => request.content_type, + 'created' => Time.now.getgm ) end @@ -787,19 +787,30 @@ end - ### Add browser cache headers for resources. This requires the sha256 + ### Add browser cache headers for resources. + ### Last-Modified is always added. ETag support requires the sha256 ### processor plugin to be enabled for stored resources. - def add_etag_headers( request, metadata ) + ### + def add_cache_headers( request, metadata ) response = request.response - checksum = metadata[ 'checksum' ] - return unless checksum - if (( match = request.headers[ :if_none_match ] )) - match = match.gsub( '"', '' ).split( /,\s*/ ) - finish_with( HTTP::NOT_MODIFIED ) if match.include?( checksum ) + # ETag takes precedence if available. + # + if (( checksum = metadata['checksum'] )) + if (( match = request.headers[ :if_none_match ] )) + match = match.gsub( '"', '' ).split( /,\s*/ ) + finish_with( HTTP::NOT_MODIFIED ) if match.include?( checksum ) + end + response.headers[ :etag ] = checksum end - response.headers[ :etag ] = checksum + return unless metadata[ 'created' ] + + if (( modified = request.headers[ :if_modified_since ] )) + finish_with( HTTP::NOT_MODIFIED ) if Time.parse( modified ) <= metadata['created'].round + end + response.headers[ :last_modified ] = metadata[ 'created' ].httpdate + return end diff --git a/spec/thingfish/handler_spec.rb b/spec/thingfish/handler_spec.rb --- a/spec/thingfish/handler_spec.rb +++ b/spec/thingfish/handler_spec.rb @@ -359,7 +359,20 @@ end - it "adds browser cache headers to resources with a checksum attribute" do + it "adds date cache headers to resources" do + created = Time.now + uuid = @handler.datastore.save( @png_io ) + @handler.metastore.save( uuid, 'format' => 'image/png', 'created' => created ) + + req = factory.get( "/#{uuid}" ) + result = @handler.handle( req ) + + expect( result.status_line ).to match( /200 ok/i ) + expect( result.headers.last_modified ).to eq( created.httpdate ) + end + + + it "adds content cache headers to resources with a checksum attribute" do uuid = @handler.datastore.save( @png_io ) @handler.metastore.save( uuid, 'format' => 'image/png', 'checksum' => '123456' ) @@ -385,7 +398,21 @@ end - it "returns a 304 not modified for unchanged client cache requests" do + it "returns a 304 not modified for unchanged date cache requests" do + created = Time.now + uuid = @handler.datastore.save( @png_io ) + @handler.metastore.save( uuid, 'format' => 'image/png', 'created' => created ) + + req = factory.get( "/#{uuid}" ) + req.headers[ :if_modified_since ] = ( Time.now - 300 ).httpdate + result = @handler.handle( req ) + + expect( result.status_line ).to match( /304 not modified/i ) + expect( result.body.read ).to be_empty + end + + + it "returns a 304 not modified for unchanged content cache requests" do uuid = @handler.datastore.save( @png_io ) @handler.metastore.save( uuid, 'format' => 'image/png', 'checksum' => '123456' ) @@ -398,7 +425,6 @@ end - it "can remove everything associated with an object id" do uuid = @handler.datastore.save( @png_io ) @handler.metastore.save( uuid, {