httparty 0.13.0 → 0.14.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.

Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +92 -0
  4. data/.rubocop_todo.yml +124 -0
  5. data/.simplecov +1 -0
  6. data/.travis.yml +4 -2
  7. data/CONTRIBUTING.md +23 -0
  8. data/Gemfile +8 -3
  9. data/Guardfile +3 -3
  10. data/History +106 -11
  11. data/README.md +19 -20
  12. data/Rakefile +5 -7
  13. data/bin/httparty +18 -14
  14. data/docs/README.md +100 -0
  15. data/examples/README.md +67 -0
  16. data/examples/aaws.rb +5 -5
  17. data/examples/basic.rb +6 -10
  18. data/examples/crack.rb +2 -2
  19. data/examples/custom_parsers.rb +1 -4
  20. data/examples/delicious.rb +8 -8
  21. data/examples/google.rb +2 -2
  22. data/examples/headers_and_user_agents.rb +1 -1
  23. data/examples/logging.rb +36 -0
  24. data/examples/nokogiri_html_parser.rb +0 -3
  25. data/examples/rescue_json.rb +17 -0
  26. data/examples/rubyurl.rb +3 -3
  27. data/examples/stackexchange.rb +24 -0
  28. data/examples/tripit_sign_in.rb +20 -9
  29. data/examples/twitter.rb +7 -7
  30. data/examples/whoismyrep.rb +1 -1
  31. data/features/command_line.feature +90 -2
  32. data/features/digest_authentication.feature +10 -0
  33. data/features/steps/env.rb +16 -11
  34. data/features/steps/httparty_response_steps.rb +18 -14
  35. data/features/steps/httparty_steps.rb +10 -2
  36. data/features/steps/mongrel_helper.rb +35 -2
  37. data/features/steps/remote_service_steps.rb +26 -8
  38. data/features/supports_read_timeout_option.feature +13 -0
  39. data/httparty.gemspec +6 -5
  40. data/lib/httparty/connection_adapter.rb +36 -13
  41. data/lib/httparty/cookie_hash.rb +3 -4
  42. data/lib/httparty/exceptions.rb +4 -1
  43. data/lib/httparty/hash_conversions.rb +17 -15
  44. data/lib/httparty/logger/{apache_logger.rb → apache_formatter.rb} +3 -3
  45. data/lib/httparty/logger/curl_formatter.rb +91 -0
  46. data/lib/httparty/logger/logger.rb +18 -10
  47. data/lib/httparty/module_inheritable_attributes.rb +1 -1
  48. data/lib/httparty/net_digest_auth.rb +69 -18
  49. data/lib/httparty/parser.rb +4 -2
  50. data/lib/httparty/request.rb +105 -48
  51. data/lib/httparty/response.rb +31 -6
  52. data/lib/httparty/version.rb +1 -1
  53. data/lib/httparty.rb +132 -72
  54. data/spec/httparty/connection_adapter_spec.rb +285 -88
  55. data/spec/httparty/cookie_hash_spec.rb +46 -29
  56. data/spec/httparty/exception_spec.rb +29 -7
  57. data/spec/httparty/hash_conversions_spec.rb +49 -0
  58. data/spec/httparty/logger/apache_formatter_spec.rb +41 -0
  59. data/spec/httparty/logger/curl_formatter_spec.rb +119 -0
  60. data/spec/httparty/logger/logger_spec.rb +23 -7
  61. data/spec/httparty/net_digest_auth_spec.rb +118 -30
  62. data/spec/httparty/parser_spec.rb +43 -35
  63. data/spec/httparty/request_spec.rb +734 -182
  64. data/spec/httparty/response_spec.rb +139 -69
  65. data/spec/httparty/ssl_spec.rb +22 -22
  66. data/spec/httparty_spec.rb +307 -199
  67. data/spec/spec_helper.rb +34 -12
  68. data/spec/support/ssl_test_helper.rb +6 -6
  69. data/spec/support/ssl_test_server.rb +21 -21
  70. data/spec/support/stub_response.rb +20 -14
  71. data/website/index.html +3 -3
  72. metadata +30 -33
  73. data/lib/httparty/core_extensions.rb +0 -32
  74. data/lib/httparty/logger/curl_logger.rb +0 -48
  75. data/spec/httparty/logger/apache_logger_spec.rb +0 -26
  76. data/spec/httparty/logger/curl_logger_spec.rb +0 -18
  77. data/spec/spec.opts +0 -2
@@ -10,7 +10,7 @@ module HTTParty
10
10
 
11
11
  duplicate.each_pair do |key, value|
12
12
  duplicate[key] = if value.is_a?(Hash)
13
- hash_deep_dup(value)
13
+ hash_deep_dup(value)
14
14
  elsif value.is_a?(Proc)
15
15
  duplicate[key] = value.dup
16
16
  else
@@ -4,10 +4,22 @@ require 'net/http'
4
4
  module Net
5
5
  module HTTPHeader
6
6
  def digest_auth(username, password, response)
7
- @header['Authorization'] = DigestAuthenticator.new(username, password,
8
- @method, @path, response).authorization_header
7
+ authenticator = DigestAuthenticator.new(
8
+ username,
9
+ password,
10
+ @method,
11
+ @path,
12
+ response
13
+ )
14
+
15
+ @header['Authorization'] = authenticator.authorization_header
16
+ @header['cookie'] = append_cookies(authenticator) if response['Set-Cookie']
9
17
  end
10
18
 
19
+ def append_cookies(authenticator)
20
+ cookies = @header['cookie'] ? @header['cookie'] : []
21
+ cookies.concat(authenticator.cookie_header)
22
+ end
11
23
 
12
24
  class DigestAuthenticator
13
25
  def initialize(username, password, method, path, response_header)
@@ -16,50 +28,76 @@ module Net
16
28
  @method = method
17
29
  @path = path
18
30
  @response = parse(response_header)
31
+ @cookies = parse_cookies(response_header)
19
32
  end
20
33
 
21
34
  def authorization_header
22
35
  @cnonce = md5(random)
23
36
  header = [
24
- %Q(Digest username="#{@username}"),
25
- %Q(realm="#{@response['realm']}"),
26
- %Q(nonce="#{@response['nonce']}"),
27
- %Q(uri="#{@path}"),
28
- %Q(response="#{request_digest}"),
37
+ %(Digest username="#{@username}"),
38
+ %(realm="#{@response['realm']}"),
39
+ %(nonce="#{@response['nonce']}"),
40
+ %(uri="#{@path}"),
41
+ %(response="#{request_digest}")
29
42
  ]
30
43
 
44
+ header << %(algorithm="#{@response['algorithm']}") if algorithm_present?
45
+
31
46
  if qop_present?
32
47
  fields = [
33
- %Q(cnonce="#{@cnonce}"),
34
- %Q(qop="#{@response['qop']}"),
35
- %Q(nc=00000001)
48
+ %(cnonce="#{@cnonce}"),
49
+ %(qop="#{@response['qop']}"),
50
+ "nc=00000001"
36
51
  ]
37
52
  fields.each { |field| header << field }
38
53
  end
39
54
 
40
- header << %Q(opaque="#{@response['opaque']}") if opaque_present?
55
+ header << %(opaque="#{@response['opaque']}") if opaque_present?
41
56
  header
42
57
  end
43
58
 
44
- private
59
+ def cookie_header
60
+ @cookies
61
+ end
62
+
63
+ private
45
64
 
46
65
  def parse(response_header)
47
- response_header['www-authenticate'] =~ /Digest (.*)/
66
+ header = response_header['www-authenticate']
67
+ .gsub(/qop=(auth(?:-int)?)/, 'qop="\\1"')
68
+
69
+ header =~ /Digest (.*)/
48
70
  params = {}
49
- $1.gsub(/(\w+)="(.*?)"/) { params[$1] = $2 }
71
+ if $1
72
+ non_quoted = $1.gsub(/(\w+)="(.*?)"/) { params[$1] = $2 }
73
+ non_quoted.gsub(/(\w+)=([^,]*)/) { params[$1] = $2 }
74
+ end
50
75
  params
51
76
  end
52
77
 
78
+ def parse_cookies(response_header)
79
+ return [] unless response_header['Set-Cookie']
80
+
81
+ cookies = response_header['Set-Cookie'].split('; ')
82
+
83
+ cookies.reduce([]) do |ret, cookie|
84
+ ret << cookie
85
+ ret
86
+ end
87
+
88
+ cookies
89
+ end
90
+
53
91
  def opaque_present?
54
- @response.has_key?('opaque') and not @response['opaque'].empty?
92
+ @response.key?('opaque') && !@response['opaque'].empty?
55
93
  end
56
94
 
57
95
  def qop_present?
58
- @response.has_key?('qop') and not @response['qop'].empty?
96
+ @response.key?('qop') && !@response['qop'].empty?
59
97
  end
60
98
 
61
99
  def random
62
- "%x" % (Time.now.to_i + rand(65535))
100
+ format "%x", (Time.now.to_i + rand(65535))
63
101
  end
64
102
 
65
103
  def request_digest
@@ -72,8 +110,21 @@ module Net
72
110
  Digest::MD5.hexdigest(str)
73
111
  end
74
112
 
113
+ def algorithm_present?
114
+ @response.key?('algorithm') && !@response['algorithm'].empty?
115
+ end
116
+
117
+ def use_md5_sess?
118
+ algorithm_present? && @response['algorithm'] == 'MD5-sess'
119
+ end
120
+
75
121
  def a1
76
- [@username, @response['realm'], @password].join(":")
122
+ a1_user_realm_pwd = [@username, @response['realm'], @password].join(':')
123
+ if use_md5_sess?
124
+ [ md5(a1_user_realm_pwd), @response['nonce'], @cnonce ].join(':')
125
+ else
126
+ a1_user_realm_pwd
127
+ end
77
128
  end
78
129
 
79
130
  def a2
@@ -98,7 +98,9 @@ module HTTParty
98
98
  # @return [Object] the parsed body
99
99
  # @return [nil] when the response body is nil, an empty string, spaces only or "null"
100
100
  def parse
101
- return nil if body.nil? || body.strip.empty? || body == "null"
101
+ return nil if body.nil?
102
+ return nil if body == "null"
103
+ return nil if body.valid_encoding? && body.strip.empty?
102
104
  if supports_format?
103
105
  parse_supported_format
104
106
  else
@@ -113,7 +115,7 @@ module HTTParty
113
115
  end
114
116
 
115
117
  def json
116
- JSON.load(body, nil)
118
+ JSON.parse(body, :quirks_mode => true, :allow_nan => true)
117
119
  end
118
120
 
119
121
  def csv
@@ -9,17 +9,18 @@ module HTTParty
9
9
  Net::HTTP::Head,
10
10
  Net::HTTP::Options,
11
11
  Net::HTTP::Move,
12
- Net::HTTP::Copy
12
+ Net::HTTP::Copy,
13
+ Net::HTTP::Mkcol,
13
14
  ]
14
15
 
15
- SupportedURISchemes = [URI::HTTP, URI::HTTPS, URI::Generic]
16
+ SupportedURISchemes = ['http', 'https', 'webcal', nil]
16
17
 
17
- NON_RAILS_QUERY_STRING_NORMALIZER = Proc.new do |query|
18
+ NON_RAILS_QUERY_STRING_NORMALIZER = proc do |query|
18
19
  Array(query).sort_by { |a| a[0].to_s }.map do |key, value|
19
20
  if value.nil?
20
21
  key.to_s
21
- elsif value.is_a?(Array)
22
- value.map {|v| "#{key}=#{URI.encode(v.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))}"}
22
+ elsif value.respond_to?(:to_ary)
23
+ value.to_ary.map {|v| "#{key}=#{ERB::Util.url_encode(v.to_s)}"}
23
24
  else
24
25
  HashConversions.to_params(key => value)
25
26
  end
@@ -29,21 +30,32 @@ module HTTParty
29
30
  attr_accessor :http_method, :options, :last_response, :redirect, :last_uri
30
31
  attr_reader :path
31
32
 
32
- def initialize(http_method, path, o={})
33
+ def initialize(http_method, path, o = {})
33
34
  self.http_method = http_method
34
- self.path = path
35
35
  self.options = {
36
- :limit => o.delete(:no_follow) ? 1 : 5,
37
- :assume_utf16_is_big_endian => true,
38
- :default_params => {},
39
- :follow_redirects => true,
40
- :parser => Parser,
41
- :connection_adapter => ConnectionAdapter
36
+ limit: o.delete(:no_follow) ? 1 : 5,
37
+ assume_utf16_is_big_endian: true,
38
+ default_params: {},
39
+ follow_redirects: true,
40
+ parser: Parser,
41
+ uri_adapter: URI,
42
+ connection_adapter: ConnectionAdapter
42
43
  }.merge(o)
44
+ self.path = path
45
+ set_basic_auth_from_uri
43
46
  end
44
47
 
45
48
  def path=(uri)
46
- @path = URI.parse(uri)
49
+ uri_adapter = options[:uri_adapter]
50
+
51
+ @path = if uri.is_a?(uri_adapter)
52
+ uri
53
+ elsif String.try_convert(uri)
54
+ uri_adapter.parse uri
55
+ else
56
+ raise ArgumentError,
57
+ "bad argument (expected #{uri_adapter} object or URI string)"
58
+ end
47
59
  end
48
60
 
49
61
  def request_uri(uri)
@@ -55,14 +67,21 @@ module HTTParty
55
67
  end
56
68
 
57
69
  def uri
58
- new_uri = path.relative? ? URI.parse("#{base_uri}#{path}") : path.clone
70
+ if redirect && path.relative? && path.path[0] != "/"
71
+ last_uri_host = @last_uri.path.gsub(/[^\/]+$/, "")
72
+
73
+ path.path = "/#{path.path}" if last_uri_host[-1] != "/"
74
+ path.path = last_uri_host + path.path
75
+ end
76
+
77
+ new_uri = path.relative? ? options[:uri_adapter].parse("#{base_uri}#{path}") : path.clone
59
78
 
60
79
  # avoid double query string on redirects [#12]
61
80
  unless redirect
62
81
  new_uri.query = query_string(new_uri)
63
82
  end
64
83
 
65
- unless SupportedURISchemes.include? new_uri.class
84
+ unless SupportedURISchemes.include? new_uri.scheme
66
85
  raise UnsupportedURIScheme, "'#{new_uri}' Must be HTTP, HTTPS or Generic"
67
86
  end
68
87
 
@@ -70,7 +89,13 @@ module HTTParty
70
89
  end
71
90
 
72
91
  def base_uri
73
- redirect ? "#{@last_uri.scheme}://#{@last_uri.host}" : options[:base_uri]
92
+ if redirect
93
+ base_uri = "#{@last_uri.scheme}://#{@last_uri.host}"
94
+ base_uri += ":#{@last_uri.port}" if @last_uri.port != 80
95
+ base_uri
96
+ else
97
+ options[:base_uri] && HTTParty.normalize_base_uri(options[:base_uri])
98
+ end
74
99
  end
75
100
 
76
101
  def format
@@ -95,7 +120,7 @@ module HTTParty
95
120
  chunks = []
96
121
 
97
122
  http_response.read_body do |fragment|
98
- chunks << fragment
123
+ chunks << fragment unless options[:stream_body]
99
124
  block.call(fragment)
100
125
  end
101
126
 
@@ -104,6 +129,7 @@ module HTTParty
104
129
  end
105
130
 
106
131
  handle_deflation unless http_method == Net::HTTP::Head
132
+ handle_host_redirection if response_redirects?
107
133
  handle_response(chunked_body, &block)
108
134
  end
109
135
 
@@ -118,11 +144,11 @@ module HTTParty
118
144
  end
119
145
 
120
146
  def body
121
- options[:body].is_a?(Hash) ? normalize_query(options[:body]) : options[:body]
147
+ options[:body].respond_to?(:to_hash) ? normalize_query(options[:body]) : options[:body]
122
148
  end
123
149
 
124
150
  def credentials
125
- options[:basic_auth] || options[:digest_auth]
151
+ (options[:basic_auth] || options[:digest_auth]).to_hash
126
152
  end
127
153
 
128
154
  def username
@@ -148,17 +174,18 @@ module HTTParty
148
174
  def setup_raw_request
149
175
  @raw_request = http_method.new(request_uri(uri))
150
176
  @raw_request.body = body if body
151
- @raw_request.initialize_http_header(options[:headers])
152
- @raw_request.basic_auth(username, password) if options[:basic_auth]
177
+ @raw_request.body_stream = options[:body_stream] if options[:body_stream]
178
+ @raw_request.initialize_http_header(options[:headers].to_hash) if options[:headers].respond_to?(:to_hash)
179
+ @raw_request.basic_auth(username, password) if options[:basic_auth] && send_authorization_header?
153
180
  setup_digest_auth if options[:digest_auth]
154
181
  end
155
182
 
156
183
  def setup_digest_auth
157
184
  auth_request = http_method.new(uri.request_uri)
158
- auth_request.initialize_http_header(options[:headers])
185
+ auth_request.initialize_http_header(options[:headers].to_hash) if options[:headers].respond_to?(:to_hash)
159
186
  res = http.request(auth_request)
160
187
 
161
- if res['www-authenticate'] != nil && res['www-authenticate'].length > 0
188
+ if !res['www-authenticate'].nil? && res['www-authenticate'].length > 0
162
189
  @raw_request.digest_auth(username, password, res)
163
190
  end
164
191
  end
@@ -167,8 +194,8 @@ module HTTParty
167
194
  query_string_parts = []
168
195
  query_string_parts << uri.query unless uri.query.nil?
169
196
 
170
- if options[:query].is_a?(Hash)
171
- query_string_parts << normalize_query(options[:default_params].merge(options[:query]))
197
+ if options[:query].respond_to?(:to_hash)
198
+ query_string_parts << normalize_query(options[:default_params].merge(options[:query].to_hash))
172
199
  else
173
200
  query_string_parts << normalize_query(options[:default_params]) unless options[:default_params].empty?
174
201
  query_string_parts << options[:query] unless options[:query].nil?
@@ -196,12 +223,10 @@ module HTTParty
196
223
  end
197
224
 
198
225
  def encode_with_ruby_encoding(body, charset)
199
- begin
200
- encoding = Encoding.find(charset)
201
- body.force_encoding(encoding)
202
- rescue
203
- body
204
- end
226
+ encoding = Encoding.find(charset)
227
+ body.force_encoding(encoding)
228
+ rescue
229
+ body
205
230
  end
206
231
 
207
232
  def assume_utf16_is_big_endian
@@ -222,7 +247,6 @@ module HTTParty
222
247
  else
223
248
  body.force_encoding("UTF-16LE")
224
249
  end
225
-
226
250
  end
227
251
 
228
252
  def _encode_body(body)
@@ -256,18 +280,29 @@ module HTTParty
256
280
  end
257
281
  self.path = last_response['location']
258
282
  self.redirect = true
259
- self.http_method = Net::HTTP::Get unless options[:maintain_method_across_redirects]
283
+ if last_response.class == Net::HTTPSeeOther
284
+ unless options[:maintain_method_across_redirects] && options[:resend_on_redirect]
285
+ self.http_method = Net::HTTP::Get
286
+ end
287
+ elsif last_response.code != '307' && last_response.code != '308'
288
+ unless options[:maintain_method_across_redirects]
289
+ self.http_method = Net::HTTP::Get
290
+ end
291
+ end
260
292
  capture_cookies(last_response)
261
293
  perform(&block)
262
294
  else
263
- body = body || last_response.body
295
+ body ||= last_response.body
264
296
  body = encode_body(body)
265
- Response.new(self, last_response, lambda { parse_response(body) }, :body => body)
297
+ Response.new(self, last_response, lambda { parse_response(body) }, body: body)
266
298
  end
267
299
  end
268
300
 
269
301
  # Inspired by Ruby 1.9
270
302
  def handle_deflation
303
+ return if response_redirects?
304
+ return if last_response.body.nil?
305
+
271
306
  case last_response["content-encoding"]
272
307
  when "gzip", "x-gzip"
273
308
  body_io = StringIO.new(last_response.body)
@@ -279,14 +314,29 @@ module HTTParty
279
314
  end
280
315
  end
281
316
 
317
+ def handle_host_redirection
318
+ check_duplicate_location_header
319
+ redirect_path = options[:uri_adapter].parse last_response['location']
320
+ return if redirect_path.relative? || path.host == redirect_path.host
321
+ @changed_hosts = true
322
+ end
323
+
324
+ def check_duplicate_location_header
325
+ location = last_response.get_fields('location')
326
+ if location.is_a?(Array) && location.count > 1
327
+ raise DuplicateLocationHeader.new(last_response)
328
+ end
329
+ end
330
+
331
+ def send_authorization_header?
332
+ !defined?(@changed_hosts)
333
+ end
334
+
282
335
  def response_redirects?
283
336
  case last_response
284
- when Net::HTTPMultipleChoice, # 300
285
- Net::HTTPMovedPermanently, # 301
286
- Net::HTTPFound, # 302
287
- Net::HTTPSeeOther, # 303
288
- Net::HTTPUseProxy, # 305
289
- Net::HTTPTemporaryRedirect
337
+ when Net::HTTPNotModified # 304
338
+ false
339
+ when Net::HTTPRedirection
290
340
  options[:follow_redirects] && last_response.key?('location')
291
341
  end
292
342
  end
@@ -297,8 +347,8 @@ module HTTParty
297
347
 
298
348
  def capture_cookies(response)
299
349
  return unless response['Set-Cookie']
300
- cookies_hash = HTTParty::CookieHash.new()
301
- cookies_hash.add_cookies(options[:headers]['Cookie']) if options[:headers] && options[:headers]['Cookie']
350
+ cookies_hash = HTTParty::CookieHash.new
351
+ cookies_hash.add_cookies(options[:headers].to_hash['Cookie']) if options[:headers] && options[:headers].to_hash['Cookie']
302
352
  response.get_fields('Set-Cookie').each { |cookie| cookies_hash.add_cookies(cookie) }
303
353
  options[:headers] ||= {}
304
354
  options[:headers]['Cookie'] = cookies_hash.to_cookie_string
@@ -316,15 +366,22 @@ module HTTParty
316
366
  def validate
317
367
  raise HTTParty::RedirectionTooDeep.new(last_response), 'HTTP redirects too deep' if options[:limit].to_i <= 0
318
368
  raise ArgumentError, 'only get, post, patch, put, delete, head, and options methods are supported' unless SupportedHTTPMethods.include?(http_method)
319
- raise ArgumentError, ':headers must be a hash' if options[:headers] && !options[:headers].is_a?(Hash)
369
+ raise ArgumentError, ':headers must be a hash' if options[:headers] && !options[:headers].respond_to?(:to_hash)
320
370
  raise ArgumentError, 'only one authentication method, :basic_auth or :digest_auth may be used at a time' if options[:basic_auth] && options[:digest_auth]
321
- raise ArgumentError, ':basic_auth must be a hash' if options[:basic_auth] && !options[:basic_auth].is_a?(Hash)
322
- raise ArgumentError, ':digest_auth must be a hash' if options[:digest_auth] && !options[:digest_auth].is_a?(Hash)
323
- raise ArgumentError, ':query must be hash if using HTTP Post' if post? && !options[:query].nil? && !options[:query].is_a?(Hash)
371
+ raise ArgumentError, ':basic_auth must be a hash' if options[:basic_auth] && !options[:basic_auth].respond_to?(:to_hash)
372
+ raise ArgumentError, ':digest_auth must be a hash' if options[:digest_auth] && !options[:digest_auth].respond_to?(:to_hash)
373
+ raise ArgumentError, ':query must be hash if using HTTP Post' if post? && !options[:query].nil? && !options[:query].respond_to?(:to_hash)
324
374
  end
325
375
 
326
376
  def post?
327
377
  Net::HTTP::Post == http_method
328
378
  end
379
+
380
+ def set_basic_auth_from_uri
381
+ if path.userinfo
382
+ username, password = path.userinfo.split(':')
383
+ options[:basic_auth] = {username: username, password: password}
384
+ end
385
+ end
329
386
  end
330
387
  end
@@ -1,12 +1,12 @@
1
1
  module HTTParty
2
- class Response < HTTParty::BasicObject #:nodoc:
2
+ class Response < BasicObject
3
3
  def self.underscore(string)
4
- string.gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').gsub(/([a-z])([A-Z])/,'\1_\2').downcase
4
+ string.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').gsub(/([a-z])([A-Z])/, '\1_\2').downcase
5
5
  end
6
6
 
7
7
  attr_reader :request, :response, :body, :headers
8
8
 
9
- def initialize(request, response, parsed_block, options={})
9
+ def initialize(request, response, parsed_block, options = {})
10
10
  @request = request
11
11
  @response = response
12
12
  @body = options[:body] || response.body
@@ -17,6 +17,8 @@ module HTTParty
17
17
  logger = ::HTTParty::Logger.build(request.options[:logger], request.options[:log_level], request.options[:log_format])
18
18
  logger.format(request, self)
19
19
  end
20
+
21
+ throw_exception
20
22
  end
21
23
 
22
24
  def parsed_response
@@ -27,20 +29,37 @@ module HTTParty
27
29
  Response
28
30
  end
29
31
 
32
+ def is_a?(klass)
33
+ self.class == klass || self.class < klass
34
+ end
35
+
36
+ alias_method :kind_of?, :is_a?
37
+
30
38
  def code
31
39
  response.code.to_i
32
40
  end
33
41
 
42
+ def tap
43
+ yield self
44
+ self
45
+ end
46
+
34
47
  def inspect
35
- inspect_id = "%x" % (object_id * 2)
48
+ inspect_id = ::Kernel::format "%x", (object_id * 2)
36
49
  %(#<#{self.class}:0x#{inspect_id} parsed_response=#{parsed_response.inspect}, @response=#{response.inspect}, @headers=#{headers.inspect}>)
37
50
  end
38
51
 
52
+ RESPOND_TO_METHODS = [:request, :response, :parsed_response, :body, :headers]
53
+
39
54
  CODES_TO_OBJ = ::Net::HTTPResponse::CODE_CLASS_TO_OBJ.merge ::Net::HTTPResponse::CODE_TO_OBJ
40
55
 
41
56
  CODES_TO_OBJ.each do |response_code, klass|
42
57
  name = klass.name.sub("Net::HTTP", '')
43
- define_method("#{underscore(name)}?") do
58
+ name = "#{underscore(name)}?".to_sym
59
+
60
+ RESPOND_TO_METHODS << name
61
+
62
+ define_method(name) do
44
63
  klass === response
45
64
  end
46
65
  end
@@ -51,7 +70,7 @@ module HTTParty
51
70
  end
52
71
 
53
72
  def respond_to?(name, include_all = false)
54
- return true if [:request, :response, :parsed_response, :body, :headers].include?(name)
73
+ return true if RESPOND_TO_METHODS.include?(name)
55
74
  parsed_response.respond_to?(name, include_all) || response.respond_to?(name, include_all)
56
75
  end
57
76
 
@@ -66,6 +85,12 @@ module HTTParty
66
85
  super
67
86
  end
68
87
  end
88
+
89
+ def throw_exception
90
+ if @request.options[:raise_on] && @request.options[:raise_on].include?(code)
91
+ ::Kernel.raise ::HTTParty::ResponseError.new(@response), "Code #{code} - #{body}"
92
+ end
93
+ end
69
94
  end
70
95
  end
71
96
 
@@ -1,3 +1,3 @@
1
1
  module HTTParty
2
- VERSION = "0.13.0"
2
+ VERSION = "0.14.0"
3
3
  end