diff --git a/lib/remote_storage/rest_provider.rb b/lib/remote_storage/rest_provider.rb index 37ebe10..0e95577 100644 --- a/lib/remote_storage/rest_provider.rb +++ b/lib/remote_storage/rest_provider.rb @@ -36,23 +36,30 @@ module RemoteStorage end def get_head(user, directory, key) - url = url_for_key(user, directory, key) + none_match = (server.env["HTTP_IF_NONE_MATCH"] || "").split(",") + .map(&:strip) + .map { |s| s.gsub(/^"?W\//, "") } + metadata = redis.hgetall redis_metadata_object_key(user, directory, key) - res = do_head_request(url) + server.halt 404 if metadata.empty? - set_response_headers(res) - rescue RestClient::ResourceNotFound - server.halt 404 + # Set the response headers for a 304 or 200 response + server.headers["ETag"] = %Q("#{metadata["e"]}") + server.headers["Last-Modified"] = Time.at(metadata["m"].to_i / 1000).httpdate + + if none_match.include? %Q("#{metadata["e"]}") + server.halt 304 + end end def get_data(user, directory, key) none_match = (server.env["HTTP_IF_NONE_MATCH"] || "").split(",") .map(&:strip) .map { |s| s.gsub(/^"?W\//, "") } - existing_metadata = redis.hgetall redis_metadata_object_key(user, directory, key) - if none_match.include? %Q("#{existing_metadata["e"]}") - server.headers["ETag"] = %Q("#{existing_metadata["e"]}") - server.headers["Last-Modified"] = Time.at(existing_metadata["m"].to_i / 1000).httpdate + metadata = redis.hgetall redis_metadata_object_key(user, directory, key) + if none_match.include? %Q("#{metadata["e"]}") + server.headers["ETag"] = %Q("#{metadata["e"]}") + server.headers["Last-Modified"] = Time.at(metadata["m"].to_i / 1000).httpdate server.halt 304 end diff --git a/spec/s3/app_spec.rb b/spec/s3/app_spec.rb index 8f818f1..6ab49ec 100644 --- a/spec/s3/app_spec.rb +++ b/spec/s3/app_spec.rb @@ -815,7 +815,7 @@ describe "App" do header "Authorization", "Bearer amarillo" put_stub = OpenStruct.new(headers: { - etag: "bla" + etag: "0815etag" }) RestClient.stub :put, put_stub do @@ -838,20 +838,45 @@ describe "App" do end describe "documents" do - it "returns a 404 when the document doesn't exist" do - raises_exception = ->(url, headers) { raise RestClient::ResourceNotFound.new } - RestClient.stub :head, raises_exception do + context "when the document doesn't exist" do + it "returns a 404" do head "/phil/food/steak" + + last_response.status.must_equal 404 + last_response.body.must_be_empty + end + end + + context "when the document exists" do + it "returns the required response headers" do + head "/phil/food/aguacate" + + last_response.status.must_equal 200 + last_response.headers["ETag"].must_equal "\"0815etag\"" + last_response.headers["Cache-Control"].must_equal "no-cache" end - last_response.status.must_equal 404 - last_response.body.must_be_empty + it "responds with 304 when IF_NONE_MATCH header contains the ETag" do + header "If-None-Match", "\"0815etag\"" + + head "/phil/food/aguacate" + + last_response.status.must_equal 304 + last_response.headers["ETag"].must_equal "\"0815etag\"" + last_response.headers["Last-Modified"].must_equal "Fri, 04 Mar 2016 12:20:18 GMT" + end + + it "responds with 304 when IF_NONE_MATCH header contains weak ETAG matching the current ETag" do + header "If-None-Match", "W/\"0815etag\"" + + head "/phil/food/aguacate" + + last_response.status.must_equal 304 + last_response.headers["ETag"].must_equal "\"0815etag\"" + last_response.headers["Last-Modified"].must_equal "Fri, 04 Mar 2016 12:20:18 GMT" + end end end - end - end - end - diff --git a/spec/swift/app_spec.rb b/spec/swift/app_spec.rb index c400af4..16311d9 100644 --- a/spec/swift/app_spec.rb +++ b/spec/swift/app_spec.rb @@ -773,7 +773,7 @@ describe "App" do header "Authorization", "Bearer amarillo" put_stub = OpenStruct.new(headers: { - etag: "bla", + etag: "0815etag", last_modified: "Fri, 04 Mar 2016 12:20:18 GMT" }) @@ -795,20 +795,46 @@ describe "App" do end describe "documents" do - it "returns a 404 when the document doesn't exist" do - raises_exception = ->(url, headers) { raise RestClient::ResourceNotFound.new } - RestClient.stub :head, raises_exception do + context "when the document doesn't exist" do + it "returns a 404" do head "/phil/food/steak" + + last_response.status.must_equal 404 + last_response.body.must_be_empty + end + end + + context "when the document exists" do + it "returns the required response headers" do + head "/phil/food/aguacate" + + last_response.status.must_equal 200 + last_response.headers["ETag"].must_equal "\"0815etag\"" + last_response.headers["Cache-Control"].must_equal "no-cache" end - last_response.status.must_equal 404 - last_response.body.must_be_empty + it "responds with 304 when IF_NONE_MATCH header contains the ETag" do + header "If-None-Match", "\"0815etag\"" + + head "/phil/food/aguacate" + + last_response.status.must_equal 304 + last_response.headers["ETag"].must_equal "\"0815etag\"" + last_response.headers["Last-Modified"].must_equal "Fri, 04 Mar 2016 12:20:18 GMT" + end + + it "responds with 304 when IF_NONE_MATCH header contains weak ETAG matching the current ETag" do + header "If-None-Match", "W/\"0815etag\"" + + head "/phil/food/aguacate" + + last_response.status.must_equal 304 + last_response.headers["ETag"].must_equal "\"0815etag\"" + last_response.headers["Last-Modified"].must_equal "Fri, 04 Mar 2016 12:20:18 GMT" + end end end - end - end - end