Skip to content

Commit

Permalink
Add support for arrays in query strings
Browse files Browse the repository at this point in the history
  • Loading branch information
mloughran committed Nov 16, 2012
1 parent c58a5e1 commit 9e87b3d
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 1 deletion.
6 changes: 5 additions & 1 deletion lib/signature.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
require 'openssl'

require 'signature/query_encoder'

module Signature
class AuthenticationError < RuntimeError; end

Expand All @@ -18,6 +20,8 @@ def sign(request)
class Request
attr_accessor :path, :query_hash

include QueryEncoder

# http://www.w3.org/TR/NOTE-datetime
ISO8601 = "%Y-%m-%dT%H:%M:%SZ"

Expand Down Expand Up @@ -182,7 +186,7 @@ def parameter_string
# Exclude signature from signature generation!
hash.delete("auth_signature")

hash.keys.sort.map { |k| "#{k}=#{hash[k]}" }.join("&")
hash.sort.map { |k, v| QueryEncoder.encode_param(k, v) }.join('&')
end

def validate_version!
Expand Down
38 changes: 38 additions & 0 deletions lib/signature/query_encoder.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
module Signature
# Query string encoding extracted with thanks from em-http-request
module QueryEncoder
class << self
# URL encodes query parameters:
# single k=v, or a URL encoded array, if v is an array of values
def encode_param(k, v)
if v.is_a?(Array)
v.map { |e| escape(k) + "[]=" + escape(e) }.join("&")
else
escape(k) + "=" + escape(v)
end
end

private

def escape(s)
if defined?(EscapeUtils)
EscapeUtils.escape_url(s.to_s)
else
s.to_s.gsub(/([^a-zA-Z0-9_.-]+)/n) {
'%'+$1.unpack('H2'*bytesize($1)).join('%').upcase
}
end
end

if ''.respond_to?(:bytesize)
def bytesize(string)
string.bytesize
end
else
def bytesize(string)
string.size
end
end
end
end
end
7 changes: 7 additions & 0 deletions spec/signature_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,13 @@
@request.sign(@token)[:auth_signature].should == @signature
end

it "should generate correct string when query hash contains array" do
@request.query_hash = {
"things" => ["thing1", "thing2"]
}
@request.send(:string_to_sign).should == "POST\n/some/path\nthings[]=thing1&things[]=thing2"
end

it "should use the path to generate signature" do
@request.path = '/some/other/path'
@request.sign(@token)[:auth_signature].should_not == @signature
Expand Down

0 comments on commit 9e87b3d

Please sign in to comment.