M lib/thingfish/handler.rb +24 -13
@@ 333,7 333,7 @@ class Thingfish::Handler < Strelka::App
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 @@ class Thingfish::Handler < Strelka::App
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 @@ class Thingfish::Handler < Strelka::App
### 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 @@ class Thingfish::Handler < Strelka::App
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
M spec/thingfish/handler_spec.rb +29 -3
@@ 359,7 359,20 @@ describe Thingfish::Handler do
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 @@ describe Thingfish::Handler do
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 @@ describe Thingfish::Handler do
end
-
it "can remove everything associated with an object id" do
uuid = @handler.datastore.save( @png_io )
@handler.metastore.save( uuid, {