httparty 0.6.1 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of httparty might be problematic. Click here for more details.

@@ -11,6 +11,18 @@ module HTTParty
11
11
 
12
12
  SupportedURISchemes = [URI::HTTP, URI::HTTPS]
13
13
 
14
+ NON_RAILS_QUERY_STRING_NORMALIZER = Proc.new do |query|
15
+ query.map do |key, value|
16
+ if value.nil?
17
+ key
18
+ elsif value.is_a?(Array)
19
+ value.map {|v| "#{key}=#{URI.encode(v.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))}"}
20
+ else
21
+ {key => value}.to_params
22
+ end
23
+ end.flatten.sort.join('&')
24
+ end
25
+
14
26
  attr_accessor :http_method, :path, :options, :last_response, :redirect
15
27
 
16
28
  def initialize(http_method, path, o={})
@@ -19,6 +31,7 @@ module HTTParty
19
31
  self.options = {
20
32
  :limit => o.delete(:no_follow) ? 1 : 5,
21
33
  :default_params => {},
34
+ :follow_redirects => true,
22
35
  :parser => Parser
23
36
  }.merge(o)
24
37
  end
@@ -53,12 +66,34 @@ module HTTParty
53
66
  def perform
54
67
  validate
55
68
  setup_raw_request
56
- get_response
69
+ self.last_response = http.request(@raw_request)
70
+ handle_deflation
57
71
  handle_response
58
72
  end
59
73
 
60
74
  private
61
75
 
76
+ def attach_ssl_certificates(http)
77
+ if http.use_ssl?
78
+ # Client certificate authentication
79
+ if options[:pem]
80
+ http.cert = OpenSSL::X509::Certificate.new(options[:pem])
81
+ http.key = OpenSSL::PKey::RSA.new(options[:pem], options[:pem_password])
82
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
83
+ end
84
+
85
+ # SSL certificate authority file and/or directory
86
+ if options[:ssl_ca_file]
87
+ http.ca_file = options[:ssl_ca_file]
88
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
89
+ end
90
+ if options[:ssl_ca_path]
91
+ http.ca_path = options[:ssl_ca_path]
92
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
93
+ end
94
+ end
95
+ end
96
+
62
97
  def http
63
98
  http = Net::HTTP.new(uri.host, uri.port, options[:http_proxyaddr], options[:http_proxyport])
64
99
  http.use_ssl = ssl_implied?
@@ -68,13 +103,7 @@ module HTTParty
68
103
  http.read_timeout = options[:timeout]
69
104
  end
70
105
 
71
- if options[:pem] && http.use_ssl?
72
- http.cert = OpenSSL::X509::Certificate.new(options[:pem])
73
- http.key = OpenSSL::PKey::RSA.new(options[:pem])
74
- http.verify_mode = OpenSSL::SSL::VERIFY_PEER
75
- else
76
- http.verify_mode = OpenSSL::SSL::VERIFY_NONE
77
- end
106
+ attach_ssl_certificates(http)
78
107
 
79
108
  if options[:debug_output]
80
109
  http.set_debug_output(options[:debug_output])
@@ -88,7 +117,7 @@ module HTTParty
88
117
  end
89
118
 
90
119
  def body
91
- options[:body].is_a?(Hash) ? options[:body].to_params : options[:body]
120
+ options[:body].is_a?(Hash) ? normalize_query(options[:body]) : options[:body]
92
121
  end
93
122
 
94
123
  def credentials
@@ -103,6 +132,18 @@ module HTTParty
103
132
  credentials[:password]
104
133
  end
105
134
 
135
+ def normalize_query(query)
136
+ if query_string_normalizer
137
+ query_string_normalizer.call(query)
138
+ else
139
+ query.to_params
140
+ end
141
+ end
142
+
143
+ def query_string_normalizer
144
+ options[:query_string_normalizer]
145
+ end
146
+
106
147
  def setup_raw_request
107
148
  @raw_request = http_method.new(uri.request_uri)
108
149
  @raw_request.body = body if body
@@ -118,22 +159,14 @@ module HTTParty
118
159
  end
119
160
  end
120
161
 
121
- def perform_actual_request
122
- http.request(@raw_request)
123
- end
124
-
125
- def get_response
126
- self.last_response = perform_actual_request
127
- end
128
-
129
162
  def query_string(uri)
130
163
  query_string_parts = []
131
164
  query_string_parts << uri.query unless uri.query.nil?
132
165
 
133
166
  if options[:query].is_a?(Hash)
134
- query_string_parts << options[:default_params].merge(options[:query]).to_params
167
+ query_string_parts << normalize_query(options[:default_params].merge(options[:query]))
135
168
  else
136
- query_string_parts << options[:default_params].to_params unless options[:default_params].empty?
169
+ query_string_parts << normalize_query(options[:default_params]) unless options[:default_params].empty?
137
170
  query_string_parts << options[:query] unless options[:query].nil?
138
171
  end
139
172
 
@@ -142,26 +175,15 @@ module HTTParty
142
175
 
143
176
  # Raises exception Net::XXX (http error code) if an http error occured
144
177
  def handle_response
145
- handle_deflation
146
- case last_response
147
- when Net::HTTPMultipleChoice, # 300
148
- Net::HTTPMovedPermanently, # 301
149
- Net::HTTPFound, # 302
150
- Net::HTTPSeeOther, # 303
151
- Net::HTTPUseProxy, # 305
152
- Net::HTTPTemporaryRedirect
153
- if last_response.key?('location')
154
- options[:limit] -= 1
155
- self.path = last_response['location']
156
- self.redirect = true
157
- self.http_method = Net::HTTP::Get unless options[:maintain_method_across_redirects]
158
- capture_cookies(last_response)
159
- perform
160
- else
161
- last_response
162
- end
178
+ if response_redirects?
179
+ options[:limit] -= 1
180
+ self.path = last_response['location']
181
+ self.redirect = true
182
+ self.http_method = Net::HTTP::Get unless options[:maintain_method_across_redirects]
183
+ capture_cookies(last_response)
184
+ perform
163
185
  else
164
- Response.new(last_response, parse_response(last_response.body))
186
+ Response.new(self, last_response, parse_response(last_response.body))
165
187
  end
166
188
  end
167
189
 
@@ -176,6 +198,18 @@ module HTTParty
176
198
  end
177
199
  end
178
200
 
201
+ def response_redirects?
202
+ case last_response
203
+ when Net::HTTPMultipleChoice, # 300
204
+ Net::HTTPMovedPermanently, # 301
205
+ Net::HTTPFound, # 302
206
+ Net::HTTPSeeOther, # 303
207
+ Net::HTTPUseProxy, # 305
208
+ Net::HTTPTemporaryRedirect
209
+ options[:follow_redirects] && last_response.key?('location')
210
+ end
211
+ end
212
+
179
213
  def parse_response(body)
180
214
  parser.call(body, format)
181
215
  end
@@ -198,15 +232,15 @@ module HTTParty
198
232
  end
199
233
  end
200
234
 
201
- def validate
202
- raise HTTParty::RedirectionTooDeep.new(last_response), 'HTTP redirects too deep' if options[:limit].to_i <= 0
203
- raise ArgumentError, 'only get, post, put, delete, head, and options methods are supported' unless SupportedHTTPMethods.include?(http_method)
204
- raise ArgumentError, ':headers must be a hash' if options[:headers] && !options[:headers].is_a?(Hash)
205
- raise ArgumentError, 'only one authentication method, :basic_auth or :digest_auth may be used at a time' if options[:basic_auth] && options[:digest_auth]
206
- raise ArgumentError, ':basic_auth must be a hash' if options[:basic_auth] && !options[:basic_auth].is_a?(Hash)
207
- raise ArgumentError, ':digest_auth must be a hash' if options[:digest_auth] && !options[:digest_auth].is_a?(Hash)
208
- raise ArgumentError, ':query must be hash if using HTTP Post' if post? && !options[:query].nil? && !options[:query].is_a?(Hash)
209
- end
235
+ def validate
236
+ raise HTTParty::RedirectionTooDeep.new(last_response), 'HTTP redirects too deep' if options[:limit].to_i <= 0
237
+ raise ArgumentError, 'only get, post, put, delete, head, and options methods are supported' unless SupportedHTTPMethods.include?(http_method)
238
+ raise ArgumentError, ':headers must be a hash' if options[:headers] && !options[:headers].is_a?(Hash)
239
+ raise ArgumentError, 'only one authentication method, :basic_auth or :digest_auth may be used at a time' if options[:basic_auth] && options[:digest_auth]
240
+ raise ArgumentError, ':basic_auth must be a hash' if options[:basic_auth] && !options[:basic_auth].is_a?(Hash)
241
+ raise ArgumentError, ':digest_auth must be a hash' if options[:digest_auth] && !options[:digest_auth].is_a?(Hash)
242
+ raise ArgumentError, ':query must be hash if using HTTP Post' if post? && !options[:query].nil? && !options[:query].is_a?(Hash)
243
+ end
210
244
 
211
245
  def post?
212
246
  Net::HTTP::Post == http_method
@@ -28,9 +28,15 @@ module HTTParty
28
28
  end
29
29
  end
30
30
 
31
- attr_reader :response, :parsed_response, :body, :headers
32
31
 
33
- def initialize(response, parsed_response)
32
+ def self.underscore(string)
33
+ string.gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').gsub(/([a-z])([A-Z])/,'\1_\2').downcase
34
+ end
35
+
36
+ attr_reader :request, :response, :parsed_response, :body, :headers
37
+
38
+ def initialize(request, response, parsed_response)
39
+ @request = request
34
40
  @response = response
35
41
  @body = response.body
36
42
  @parsed_response = parsed_response
@@ -50,6 +56,17 @@ module HTTParty
50
56
  %(#<#{self.class}:0x#{inspect_id} @parsed_response=#{parsed_response.inspect}, @response=#{response.inspect}, @headers=#{headers.inspect}>)
51
57
  end
52
58
 
59
+ CODES_TO_OBJ = Net::HTTPResponse::CODE_CLASS_TO_OBJ.merge Net::HTTPResponse::CODE_TO_OBJ
60
+
61
+ CODES_TO_OBJ.each do |response_code, klass|
62
+ name = klass.name.sub("Net::HTTP", '')
63
+ define_method("#{underscore(name)}?") do
64
+ klass === response
65
+ end
66
+ end
67
+
68
+ protected
69
+
53
70
  def method_missing(name, *args, &block)
54
71
  if parsed_response.respond_to?(name)
55
72
  parsed_response.send(name, *args, &block)
@@ -0,0 +1,29 @@
1
+ #!/bin/sh
2
+ set -e
3
+
4
+ if [ -d "generated" ] ; then
5
+ echo >&2 "error: 'generated' directory already exists. Delete it first."
6
+ exit 1
7
+ fi
8
+
9
+ mkdir generated
10
+
11
+ # Generate the CA private key and certificate
12
+ openssl req -batch -subj '/CN=INSECURE Test Certificate Authority' -newkey rsa:1024 -new -x509 -days 999999 -keyout generated/ca.key -nodes -out generated/ca.crt
13
+
14
+ # Create symlinks for ssl_ca_path
15
+ c_rehash generated
16
+
17
+ # Generate the server private key and self-signed certificate
18
+ openssl req -batch -subj '/CN=localhost' -newkey rsa:1024 -new -x509 -days 999999 -keyout generated/server.key -nodes -out generated/selfsigned.crt
19
+
20
+ # Generate certificate signing request with bogus hostname
21
+ openssl req -batch -subj '/CN=bogo' -new -days 999999 -key generated/server.key -nodes -out generated/bogushost.csr
22
+
23
+ # Sign the certificate requests
24
+ openssl x509 -CA generated/ca.crt -CAkey generated/ca.key -set_serial 1 -in generated/selfsigned.crt -out generated/server.crt -clrext -extfile openssl-exts.cnf -extensions cert -days 999999
25
+ openssl x509 -req -CA generated/ca.crt -CAkey generated/ca.key -set_serial 1 -in generated/bogushost.csr -out generated/bogushost.crt -clrext -extfile openssl-exts.cnf -extensions cert -days 999999
26
+
27
+ # Remove certificate signing requests
28
+ rm -f generated/*.csr
29
+
@@ -0,0 +1,16 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIICbTCCAdagAwIBAgIJAIAeO9TXtJ45MA0GCSqGSIb3DQEBBQUAMC4xLDAqBgNV
3
+ BAMTI0lOU0VDVVJFIFRlc3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MCAXDTEwMTAy
4
+ MDEzNDYyM1oYDzQ3NDgwOTE1MTM0NjIzWjAuMSwwKgYDVQQDEyNJTlNFQ1VSRSBU
5
+ ZXN0IENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
6
+ gYkCgYEA3lkBcd352qiIIzqnyvvJj59cx1dnzMyjnuaK2cRH420rBfukLE2MbOVr
7
+ 9nYq/7CdjqXpE8uFAF+UTSIK6MWZ/bidkr2xd/et/Ce2pVIVxH+rt3pJz3wZhC3H
8
+ Yz+HU4CD2iI9wAzsb6mMV7md1fjlYfir4SBGGPTkcqUJUp2/tQMCAwEAAaOBkDCB
9
+ jTAdBgNVHQ4EFgQUy0Lz6RgmtpywlBOXdPABQArp358wXgYDVR0jBFcwVYAUy0Lz
10
+ 6RgmtpywlBOXdPABQArp35+hMqQwMC4xLDAqBgNVBAMTI0lOU0VDVVJFIFRlc3Qg
11
+ Q2VydGlmaWNhdGUgQXV0aG9yaXR5ggkAgB471Ne0njkwDAYDVR0TBAUwAwEB/zAN
12
+ BgkqhkiG9w0BAQUFAAOBgQCmi3JQm+EIWjkRlyz9sijkYS+Ps4opmd/weeaXwa4E
13
+ gVBWJGyiduB+kBnfv61+/tDjlrbjBDH5dP8suczHQL8gox4zGgjw64KH4o1ujZYR
14
+ cEPbhnUpwbXu7yItlajBZfpFefjF5P0Ao2iEzQldDy0D6nQ19h5QANvQxqweTPQp
15
+ pw==
16
+ -----END CERTIFICATE-----
@@ -0,0 +1,13 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIICBTCCAW6gAwIBAgIBATANBgkqhkiG9w0BAQUFADAuMSwwKgYDVQQDEyNJTlNF
3
+ Q1VSRSBUZXN0IENlcnRpZmljYXRlIEF1dGhvcml0eTAgFw0xMDEwMjAxMzQ2MjNa
4
+ GA80NzQ4MDkxNTEzNDYyM1owDzENMAsGA1UEAxMEYm9nbzCBnzANBgkqhkiG9w0B
5
+ AQEFAAOBjQAwgYkCgYEAr6b0ZBrRrVvPmPbQv36Jnj5jv00ZkhimXrmbv9Z1AdIZ
6
+ WSsBpMd8TP7exE5OR5/DaxKmiZqVskgRyRkLm52/Dkt7Ncrzr5I3unHnMqsAv/28
7
+ 5fGlYoRxnkCGMse/6NOFgCemRFw/bglxPNAGrFYKStameBRbCm0dCgtlvcwzdf8C
8
+ AwEAAaNQME4wDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUddLPFtGmb0aFWbTl2kAo
9
+ xD+fd6kwHwYDVR0jBBgwFoAUy0Lz6RgmtpywlBOXdPABQArp358wDQYJKoZIhvcN
10
+ AQEFBQADgYEAosqpPVsFu6cOIhGFT85Y1wwRUaihO0vWO7ghBU5ScuRU3tuvyJDZ
11
+ Z/HoAMXV6XZjVZzRosjtPjFbyWkZYjUqJJRMyEaRiGArWe6urKLzwnD6R9O3eNa5
12
+ 7bgFhzZ5WBldJmtq4A3oNqBuvgZkYM6NVKvS4UoakkTliHB21/mDOSY=
13
+ -----END CERTIFICATE-----
@@ -0,0 +1,16 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIICbTCCAdagAwIBAgIJAIAeO9TXtJ45MA0GCSqGSIb3DQEBBQUAMC4xLDAqBgNV
3
+ BAMTI0lOU0VDVVJFIFRlc3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MCAXDTEwMTAy
4
+ MDEzNDYyM1oYDzQ3NDgwOTE1MTM0NjIzWjAuMSwwKgYDVQQDEyNJTlNFQ1VSRSBU
5
+ ZXN0IENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
6
+ gYkCgYEA3lkBcd352qiIIzqnyvvJj59cx1dnzMyjnuaK2cRH420rBfukLE2MbOVr
7
+ 9nYq/7CdjqXpE8uFAF+UTSIK6MWZ/bidkr2xd/et/Ce2pVIVxH+rt3pJz3wZhC3H
8
+ Yz+HU4CD2iI9wAzsb6mMV7md1fjlYfir4SBGGPTkcqUJUp2/tQMCAwEAAaOBkDCB
9
+ jTAdBgNVHQ4EFgQUy0Lz6RgmtpywlBOXdPABQArp358wXgYDVR0jBFcwVYAUy0Lz
10
+ 6RgmtpywlBOXdPABQArp35+hMqQwMC4xLDAqBgNVBAMTI0lOU0VDVVJFIFRlc3Qg
11
+ Q2VydGlmaWNhdGUgQXV0aG9yaXR5ggkAgB471Ne0njkwDAYDVR0TBAUwAwEB/zAN
12
+ BgkqhkiG9w0BAQUFAAOBgQCmi3JQm+EIWjkRlyz9sijkYS+Ps4opmd/weeaXwa4E
13
+ gVBWJGyiduB+kBnfv61+/tDjlrbjBDH5dP8suczHQL8gox4zGgjw64KH4o1ujZYR
14
+ cEPbhnUpwbXu7yItlajBZfpFefjF5P0Ao2iEzQldDy0D6nQ19h5QANvQxqweTPQp
15
+ pw==
16
+ -----END CERTIFICATE-----
@@ -0,0 +1,15 @@
1
+ -----BEGIN RSA PRIVATE KEY-----
2
+ MIICXgIBAAKBgQDeWQFx3fnaqIgjOqfK+8mPn1zHV2fMzKOe5orZxEfjbSsF+6Qs
3
+ TYxs5Wv2dir/sJ2OpekTy4UAX5RNIgroxZn9uJ2SvbF39638J7alUhXEf6u3eknP
4
+ fBmELcdjP4dTgIPaIj3ADOxvqYxXuZ3V+OVh+KvhIEYY9ORypQlSnb+1AwIDAQAB
5
+ AoGBAL147VFCDlM1gGU865V+wIFCFQbNxedwjxGuda4io/v6oEoF6R3Tq5F0Y27v
6
+ va6Lq4fOe/LhYGI0EKU2GEPJd3F2wA21r+81InPKAkqYI5CDQtKDDNLviur8ZVKF
7
+ i3UzutjeYoCqmWeHaKPD6w5DtqeBieem7LTWRyXlFtHZV/nBAkEA8nsMOSd1+JTm
8
+ ZT4HDsEFQrN8mIFUUioFSHPut2CwzvTEW+hTkLQiog3bua4n7uQOFImR63X9qMsh
9
+ IjZRJQNmowJBAOq+mQdnRWYKl0SYb++Eb3uW6L4h1zsW375+caKo9omtpeqDW/y0
10
+ BWyY0q4DPkm3yU26Yr+b2JijISrml9/8PiECQQDHuXyG8y7jktn3GFE94NURbL+6
11
+ 6gPnLX9ufzdoSjc4MDowrbtvHEDOlHWgioeP6L6EQhA0DtrhlnbzNCRARX3bAkEA
12
+ jQOsF+dwqAjKr/lGnMKY2cxgyf64NZXbGKsKhmUrnK9E0SjR9G8MJx1yyffGzi/q
13
+ bJf/xAzRw3eTcBsPtwznIQJAHq5MOK7oaUuO+6cbsZYpOYOOkKIvDLiOtdSr7LTI
14
+ DziH/fpzB0VhCmFhhEQwHhlB4t3m66A9TelHmhrCDsIaLA==
15
+ -----END RSA PRIVATE KEY-----
@@ -0,0 +1,14 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIICHTCCAYagAwIBAgIJALT/G+ylQljIMA0GCSqGSIb3DQEBBQUAMBQxEjAQBgNV
3
+ BAMTCWxvY2FsaG9zdDAgFw0xMDEwMjAxMzQ2MjNaGA80NzQ4MDkxNTEzNDYyM1ow
4
+ FDESMBAGA1UEAxMJbG9jYWxob3N0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB
5
+ gQCvpvRkGtGtW8+Y9tC/fomePmO/TRmSGKZeuZu/1nUB0hlZKwGkx3xM/t7ETk5H
6
+ n8NrEqaJmpWySBHJGQubnb8OS3s1yvOvkje6cecyqwC//bzl8aVihHGeQIYyx7/o
7
+ 04WAJ6ZEXD9uCXE80AasVgpK1qZ4FFsKbR0KC2W9zDN1/wIDAQABo3UwczAdBgNV
8
+ HQ4EFgQUddLPFtGmb0aFWbTl2kAoxD+fd6kwRAYDVR0jBD0wO4AUddLPFtGmb0aF
9
+ WbTl2kAoxD+fd6mhGKQWMBQxEjAQBgNVBAMTCWxvY2FsaG9zdIIJALT/G+ylQljI
10
+ MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAlOCBO54S88mD3VYviER6
11
+ V+lkd7iWmdas2wUUDeMKA9CxnirWi7ne2U7wQH/5FJ1j3ImSfjb4h/98xiVJE84e
12
+ Ld7mb61g/M4g4b62kt0HK8/cGUxfuz5zwIfi28qJq3ow6AFEq1fywbJvUAnnamwU
13
+ cZF/qoVfJhus2mXjYc4hFWg=
14
+ -----END CERTIFICATE-----
@@ -0,0 +1,13 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIICCjCCAXOgAwIBAgIBATANBgkqhkiG9w0BAQUFADAuMSwwKgYDVQQDEyNJTlNF
3
+ Q1VSRSBUZXN0IENlcnRpZmljYXRlIEF1dGhvcml0eTAgFw0xMDEwMjAxMzQ2MjNa
4
+ GA80NzQ4MDkxNTEzNDYyM1owFDESMBAGA1UEAxMJbG9jYWxob3N0MIGfMA0GCSqG
5
+ SIb3DQEBAQUAA4GNADCBiQKBgQCvpvRkGtGtW8+Y9tC/fomePmO/TRmSGKZeuZu/
6
+ 1nUB0hlZKwGkx3xM/t7ETk5Hn8NrEqaJmpWySBHJGQubnb8OS3s1yvOvkje6cecy
7
+ qwC//bzl8aVihHGeQIYyx7/o04WAJ6ZEXD9uCXE80AasVgpK1qZ4FFsKbR0KC2W9
8
+ zDN1/wIDAQABo1AwTjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBR10s8W0aZvRoVZ
9
+ tOXaQCjEP593qTAfBgNVHSMEGDAWgBTLQvPpGCa2nLCUE5d08AFACunfnzANBgkq
10
+ hkiG9w0BAQUFAAOBgQCR4Oor0YAvK0tNFrOLtqmC6D0F5IYCyu7komk7JGn9L4nn
11
+ 7VyVxd4MXdc1r1v+WP5JtnA9ZjMmEmH9gl4gwR/Cu+TMkArsq0Z8mREOLNL8pwpx
12
+ Zxgk0CwacYR9RQcpuJ9nSDzVoO5ecYkb5C9q7gwgqbmCzr7oz/rwTqRwiUZCVQ==
13
+ -----END CERTIFICATE-----
@@ -0,0 +1,15 @@
1
+ -----BEGIN RSA PRIVATE KEY-----
2
+ MIICXQIBAAKBgQCvpvRkGtGtW8+Y9tC/fomePmO/TRmSGKZeuZu/1nUB0hlZKwGk
3
+ x3xM/t7ETk5Hn8NrEqaJmpWySBHJGQubnb8OS3s1yvOvkje6cecyqwC//bzl8aVi
4
+ hHGeQIYyx7/o04WAJ6ZEXD9uCXE80AasVgpK1qZ4FFsKbR0KC2W9zDN1/wIDAQAB
5
+ AoGALIdgkTgTS6VovVhklwcXEBy04LxE7Tp+gqj/COTvCKUgc/BpHELOCh7ajl1j
6
+ jti7i5tQyLV9mZKXn6lPvgWBd0w+p6VhM4NFA97CoodEJm2ckFC9zUABCh9dOpbm
7
+ 8KzF7hdpYWgJJchwwZ60tbcP7K1DkiNX6Kk9qKQEWvitMBECQQDpOSzzLldcEU9l
8
+ ze/nG2+rf6ecaPnKeafY8R2qVils8I7ZJAW3+0bNT5gQs7rT7aWo8vMvrXq++lWb
9
+ JkNV6hK9AkEAwM5wsmg7REmAaDwgUBq5mNt963/uG2ihAODFS70lYT23UYl5Y3rD
10
+ s3qU4ntG4DvWIQgPdwdstzDh9fMBVXa1awJBAID1WoOE5k1ETRDP1I2HwDGmPnng
11
+ Ge75YfQ1LuAXEITqZzJuFrNqv/Waw0zI9M9moqlO3WVJmYusRFWrzKPe8EkCQEwC
12
+ FlN+275z63csHOD3aCtmfCGW8VtEyBP8iErvagkHt3khZQVepD/hF0ihqLNFY4jq
13
+ EI6wEp+1WZ8ICYKTpbkCQQDhl5QLdy5Xo3k3agCnB9nktSzs2iqFvsGvfOAW4628
14
+ iThKTNua6bBvbdiG0Vh2Sv0XBYVJoHB3WnTVgFyPJaaF
15
+ -----END RSA PRIVATE KEY-----
@@ -0,0 +1,9 @@
1
+ [ca]
2
+ basicConstraints=critical,CA:true
3
+ subjectKeyIdentifier=hash
4
+ authorityKeyIdentifier=keyid:always,issuer:always
5
+
6
+ [cert]
7
+ basicConstraints=critical,CA:false
8
+ subjectKeyIdentifier=hash
9
+ authorityKeyIdentifier=keyid,issuer
@@ -1,7 +1,5 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
2
 
3
- class CustomParser < HTTParty::Parser; end
4
-
5
3
  describe HTTParty::Parser do
6
4
  describe ".SupportedFormats" do
7
5
  it "returns a hash" do
@@ -115,10 +113,13 @@ describe HTTParty::Parser do
115
113
  end
116
114
 
117
115
  it "raises a useful exception message for subclasses" do
118
- parser = CustomParser.new('body', :atom)
116
+ atom_parser = Class.new(HTTParty::Parser) do
117
+ def self.name; 'AtomParser'; end
118
+ end
119
+ parser = atom_parser.new 'body', :atom
119
120
  expect do
120
121
  parser.send(:parse_supported_format)
121
- end.to raise_error(NotImplementedError, "CustomParser has not implemented a parsing method for the :atom format.")
122
+ end.to raise_error(NotImplementedError, "AtomParser has not implemented a parsing method for the :atom format.")
122
123
  end
123
124
  end
124
125
  end
@@ -5,6 +5,28 @@ describe HTTParty::Request do
5
5
  @request = HTTParty::Request.new(Net::HTTP::Get, 'http://api.foo.com/v1', :format => :xml)
6
6
  end
7
7
 
8
+ describe "::NON_RAILS_QUERY_STRING_NORMALIZER" do
9
+ let(:normalizer) { HTTParty::Request::NON_RAILS_QUERY_STRING_NORMALIZER }
10
+
11
+ it "doesn't modify strings" do
12
+ query_string = normalizer["foo=bar&foo=baz"]
13
+ URI.unescape(query_string).should == "foo=bar&foo=baz"
14
+ end
15
+
16
+ context "when representing an array" do
17
+
18
+ it "doesn't include brackets" do
19
+ query_string = normalizer[{:page => 1, :foo => %w(bar baz)}]
20
+ URI.unescape(query_string).should == "foo=bar&foo=baz&page=1"
21
+ end
22
+
23
+ it "URI encodes array values" do
24
+ query_string = normalizer[{:people => ["Bob Marley", "Tim & Jon"]}]
25
+ query_string.should == "people=Bob%20Marley&people=Tim%20%26%20Jon"
26
+ end
27
+ end
28
+ end
29
+
8
30
  describe "initialization" do
9
31
  it "sets parser to HTTParty::Parser" do
10
32
  request = HTTParty::Request.new(Net::HTTP::Get, 'http://google.com')
@@ -74,6 +96,33 @@ describe HTTParty::Request do
74
96
  @request.options[:default_params] = {}
75
97
  @request.uri.query.should be_nil
76
98
  end
99
+
100
+ it "respects the query string normalization proc" do
101
+ empty_proc = lambda {|qs| ""}
102
+ @request.options[:query_string_normalizer] = empty_proc
103
+ @request.options[:query] = {:foo => :bar}
104
+ URI.unescape(@request.uri.query).should == ""
105
+ end
106
+
107
+ context "when representing an array" do
108
+ it "returns a Rails style query string" do
109
+ @request.options[:query] = {:foo => %w(bar baz)}
110
+ URI.unescape(@request.uri.query).should == "foo[]=bar&foo[]=baz"
111
+ end
112
+ end
113
+
114
+ end
115
+ end
116
+
117
+ describe "#setup_raw_request" do
118
+ context "when query_string_normalizer is set" do
119
+ it "sets the body to the return value of the proc" do
120
+ @request.options[:query_string_normalizer] = HTTParty::Request::NON_RAILS_QUERY_STRING_NORMALIZER
121
+ @request.options[:body] = {:page => 1, :foo => %w(bar baz)}
122
+ @request.send(:setup_raw_request)
123
+ body = @request.instance_variable_get(:@raw_request).body
124
+ URI.unescape(body).should == "foo=bar&foo=baz&page=1"
125
+ end
77
126
  end
78
127
  end
79
128
 
@@ -111,9 +160,10 @@ describe HTTParty::Request do
111
160
  @cert = mock("OpenSSL::X509::Certificate")
112
161
  @key = mock("OpenSSL::PKey::RSA")
113
162
  OpenSSL::X509::Certificate.should_receive(:new).with(pem).and_return(@cert)
114
- OpenSSL::PKey::RSA.should_receive(:new).with(pem).and_return(@key)
163
+ OpenSSL::PKey::RSA.should_receive(:new).with(pem, "password").and_return(@key)
115
164
 
116
165
  @request.options[:pem] = pem
166
+ @request.options[:pem_password] = "password"
117
167
  @pem_http = @request.send(:http)
118
168
  end
119
169
 
@@ -139,16 +189,6 @@ describe HTTParty::Request do
139
189
  request.options[:pem] = :pem_contents
140
190
  request.send(:http)
141
191
  end
142
-
143
- it "should not verify a certificate if scheme is not https" do
144
- http = Net::HTTP.new('google.com')
145
- Net::HTTP.stub(:new => http)
146
-
147
- request = HTTParty::Request.new(Net::HTTP::Get, 'http://google.com')
148
- request.options[:pem] = :pem_contents
149
- http = request.send(:http)
150
- http.verify_mode.should == OpenSSL::SSL::VERIFY_NONE
151
- end
152
192
  end
153
193
 
154
194
  context "debugging" do
@@ -282,9 +322,19 @@ describe HTTParty::Request do
282
322
  @request.perform.should == {"hash" => {"foo" => "bar"}}
283
323
  end
284
324
 
285
- it "returns the Net::HTTP response if the 300 does not contain a location header" do
325
+ it "redirects if a 300 contains a relative location header" do
326
+ redirect = stub_response '', 300
327
+ redirect['location'] = '/foo/bar'
328
+ ok = stub_response('<hash><foo>bar</foo></hash>', 200)
329
+ @http.stub!(:request).and_return(redirect, ok)
330
+ response = @request.perform
331
+ response.request.uri.request_uri.should == "/foo/bar"
332
+ response.should == {"hash" => {"foo" => "bar"}}
333
+ end
334
+
335
+ it "returns the HTTParty::Response when the 300 does not contain a location header" do
286
336
  net_response = stub_response '', 300
287
- @request.perform.should be_kind_of(Net::HTTPMultipleChoice)
337
+ HTTParty::Response.should === @request.perform
288
338
  end
289
339
  end
290
340