Merge pull request #64 from 5apps/fix_root_etag

Fix ETag generation for container's root
This commit is contained in:
Greg Karékinian 2015-06-30 15:13:17 +02:00
commit 267c8288ba

View File

@ -4,6 +4,7 @@ require "cgi"
require "active_support/core_ext/time/conversions" require "active_support/core_ext/time/conversions"
require "active_support/core_ext/numeric/time" require "active_support/core_ext/numeric/time"
require "redis" require "redis"
require 'digest/md5'
module RemoteStorage module RemoteStorage
class Swift class Swift
@ -57,37 +58,48 @@ module RemoteStorage
end end
def get_head_directory_listing(user, directory) def get_head_directory_listing(user, directory)
res = do_head_request("#{url_for_directory(user, directory)}/") is_root_listing = directory.empty?
if is_root_listing
# We need to calculate the etag ourselves
res = do_get_request("#{url_for_directory(user, directory)}/?format=json")
etag = etag_for(res.body)
else
res = do_head_request("#{url_for_directory(user, directory)}/")
etag = res.headers[:etag]
end
server.headers["Content-Type"] = "application/json" server.headers["Content-Type"] = "application/json"
server.headers["ETag"] = %Q("#{res.headers[:etag]}") server.headers["ETag"] = %Q("#{etag}")
rescue RestClient::ResourceNotFound rescue RestClient::ResourceNotFound
server.halt 404 server.halt 404
end end
def get_directory_listing(user, directory) def get_directory_listing(user, directory)
server.headers["Content-Type"] = "application/json"
do_head_request("#{url_for_directory(user, directory)}/") do |response|
if response.code == 404
return directory_listing([]).to_json
else
server.headers["ETag"] = %Q("#{response.headers[:etag]}")
none_match = (server.env["HTTP_IF_NONE_MATCH"] || "").split(",").map(&:strip)
server.halt 304 if none_match.include? %Q("#{response.headers[:etag]}")
end
end
is_root_listing = directory.empty? is_root_listing = directory.empty?
res = if is_root_listing server.headers["Content-Type"] = "application/json"
do_get_request("#{container_url_for(user)}/?format=json")
else
do_get_request("#{container_url_for(user)}/?format=json&path=#{escape(directory)}/")
end
if body = JSON.parse(res.body) etag, get_response = nil
listing = directory_listing(body, is_root_listing)
do_head_request("#{url_for_directory(user, directory)}/") do |response|
return directory_listing([]).to_json if response.code == 404
if is_root_listing
get_response = do_get_request("#{container_url_for(user)}/?format=json&path=")
etag = etag_for(get_response.body)
else
get_response = do_get_request("#{container_url_for(user)}/?format=json&path=#{escape(directory)}/")
etag = response.headers[:etag]
end
none_match = (server.env["HTTP_IF_NONE_MATCH"] || "").split(",").map(&:strip)
server.halt 304 if none_match.include? %Q("#{etag}")
end
server.headers["ETag"] = %Q("#{etag}")
if body = JSON.parse(get_response.body)
listing = directory_listing(body)
else else
puts "listing not JSON" puts "listing not JSON"
end end
@ -175,7 +187,7 @@ module RemoteStorage
permission permission
end end
def directory_listing(res_body, is_root_listing = false) def directory_listing(res_body)
listing = { listing = {
"@context" => "http://remotestorage.io/spec/folder-description", "@context" => "http://remotestorage.io/spec/folder-description",
"items" => {} "items" => {}
@ -183,14 +195,14 @@ module RemoteStorage
res_body.each do |entry| res_body.each do |entry|
name = entry["name"] name = entry["name"]
name.sub!("#{File.dirname(entry["name"])}/", '') unless is_root_listing name.sub!("#{File.dirname(entry["name"])}/", '')
if name[-1] == "/" if name[-1] == "/" # It's a directory
listing["items"].merge!({ listing["items"].merge!({
name => { name => {
"ETag" => entry["hash"], "ETag" => entry["hash"],
} }
}) })
else else # It's a file
listing["items"].merge!({ listing["items"].merge!({
name => { name => {
"ETag" => entry["hash"], "ETag" => entry["hash"],
@ -328,5 +340,15 @@ module RemoteStorage
def redis def redis
@redis ||= Redis.new(host: settings.redis["host"], port: settings.redis["port"]) @redis ||= Redis.new(host: settings.redis["host"], port: settings.redis["port"])
end end
def etag_for(body)
objects = JSON.parse(body)
if objects.empty?
Digest::MD5.hexdigest ''
else
Digest::MD5.hexdigest objects.map { |o| o["hash"] }.join
end
end
end end
end end