httparty 0.13.0 → 0.21.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (114) hide show
  1. checksums.yaml +5 -5
  2. data/.editorconfig +18 -0
  3. data/.github/workflows/ci.yml +26 -0
  4. data/.gitignore +4 -0
  5. data/.rubocop.yml +92 -0
  6. data/.rubocop_todo.yml +124 -0
  7. data/CONTRIBUTING.md +23 -0
  8. data/Changelog.md +557 -0
  9. data/Gemfile +15 -3
  10. data/Guardfile +4 -3
  11. data/README.md +24 -25
  12. data/Rakefile +5 -7
  13. data/bin/httparty +20 -14
  14. data/docs/README.md +191 -0
  15. data/examples/README.md +89 -0
  16. data/examples/aaws.rb +10 -6
  17. data/examples/basic.rb +6 -10
  18. data/examples/body_stream.rb +14 -0
  19. data/examples/crack.rb +2 -2
  20. data/examples/custom_parsers.rb +6 -5
  21. data/examples/delicious.rb +8 -8
  22. data/examples/google.rb +2 -2
  23. data/examples/headers_and_user_agents.rb +7 -3
  24. data/examples/idn.rb +10 -0
  25. data/examples/logging.rb +36 -0
  26. data/examples/microsoft_graph.rb +52 -0
  27. data/examples/multipart.rb +22 -0
  28. data/examples/nokogiri_html_parser.rb +0 -3
  29. data/examples/peer_cert.rb +9 -0
  30. data/examples/rescue_json.rb +17 -0
  31. data/examples/rubyurl.rb +3 -3
  32. data/examples/stackexchange.rb +24 -0
  33. data/examples/stream_download.rb +26 -0
  34. data/examples/tripit_sign_in.rb +20 -9
  35. data/examples/twitter.rb +7 -7
  36. data/examples/whoismyrep.rb +1 -1
  37. data/httparty.gemspec +13 -9
  38. data/lib/httparty/connection_adapter.rb +105 -25
  39. data/lib/httparty/cookie_hash.rb +10 -9
  40. data/lib/httparty/decompressor.rb +102 -0
  41. data/lib/httparty/exceptions.rb +8 -2
  42. data/lib/httparty/hash_conversions.rb +39 -19
  43. data/lib/httparty/headers_processor.rb +32 -0
  44. data/lib/httparty/logger/apache_formatter.rb +47 -0
  45. data/lib/httparty/logger/curl_formatter.rb +93 -0
  46. data/lib/httparty/logger/logger.rb +22 -10
  47. data/lib/httparty/logger/logstash_formatter.rb +61 -0
  48. data/lib/httparty/module_inheritable_attributes.rb +6 -4
  49. data/lib/httparty/net_digest_auth.rb +76 -25
  50. data/lib/httparty/parser.rb +28 -15
  51. data/lib/httparty/request/body.rb +105 -0
  52. data/lib/httparty/request/multipart_boundary.rb +13 -0
  53. data/lib/httparty/request.rb +218 -130
  54. data/lib/httparty/response/headers.rb +23 -19
  55. data/lib/httparty/response.rb +99 -15
  56. data/lib/httparty/response_fragment.rb +21 -0
  57. data/lib/httparty/text_encoder.rb +72 -0
  58. data/lib/httparty/utils.rb +13 -0
  59. data/lib/httparty/version.rb +3 -1
  60. data/lib/httparty.rb +191 -83
  61. data/website/css/common.css +1 -1
  62. data/website/index.html +3 -3
  63. metadata +50 -120
  64. data/.travis.yml +0 -7
  65. data/History +0 -303
  66. data/features/basic_authentication.feature +0 -20
  67. data/features/command_line.feature +0 -7
  68. data/features/deals_with_http_error_codes.feature +0 -26
  69. data/features/digest_authentication.feature +0 -20
  70. data/features/handles_compressed_responses.feature +0 -27
  71. data/features/handles_multiple_formats.feature +0 -57
  72. data/features/steps/env.rb +0 -22
  73. data/features/steps/httparty_response_steps.rb +0 -52
  74. data/features/steps/httparty_steps.rb +0 -35
  75. data/features/steps/mongrel_helper.rb +0 -94
  76. data/features/steps/remote_service_steps.rb +0 -74
  77. data/features/supports_redirection.feature +0 -22
  78. data/features/supports_timeout_option.feature +0 -13
  79. data/lib/httparty/core_extensions.rb +0 -32
  80. data/lib/httparty/logger/apache_logger.rb +0 -22
  81. data/lib/httparty/logger/curl_logger.rb +0 -48
  82. data/spec/fixtures/delicious.xml +0 -23
  83. data/spec/fixtures/empty.xml +0 -0
  84. data/spec/fixtures/google.html +0 -3
  85. data/spec/fixtures/ssl/generate.sh +0 -29
  86. data/spec/fixtures/ssl/generated/1fe462c2.0 +0 -16
  87. data/spec/fixtures/ssl/generated/bogushost.crt +0 -13
  88. data/spec/fixtures/ssl/generated/ca.crt +0 -16
  89. data/spec/fixtures/ssl/generated/ca.key +0 -15
  90. data/spec/fixtures/ssl/generated/selfsigned.crt +0 -14
  91. data/spec/fixtures/ssl/generated/server.crt +0 -13
  92. data/spec/fixtures/ssl/generated/server.key +0 -15
  93. data/spec/fixtures/ssl/openssl-exts.cnf +0 -9
  94. data/spec/fixtures/twitter.csv +0 -2
  95. data/spec/fixtures/twitter.json +0 -1
  96. data/spec/fixtures/twitter.xml +0 -403
  97. data/spec/fixtures/undefined_method_add_node_for_nil.xml +0 -2
  98. data/spec/httparty/connection_adapter_spec.rb +0 -298
  99. data/spec/httparty/cookie_hash_spec.rb +0 -83
  100. data/spec/httparty/exception_spec.rb +0 -23
  101. data/spec/httparty/logger/apache_logger_spec.rb +0 -26
  102. data/spec/httparty/logger/curl_logger_spec.rb +0 -18
  103. data/spec/httparty/logger/logger_spec.rb +0 -22
  104. data/spec/httparty/net_digest_auth_spec.rb +0 -152
  105. data/spec/httparty/parser_spec.rb +0 -165
  106. data/spec/httparty/request_spec.rb +0 -631
  107. data/spec/httparty/response_spec.rb +0 -221
  108. data/spec/httparty/ssl_spec.rb +0 -74
  109. data/spec/httparty_spec.rb +0 -764
  110. data/spec/spec.opts +0 -2
  111. data/spec/spec_helper.rb +0 -37
  112. data/spec/support/ssl_test_helper.rb +0 -47
  113. data/spec/support/ssl_test_server.rb +0 -80
  114. data/spec/support/stub_response.rb +0 -43
@@ -1,3 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'erb'
4
+
1
5
  module HTTParty
2
6
  class Request #:nodoc:
3
7
  SupportedHTTPMethods = [
@@ -9,41 +13,80 @@ module HTTParty
9
13
  Net::HTTP::Head,
10
14
  Net::HTTP::Options,
11
15
  Net::HTTP::Move,
12
- Net::HTTP::Copy
16
+ Net::HTTP::Copy,
17
+ Net::HTTP::Mkcol,
18
+ Net::HTTP::Lock,
19
+ Net::HTTP::Unlock,
13
20
  ]
14
21
 
15
- SupportedURISchemes = [URI::HTTP, URI::HTTPS, URI::Generic]
22
+ SupportedURISchemes = ['http', 'https', 'webcal', nil]
23
+
24
+ NON_RAILS_QUERY_STRING_NORMALIZER = proc do |query|
25
+ Array(query).sort_by { |a| a[0].to_s }.map do |key, value|
26
+ if value.nil?
27
+ key.to_s
28
+ elsif value.respond_to?(:to_ary)
29
+ value.to_ary.map {|v| "#{key}=#{ERB::Util.url_encode(v.to_s)}"}
30
+ else
31
+ HashConversions.to_params(key => value)
32
+ end
33
+ end.flatten.join('&')
34
+ end
16
35
 
17
- NON_RAILS_QUERY_STRING_NORMALIZER = Proc.new do |query|
36
+ JSON_API_QUERY_STRING_NORMALIZER = proc do |query|
18
37
  Array(query).sort_by { |a| a[0].to_s }.map do |key, value|
19
38
  if value.nil?
20
39
  key.to_s
21
- elsif value.is_a?(Array)
22
- value.map {|v| "#{key}=#{URI.encode(v.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))}"}
40
+ elsif value.respond_to?(:to_ary)
41
+ values = value.to_ary.map{|v| ERB::Util.url_encode(v.to_s)}
42
+ "#{key}=#{values.join(',')}"
23
43
  else
24
44
  HashConversions.to_params(key => value)
25
45
  end
26
46
  end.flatten.join('&')
27
47
  end
28
48
 
49
+ def self._load(data)
50
+ http_method, path, options, last_response, last_uri, raw_request = Marshal.load(data)
51
+ instance = new(http_method, path, options)
52
+ instance.last_response = last_response
53
+ instance.last_uri = last_uri
54
+ instance.instance_variable_set("@raw_request", raw_request)
55
+ instance
56
+ end
57
+
29
58
  attr_accessor :http_method, :options, :last_response, :redirect, :last_uri
30
59
  attr_reader :path
31
60
 
32
- def initialize(http_method, path, o={})
61
+ def initialize(http_method, path, o = {})
62
+ @changed_hosts = false
63
+ @credentials_sent = false
64
+
33
65
  self.http_method = http_method
34
- self.path = path
35
66
  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
67
+ limit: o.delete(:no_follow) ? 1 : 5,
68
+ assume_utf16_is_big_endian: true,
69
+ default_params: {},
70
+ follow_redirects: true,
71
+ parser: Parser,
72
+ uri_adapter: URI,
73
+ connection_adapter: ConnectionAdapter
42
74
  }.merge(o)
75
+ self.path = path
76
+ set_basic_auth_from_uri
43
77
  end
44
78
 
45
79
  def path=(uri)
46
- @path = URI.parse(uri)
80
+ uri_adapter = options[:uri_adapter]
81
+
82
+ @path = if uri.is_a?(uri_adapter)
83
+ uri
84
+ elsif String.try_convert(uri)
85
+ uri_adapter.parse(uri).normalize
86
+ else
87
+ raise ArgumentError,
88
+ "bad argument (expected #{uri_adapter} object or URI string)"
89
+ end
47
90
  end
48
91
 
49
92
  def request_uri(uri)
@@ -55,14 +98,27 @@ module HTTParty
55
98
  end
56
99
 
57
100
  def uri
58
- new_uri = path.relative? ? URI.parse("#{base_uri}#{path}") : path.clone
101
+ if redirect && path.relative? && path.path[0] != '/'
102
+ last_uri_host = @last_uri.path.gsub(/[^\/]+$/, '')
103
+
104
+ path.path = "/#{path.path}" if last_uri_host[-1] != '/'
105
+ path.path = "#{last_uri_host}#{path.path}"
106
+ end
107
+
108
+ if path.relative? && path.host
109
+ new_uri = options[:uri_adapter].parse("#{@last_uri.scheme}:#{path}").normalize
110
+ elsif path.relative?
111
+ new_uri = options[:uri_adapter].parse("#{base_uri}#{path}").normalize
112
+ else
113
+ new_uri = path.clone
114
+ end
59
115
 
60
116
  # avoid double query string on redirects [#12]
61
117
  unless redirect
62
118
  new_uri.query = query_string(new_uri)
63
119
  end
64
120
 
65
- unless SupportedURISchemes.include? new_uri.class
121
+ unless SupportedURISchemes.include? new_uri.scheme
66
122
  raise UnsupportedURIScheme, "'#{new_uri}' Must be HTTP, HTTPS or Generic"
67
123
  end
68
124
 
@@ -70,7 +126,13 @@ module HTTParty
70
126
  end
71
127
 
72
128
  def base_uri
73
- redirect ? "#{@last_uri.scheme}://#{@last_uri.host}" : options[:base_uri]
129
+ if redirect
130
+ base_uri = "#{@last_uri.scheme}://#{@last_uri.host}"
131
+ base_uri = "#{base_uri}:#{@last_uri.port}" if @last_uri.port != 80
132
+ base_uri
133
+ else
134
+ options[:base_uri] && HTTParty.normalize_base_uri(options[:base_uri])
135
+ end
74
136
  end
75
137
 
76
138
  def format
@@ -89,40 +151,54 @@ module HTTParty
89
151
  validate
90
152
  setup_raw_request
91
153
  chunked_body = nil
154
+ current_http = http
92
155
 
93
- self.last_response = http.request(@raw_request) do |http_response|
156
+ self.last_response = current_http.request(@raw_request) do |http_response|
94
157
  if block
95
158
  chunks = []
96
159
 
97
160
  http_response.read_body do |fragment|
98
- chunks << fragment
99
- block.call(fragment)
161
+ encoded_fragment = encode_text(fragment, http_response['content-type'])
162
+ chunks << encoded_fragment if !options[:stream_body]
163
+ block.call ResponseFragment.new(encoded_fragment, http_response, current_http)
100
164
  end
101
165
 
102
166
  chunked_body = chunks.join
103
167
  end
104
168
  end
105
169
 
106
- handle_deflation unless http_method == Net::HTTP::Head
107
- handle_response(chunked_body, &block)
170
+ handle_host_redirection if response_redirects?
171
+ result = handle_unauthorized
172
+ result ||= handle_response(chunked_body, &block)
173
+ result
174
+ end
175
+
176
+ def handle_unauthorized(&block)
177
+ return unless digest_auth? && response_unauthorized? && response_has_digest_auth_challenge?
178
+ return if @credentials_sent
179
+ @credentials_sent = true
180
+ perform(&block)
108
181
  end
109
182
 
110
183
  def raw_body
111
184
  @raw_request.body
112
185
  end
113
186
 
187
+ def _dump(_level)
188
+ opts = options.dup
189
+ opts.delete(:logger)
190
+ opts.delete(:parser) if opts[:parser] && opts[:parser].is_a?(Proc)
191
+ Marshal.dump([http_method, path, opts, last_response, @last_uri, @raw_request])
192
+ end
193
+
114
194
  private
115
195
 
116
196
  def http
117
197
  connection_adapter.call(uri, options)
118
198
  end
119
199
 
120
- def body
121
- options[:body].is_a?(Hash) ? normalize_query(options[:body]) : options[:body]
122
- end
123
-
124
200
  def credentials
125
- options[:basic_auth] || options[:digest_auth]
201
+ (options[:basic_auth] || options[:digest_auth]).to_hash
126
202
  end
127
203
 
128
204
  def username
@@ -146,108 +222,78 @@ module HTTParty
146
222
  end
147
223
 
148
224
  def setup_raw_request
149
- @raw_request = http_method.new(request_uri(uri))
150
- @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]
153
- setup_digest_auth if options[:digest_auth]
154
- end
155
-
156
- def setup_digest_auth
157
- auth_request = http_method.new(uri.request_uri)
158
- auth_request.initialize_http_header(options[:headers])
159
- res = http.request(auth_request)
160
-
161
- if res['www-authenticate'] != nil && res['www-authenticate'].length > 0
162
- @raw_request.digest_auth(username, password, res)
163
- end
164
- end
165
-
166
- def query_string(uri)
167
- query_string_parts = []
168
- query_string_parts << uri.query unless uri.query.nil?
169
-
170
- if options[:query].is_a?(Hash)
171
- query_string_parts << normalize_query(options[:default_params].merge(options[:query]))
225
+ if options[:headers].respond_to?(:to_hash)
226
+ headers_hash = options[:headers].to_hash
172
227
  else
173
- query_string_parts << normalize_query(options[:default_params]) unless options[:default_params].empty?
174
- query_string_parts << options[:query] unless options[:query].nil?
228
+ headers_hash = nil
175
229
  end
176
230
 
177
- query_string_parts.reject!(&:empty?) unless query_string_parts == [""]
178
- query_string_parts.size > 0 ? query_string_parts.join('&') : nil
179
- end
231
+ @raw_request = http_method.new(request_uri(uri), headers_hash)
232
+ @raw_request.body_stream = options[:body_stream] if options[:body_stream]
180
233
 
181
- def get_charset
182
- content_type = last_response["content-type"]
183
- if content_type.nil?
184
- return nil
185
- end
234
+ if options[:body]
235
+ body = Body.new(
236
+ options[:body],
237
+ query_string_normalizer: query_string_normalizer,
238
+ force_multipart: options[:multipart]
239
+ )
186
240
 
187
- if content_type =~ /;\s*charset\s*=\s*([^=,;"\s]+)/i
188
- return $1
189
- end
190
-
191
- if content_type =~ /;\s*charset\s*=\s*"((\\.|[^\\"])+)"/i
192
- return $1.gsub(/\\(.)/, '\1')
241
+ if body.multipart?
242
+ content_type = "multipart/form-data; boundary=#{body.boundary}"
243
+ @raw_request['Content-Type'] = content_type
244
+ end
245
+ @raw_request.body = body.call
193
246
  end
194
247
 
195
- nil
196
- end
248
+ @raw_request.instance_variable_set(:@decode_content, decompress_content?)
197
249
 
198
- def encode_with_ruby_encoding(body, charset)
199
- begin
200
- encoding = Encoding.find(charset)
201
- body.force_encoding(encoding)
202
- rescue
203
- body
250
+ if options[:basic_auth] && send_authorization_header?
251
+ @raw_request.basic_auth(username, password)
252
+ @credentials_sent = true
204
253
  end
254
+ setup_digest_auth if digest_auth? && response_unauthorized? && response_has_digest_auth_challenge?
205
255
  end
206
256
 
207
- def assume_utf16_is_big_endian
208
- options[:assume_utf16_is_big_endian]
257
+ def digest_auth?
258
+ !!options[:digest_auth]
209
259
  end
210
260
 
211
- def encode_utf_16(body)
212
- if body.bytesize >= 2
213
- if body.getbyte(0) == 0xFF && body.getbyte(1) == 0xFE
214
- return body.force_encoding("UTF-16LE")
215
- elsif body.getbyte(0) == 0xFE && body.getbyte(1) == 0xFF
216
- return body.force_encoding("UTF-16BE")
217
- end
218
- end
261
+ def decompress_content?
262
+ !options[:skip_decompression]
263
+ end
219
264
 
220
- if assume_utf16_is_big_endian
221
- body.force_encoding("UTF-16BE")
222
- else
223
- body.force_encoding("UTF-16LE")
224
- end
265
+ def response_unauthorized?
266
+ !!last_response && last_response.code == '401'
267
+ end
225
268
 
269
+ def response_has_digest_auth_challenge?
270
+ !last_response['www-authenticate'].nil? && last_response['www-authenticate'].length > 0
226
271
  end
227
272
 
228
- def _encode_body(body)
229
- charset = get_charset
273
+ def setup_digest_auth
274
+ @raw_request.digest_auth(username, password, last_response)
275
+ end
230
276
 
231
- if charset.nil?
232
- return body
233
- end
277
+ def query_string(uri)
278
+ query_string_parts = []
279
+ query_string_parts << uri.query unless uri.query.nil?
234
280
 
235
- if "utf-16".casecmp(charset) == 0
236
- encode_utf_16(body)
281
+ if options[:query].respond_to?(:to_hash)
282
+ query_string_parts << normalize_query(options[:default_params].merge(options[:query].to_hash))
237
283
  else
238
- encode_with_ruby_encoding(body, charset)
284
+ query_string_parts << normalize_query(options[:default_params]) unless options[:default_params].empty?
285
+ query_string_parts << options[:query] unless options[:query].nil?
239
286
  end
287
+
288
+ query_string_parts.reject!(&:empty?) unless query_string_parts == ['']
289
+ query_string_parts.size > 0 ? query_string_parts.join('&') : nil
240
290
  end
241
291
 
242
- def encode_body(body)
243
- if "".respond_to?(:encoding)
244
- _encode_body(body)
245
- else
246
- body
247
- end
292
+ def assume_utf16_is_big_endian
293
+ options[:assume_utf16_is_big_endian]
248
294
  end
249
295
 
250
- def handle_response(body, &block)
296
+ def handle_response(raw_body, &block)
251
297
  if response_redirects?
252
298
  options[:limit] -= 1
253
299
  if options[:logger]
@@ -256,37 +302,58 @@ module HTTParty
256
302
  end
257
303
  self.path = last_response['location']
258
304
  self.redirect = true
259
- self.http_method = Net::HTTP::Get unless options[:maintain_method_across_redirects]
305
+ if last_response.class == Net::HTTPSeeOther
306
+ unless options[:maintain_method_across_redirects] && options[:resend_on_redirect]
307
+ self.http_method = Net::HTTP::Get
308
+ end
309
+ elsif last_response.code != '307' && last_response.code != '308'
310
+ unless options[:maintain_method_across_redirects]
311
+ self.http_method = Net::HTTP::Get
312
+ end
313
+ end
260
314
  capture_cookies(last_response)
261
315
  perform(&block)
262
316
  else
263
- body = body || last_response.body
264
- body = encode_body(body)
265
- Response.new(self, last_response, lambda { parse_response(body) }, :body => body)
317
+ raw_body ||= last_response.body
318
+
319
+ body = decompress(raw_body, last_response['content-encoding']) unless raw_body.nil?
320
+
321
+ unless body.nil?
322
+ body = encode_text(body, last_response['content-type'])
323
+
324
+ if decompress_content?
325
+ last_response.delete('content-encoding')
326
+ raw_body = body
327
+ end
328
+ end
329
+
330
+ Response.new(self, last_response, lambda { parse_response(body) }, body: raw_body)
266
331
  end
267
332
  end
268
333
 
269
- # Inspired by Ruby 1.9
270
- def handle_deflation
271
- case last_response["content-encoding"]
272
- when "gzip", "x-gzip"
273
- body_io = StringIO.new(last_response.body)
274
- last_response.body.replace Zlib::GzipReader.new(body_io).read
275
- last_response.delete('content-encoding')
276
- when "deflate"
277
- last_response.body.replace Zlib::Inflate.inflate(last_response.body)
278
- last_response.delete('content-encoding')
334
+ def handle_host_redirection
335
+ check_duplicate_location_header
336
+ redirect_path = options[:uri_adapter].parse(last_response['location']).normalize
337
+ return if redirect_path.relative? || path.host == redirect_path.host
338
+ @changed_hosts = true
339
+ end
340
+
341
+ def check_duplicate_location_header
342
+ location = last_response.get_fields('location')
343
+ if location.is_a?(Array) && location.count > 1
344
+ raise DuplicateLocationHeader.new(last_response)
279
345
  end
280
346
  end
281
347
 
348
+ def send_authorization_header?
349
+ !@changed_hosts
350
+ end
351
+
282
352
  def response_redirects?
283
353
  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
354
+ when Net::HTTPNotModified # 304
355
+ false
356
+ when Net::HTTPRedirection
290
357
  options[:follow_redirects] && last_response.key?('location')
291
358
  end
292
359
  end
@@ -297,9 +364,10 @@ module HTTParty
297
364
 
298
365
  def capture_cookies(response)
299
366
  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']
367
+ cookies_hash = HTTParty::CookieHash.new
368
+ cookies_hash.add_cookies(options[:headers].to_hash['Cookie']) if options[:headers] && options[:headers].to_hash['Cookie']
302
369
  response.get_fields('Set-Cookie').each { |cookie| cookies_hash.add_cookies(cookie) }
370
+
303
371
  options[:headers] ||= {}
304
372
  options[:headers]['Cookie'] = cookies_hash.to_cookie_string
305
373
  end
@@ -316,15 +384,35 @@ module HTTParty
316
384
  def validate
317
385
  raise HTTParty::RedirectionTooDeep.new(last_response), 'HTTP redirects too deep' if options[:limit].to_i <= 0
318
386
  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)
387
+ raise ArgumentError, ':headers must be a hash' if options[:headers] && !options[:headers].respond_to?(:to_hash)
320
388
  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)
389
+ raise ArgumentError, ':basic_auth must be a hash' if options[:basic_auth] && !options[:basic_auth].respond_to?(:to_hash)
390
+ raise ArgumentError, ':digest_auth must be a hash' if options[:digest_auth] && !options[:digest_auth].respond_to?(:to_hash)
391
+ raise ArgumentError, ':query must be hash if using HTTP Post' if post? && !options[:query].nil? && !options[:query].respond_to?(:to_hash)
324
392
  end
325
393
 
326
394
  def post?
327
395
  Net::HTTP::Post == http_method
328
396
  end
397
+
398
+ def set_basic_auth_from_uri
399
+ if path.userinfo
400
+ username, password = path.userinfo.split(':')
401
+ options[:basic_auth] = {username: username, password: password}
402
+ @credentials_sent = true
403
+ end
404
+ end
405
+
406
+ def decompress(body, encoding)
407
+ Decompressor.new(body, encoding).decompress
408
+ end
409
+
410
+ def encode_text(text, content_type)
411
+ TextEncoder.new(
412
+ text,
413
+ content_type: content_type,
414
+ assume_utf16_is_big_endian: assume_utf16_is_big_endian
415
+ ).call
416
+ end
329
417
  end
330
418
  end
@@ -1,31 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'delegate'
4
+
1
5
  module HTTParty
2
6
  class Response #:nodoc:
3
- class Headers
7
+ class Headers < ::SimpleDelegator
4
8
  include ::Net::HTTPHeader
5
9
 
6
- def initialize(header = {})
7
- @header = header
10
+ def initialize(header_values = nil)
11
+ @header = {}
12
+ if header_values
13
+ header_values.each_pair do |k,v|
14
+ if v.is_a?(Array)
15
+ v.each do |sub_v|
16
+ add_field(k, sub_v)
17
+ end
18
+ else
19
+ add_field(k, v)
20
+ end
21
+ end
22
+ end
23
+ super(@header)
8
24
  end
9
25
 
10
26
  def ==(other)
11
- @header == other
12
- end
13
-
14
- def inspect
15
- @header.inspect
16
- end
17
-
18
- def method_missing(name, *args, &block)
19
- if @header.respond_to?(name)
20
- @header.send(name, *args, &block)
21
- else
22
- super
27
+ if other.is_a?(::Net::HTTPHeader)
28
+ @header == other.instance_variable_get(:@header)
29
+ elsif other.is_a?(Hash)
30
+ @header == other || @header == Headers.new(other).instance_variable_get(:@header)
23
31
  end
24
32
  end
25
-
26
- def respond_to?(method, include_all = false)
27
- super || @header.respond_to?(method, include_all)
28
- end
29
33
  end
30
34
  end
31
35
  end