diff --git a/lib/aws/s3/authentication.rb b/lib/aws/s3/authentication.rb index f17d879..ffa205e 100644 --- a/lib/aws/s3/authentication.rb +++ b/lib/aws/s3/authentication.rb @@ -58,6 +58,8 @@ module AWS @options = options end + private + def canonical_string options = {} options[:expires] = expires if expires? @@ -65,8 +67,6 @@ module AWS end memoized :canonical_string - private - def encoded_canonical digest = OpenSSL::Digest::Digest.new('sha1') b64_hmac = [OpenSSL::HMAC.digest(digest, secret_access_key, canonical_string)].pack("m").strip @@ -123,9 +123,7 @@ module AWS end def build - params = canonical_string.extract_significant_parameter(false) - params = '' != params ? "#{params}&" : '' - "#{params}AWSAccessKeyId=#{access_key_id}&Expires=#{expires}&Signature=#{encoded_canonical}" + "AWSAccessKeyId=#{access_key_id}&Expires=#{expires}&Signature=#{encoded_canonical}" end end @@ -153,22 +151,18 @@ module AWS response-content-type response-content-language response-expires response-cache-control response-content-disposition response-content-encoding) - end + end def query_parameters_for_signature(params) params.select {|k, v| query_parameters.include?(k)} end - def cgi_escape(value) - result = CGI::escape(value.to_s) - result = result.gsub('+', '%20').gsub('%7E', '~') - result + def escape(value) + CGI::escape(value.to_s).gsub('+', '%20').gsub('%7E', '~') end - def cgi_unescape(value) - result = value.to_s.gsub('%20', '+').gsub('~', '%7E') - result = CGI::unescape(result) - result + def unescape(value) + CGI::unescape(value.to_s.gsub('%20', '+').gsub('~', '%7E')) end end @@ -185,20 +179,6 @@ module AWS request['Host'] = DEFAULT_HOST build end - - def extract_significant_parameter(unescape = true) - # unescape is true when build-ing a CanonicalString and should be false otherwise - parts = [] - params = Rack::Utils.parse_nested_query(request.path.sub(/^[^?]*\?/, '')) - params = self.class.query_parameters_for_signature(params) - unless params.empty? - parts << params.sort_by{|p| p[0]}.collect{|p| - param = p[1] ? "#{p[0]}=#{p[1]}" : p[0] - unescape ? self.class.cgi_unescape(param) : param - }.join('&') - end - parts.count > 0 ? parts.join : nil - end private def build @@ -247,6 +227,20 @@ module AWS def path [only_path, extract_significant_parameter].compact.join('?') end + + def extract_significant_parameter + # unescape is true when build-ing a CanonicalString and should be false otherwise + parts = [] + params = Rack::Utils.parse_nested_query(request.path.sub(/^[^?]*\?/, '')) + params = self.class.query_parameters_for_signature(params) + unless params.empty? + parts << params.sort_by{|p| p[0]}.collect{|p| + param = p[1] ? "#{p[0]}=#{p[1]}" : p[0] + unescape ? self.class.cgi_unescape(param) : param + }.join('&') + end + parts.count > 0 ? parts.join : nil + end def only_path request.path[/^[^?]*/] diff --git a/lib/aws/s3/connection.rb b/lib/aws/s3/connection.rb index 0f2a12e..8659d37 100644 --- a/lib/aws/s3/connection.rb +++ b/lib/aws/s3/connection.rb @@ -63,8 +63,8 @@ module AWS path = self.class.prepare_path(path) request = request_method(:get).new(path, {}) query_string = query_string_authentication(request, options) - "#{protocol(options)}#{http.address}#{port_string}#{path[/^[^?]*/]}".tap do |url| - url << "?#{query_string}" if authenticate + "#{protocol(options)}#{http.address}#{port_string}#{path}".tap do |url| + (url << (path[/\?/] ? '&' : '?') << "#{query_string}") if authenticate end end