Handle out of sync metadata in Redis on PUTs

When the IF-MATCH comparison fails, we check the actual metadata on
the Swift server to be sure.
This commit is contained in:
Garret Alfert 2018-01-05 06:49:42 +01:00
parent 24ae9ad893
commit 18670021b1
2 changed files with 47 additions and 4 deletions

View File

@ -139,8 +139,18 @@ module RemoteStorage
url = url_for_key(user, directory, key)
if required_match = server.env["HTTP_IF_MATCH"]
unless required_match.gsub(/^"?W\//, "") == %Q("#{existing_metadata["e"]}")
server.halt 412, "Precondition Failed"
required_match = required_match.gsub(/^"?W\//, "")
unless required_match == %Q("#{existing_metadata["e"]}")
# get actual metadata and compare in case redis metadata became out of sync
head_res = do_head_request(url)
if required_match == %Q("#{head_res.headers[:etag]}")
# log previous size difference that was missed ealier because of redis failure
log_size_difference(user, existing_metadata["s"], head_res.headers[:content_length])
else
server.halt 412, "Precondition Failed"
end
end
end
if server.env["HTTP_IF_NONE_MATCH"] == "*"

View File

@ -284,11 +284,44 @@ describe "App" do
it "fails the request if the header does not match the current ETag" do
header "If-Match", "someotheretag"
put "/phil/food/aguacate", "aye"
head_stub = OpenStruct.new(headers: {
etag: "oldetag",
last_modified: "Fri, 04 Mar 2016 12:20:18 GMT",
content_type: "text/plain",
content_length: 23
})
RestClient.stub :head, head_stub do
put "/phil/food/aguacate", "aye"
end
last_response.status.must_equal 412
last_response.body.must_equal "Precondition Failed"
end
it "allows the request if redis metadata became out of sync" do
header "If-Match", "\"existingetag\""
head_stub = OpenStruct.new(headers: {
etag: "existingetag",
last_modified: "Fri, 04 Mar 2016 12:20:18 GMT",
content_type: "text/plain",
content_length: 23
})
put_stub = OpenStruct.new(headers: {
etag: "newetag",
last_modified: "Fri, 04 Mar 2016 12:20:18 GMT"
})
RestClient.stub :head, head_stub do
RestClient.stub :put, put_stub do
put "/phil/food/aguacate", "aye"
end
end
last_response.status.must_equal 200
end
end
describe "If-None-Match header set to '*'" do
@ -307,7 +340,7 @@ describe "App" do
last_response.status.must_equal 201
end
it "fails the request if the document already exsits" do
it "fails the request if the document already exists" do
put_stub = OpenStruct.new(headers: {
etag: "someetag",
last_modified: "Fri, 04 Mar 2016 12:20:18 GMT"