httparty 0.14.0 → 0.21.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.editorconfig +18 -0
- data/.github/workflows/ci.yml +26 -0
- data/.gitignore +3 -0
- data/.rubocop_todo.yml +1 -1
- data/{History → Changelog.md} +222 -63
- data/Gemfile +8 -1
- data/Guardfile +3 -2
- data/README.md +8 -8
- data/bin/httparty +3 -1
- data/docs/README.md +128 -37
- data/examples/README.md +34 -12
- data/examples/aaws.rb +7 -3
- data/examples/body_stream.rb +14 -0
- data/examples/crack.rb +1 -1
- data/examples/custom_parsers.rb +5 -1
- data/examples/delicious.rb +4 -4
- data/examples/headers_and_user_agents.rb +7 -3
- data/examples/idn.rb +10 -0
- data/examples/logging.rb +4 -4
- data/examples/microsoft_graph.rb +52 -0
- data/examples/multipart.rb +22 -0
- data/examples/peer_cert.rb +9 -0
- data/examples/stackexchange.rb +1 -1
- data/examples/stream_download.rb +26 -0
- data/examples/tripit_sign_in.rb +1 -1
- data/examples/twitter.rb +2 -2
- data/examples/whoismyrep.rb +1 -1
- data/httparty.gemspec +7 -4
- data/lib/httparty/connection_adapter.rb +73 -16
- data/lib/httparty/cookie_hash.rb +10 -8
- data/lib/httparty/decompressor.rb +102 -0
- data/lib/httparty/exceptions.rb +4 -1
- data/lib/httparty/hash_conversions.rb +30 -12
- data/lib/httparty/headers_processor.rb +32 -0
- data/lib/httparty/logger/apache_formatter.rb +31 -6
- data/lib/httparty/logger/curl_formatter.rb +9 -7
- data/lib/httparty/logger/logger.rb +5 -1
- data/lib/httparty/logger/logstash_formatter.rb +61 -0
- data/lib/httparty/module_inheritable_attributes.rb +6 -4
- data/lib/httparty/net_digest_auth.rb +19 -19
- data/lib/httparty/parser.rb +25 -14
- data/lib/httparty/request/body.rb +105 -0
- data/lib/httparty/request/multipart_boundary.rb +13 -0
- data/lib/httparty/request.rb +141 -110
- data/lib/httparty/response/headers.rb +23 -19
- data/lib/httparty/response.rb +81 -22
- data/lib/httparty/response_fragment.rb +21 -0
- data/lib/httparty/text_encoder.rb +72 -0
- data/lib/httparty/utils.rb +13 -0
- data/lib/httparty/version.rb +3 -1
- data/lib/httparty.rb +79 -31
- data/website/css/common.css +1 -1
- metadata +39 -106
- data/.simplecov +0 -1
- data/.travis.yml +0 -9
- data/features/basic_authentication.feature +0 -20
- data/features/command_line.feature +0 -95
- data/features/deals_with_http_error_codes.feature +0 -26
- data/features/digest_authentication.feature +0 -30
- data/features/handles_compressed_responses.feature +0 -27
- data/features/handles_multiple_formats.feature +0 -57
- data/features/steps/env.rb +0 -27
- data/features/steps/httparty_response_steps.rb +0 -56
- data/features/steps/httparty_steps.rb +0 -43
- data/features/steps/mongrel_helper.rb +0 -127
- data/features/steps/remote_service_steps.rb +0 -92
- data/features/supports_read_timeout_option.feature +0 -13
- data/features/supports_redirection.feature +0 -22
- data/features/supports_timeout_option.feature +0 -13
- data/spec/fixtures/delicious.xml +0 -23
- data/spec/fixtures/empty.xml +0 -0
- data/spec/fixtures/google.html +0 -3
- data/spec/fixtures/ssl/generate.sh +0 -29
- data/spec/fixtures/ssl/generated/1fe462c2.0 +0 -16
- data/spec/fixtures/ssl/generated/bogushost.crt +0 -13
- data/spec/fixtures/ssl/generated/ca.crt +0 -16
- data/spec/fixtures/ssl/generated/ca.key +0 -15
- data/spec/fixtures/ssl/generated/selfsigned.crt +0 -14
- data/spec/fixtures/ssl/generated/server.crt +0 -13
- data/spec/fixtures/ssl/generated/server.key +0 -15
- data/spec/fixtures/ssl/openssl-exts.cnf +0 -9
- data/spec/fixtures/twitter.csv +0 -2
- data/spec/fixtures/twitter.json +0 -1
- data/spec/fixtures/twitter.xml +0 -403
- data/spec/fixtures/undefined_method_add_node_for_nil.xml +0 -2
- data/spec/httparty/connection_adapter_spec.rb +0 -495
- data/spec/httparty/cookie_hash_spec.rb +0 -100
- data/spec/httparty/exception_spec.rb +0 -45
- data/spec/httparty/hash_conversions_spec.rb +0 -49
- data/spec/httparty/logger/apache_formatter_spec.rb +0 -41
- data/spec/httparty/logger/curl_formatter_spec.rb +0 -119
- data/spec/httparty/logger/logger_spec.rb +0 -38
- data/spec/httparty/net_digest_auth_spec.rb +0 -240
- data/spec/httparty/parser_spec.rb +0 -173
- data/spec/httparty/request_spec.rb +0 -1183
- data/spec/httparty/response_spec.rb +0 -291
- data/spec/httparty/ssl_spec.rb +0 -74
- data/spec/httparty_spec.rb +0 -872
- data/spec/spec_helper.rb +0 -59
- data/spec/support/ssl_test_helper.rb +0 -47
- data/spec/support/ssl_test_server.rb +0 -80
- data/spec/support/stub_response.rb +0 -49
data/lib/httparty/request.rb
CHANGED
@@ -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 = [
|
@@ -11,6 +15,8 @@ module HTTParty
|
|
11
15
|
Net::HTTP::Move,
|
12
16
|
Net::HTTP::Copy,
|
13
17
|
Net::HTTP::Mkcol,
|
18
|
+
Net::HTTP::Lock,
|
19
|
+
Net::HTTP::Unlock,
|
14
20
|
]
|
15
21
|
|
16
22
|
SupportedURISchemes = ['http', 'https', 'webcal', nil]
|
@@ -27,10 +33,35 @@ module HTTParty
|
|
27
33
|
end.flatten.join('&')
|
28
34
|
end
|
29
35
|
|
36
|
+
JSON_API_QUERY_STRING_NORMALIZER = proc do |query|
|
37
|
+
Array(query).sort_by { |a| a[0].to_s }.map do |key, value|
|
38
|
+
if value.nil?
|
39
|
+
key.to_s
|
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(',')}"
|
43
|
+
else
|
44
|
+
HashConversions.to_params(key => value)
|
45
|
+
end
|
46
|
+
end.flatten.join('&')
|
47
|
+
end
|
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
|
+
|
30
58
|
attr_accessor :http_method, :options, :last_response, :redirect, :last_uri
|
31
59
|
attr_reader :path
|
32
60
|
|
33
61
|
def initialize(http_method, path, o = {})
|
62
|
+
@changed_hosts = false
|
63
|
+
@credentials_sent = false
|
64
|
+
|
34
65
|
self.http_method = http_method
|
35
66
|
self.options = {
|
36
67
|
limit: o.delete(:no_follow) ? 1 : 5,
|
@@ -51,7 +82,7 @@ module HTTParty
|
|
51
82
|
@path = if uri.is_a?(uri_adapter)
|
52
83
|
uri
|
53
84
|
elsif String.try_convert(uri)
|
54
|
-
uri_adapter.parse
|
85
|
+
uri_adapter.parse(uri).normalize
|
55
86
|
else
|
56
87
|
raise ArgumentError,
|
57
88
|
"bad argument (expected #{uri_adapter} object or URI string)"
|
@@ -67,14 +98,20 @@ module HTTParty
|
|
67
98
|
end
|
68
99
|
|
69
100
|
def uri
|
70
|
-
if redirect && path.relative? && path.path[0] !=
|
71
|
-
last_uri_host = @last_uri.path.gsub(/[^\/]+$/,
|
101
|
+
if redirect && path.relative? && path.path[0] != '/'
|
102
|
+
last_uri_host = @last_uri.path.gsub(/[^\/]+$/, '')
|
72
103
|
|
73
|
-
path.path = "/#{path.path}" if last_uri_host[-1] !=
|
74
|
-
path.path = last_uri_host
|
104
|
+
path.path = "/#{path.path}" if last_uri_host[-1] != '/'
|
105
|
+
path.path = "#{last_uri_host}#{path.path}"
|
75
106
|
end
|
76
107
|
|
77
|
-
|
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
|
78
115
|
|
79
116
|
# avoid double query string on redirects [#12]
|
80
117
|
unless redirect
|
@@ -91,7 +128,7 @@ module HTTParty
|
|
91
128
|
def base_uri
|
92
129
|
if redirect
|
93
130
|
base_uri = "#{@last_uri.scheme}://#{@last_uri.host}"
|
94
|
-
base_uri
|
131
|
+
base_uri = "#{base_uri}:#{@last_uri.port}" if @last_uri.port != 80
|
95
132
|
base_uri
|
96
133
|
else
|
97
134
|
options[:base_uri] && HTTParty.normalize_base_uri(options[:base_uri])
|
@@ -114,39 +151,52 @@ module HTTParty
|
|
114
151
|
validate
|
115
152
|
setup_raw_request
|
116
153
|
chunked_body = nil
|
154
|
+
current_http = http
|
117
155
|
|
118
|
-
self.last_response =
|
156
|
+
self.last_response = current_http.request(@raw_request) do |http_response|
|
119
157
|
if block
|
120
158
|
chunks = []
|
121
159
|
|
122
160
|
http_response.read_body do |fragment|
|
123
|
-
|
124
|
-
|
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)
|
125
164
|
end
|
126
165
|
|
127
166
|
chunked_body = chunks.join
|
128
167
|
end
|
129
168
|
end
|
130
169
|
|
131
|
-
handle_deflation unless http_method == Net::HTTP::Head
|
132
170
|
handle_host_redirection if response_redirects?
|
133
|
-
|
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)
|
134
181
|
end
|
135
182
|
|
136
183
|
def raw_body
|
137
184
|
@raw_request.body
|
138
185
|
end
|
139
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
|
+
|
140
194
|
private
|
141
195
|
|
142
196
|
def http
|
143
197
|
connection_adapter.call(uri, options)
|
144
198
|
end
|
145
199
|
|
146
|
-
def body
|
147
|
-
options[:body].respond_to?(:to_hash) ? normalize_query(options[:body]) : options[:body]
|
148
|
-
end
|
149
|
-
|
150
200
|
def credentials
|
151
201
|
(options[:basic_auth] || options[:digest_auth]).to_hash
|
152
202
|
end
|
@@ -172,106 +222,78 @@ module HTTParty
|
|
172
222
|
end
|
173
223
|
|
174
224
|
def setup_raw_request
|
175
|
-
|
176
|
-
|
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?
|
180
|
-
setup_digest_auth if options[:digest_auth]
|
181
|
-
end
|
182
|
-
|
183
|
-
def setup_digest_auth
|
184
|
-
auth_request = http_method.new(uri.request_uri)
|
185
|
-
auth_request.initialize_http_header(options[:headers].to_hash) if options[:headers].respond_to?(:to_hash)
|
186
|
-
res = http.request(auth_request)
|
187
|
-
|
188
|
-
if !res['www-authenticate'].nil? && res['www-authenticate'].length > 0
|
189
|
-
@raw_request.digest_auth(username, password, res)
|
190
|
-
end
|
191
|
-
end
|
192
|
-
|
193
|
-
def query_string(uri)
|
194
|
-
query_string_parts = []
|
195
|
-
query_string_parts << uri.query unless uri.query.nil?
|
196
|
-
|
197
|
-
if options[:query].respond_to?(:to_hash)
|
198
|
-
query_string_parts << normalize_query(options[:default_params].merge(options[:query].to_hash))
|
225
|
+
if options[:headers].respond_to?(:to_hash)
|
226
|
+
headers_hash = options[:headers].to_hash
|
199
227
|
else
|
200
|
-
|
201
|
-
query_string_parts << options[:query] unless options[:query].nil?
|
228
|
+
headers_hash = nil
|
202
229
|
end
|
203
230
|
|
204
|
-
|
205
|
-
|
206
|
-
end
|
231
|
+
@raw_request = http_method.new(request_uri(uri), headers_hash)
|
232
|
+
@raw_request.body_stream = options[:body_stream] if options[:body_stream]
|
207
233
|
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
234
|
+
if options[:body]
|
235
|
+
body = Body.new(
|
236
|
+
options[:body],
|
237
|
+
query_string_normalizer: query_string_normalizer,
|
238
|
+
force_multipart: options[:multipart]
|
239
|
+
)
|
213
240
|
|
214
|
-
|
215
|
-
|
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
|
216
246
|
end
|
217
247
|
|
218
|
-
|
219
|
-
return $1.gsub(/\\(.)/, '\1')
|
220
|
-
end
|
248
|
+
@raw_request.instance_variable_set(:@decode_content, decompress_content?)
|
221
249
|
|
222
|
-
|
250
|
+
if options[:basic_auth] && send_authorization_header?
|
251
|
+
@raw_request.basic_auth(username, password)
|
252
|
+
@credentials_sent = true
|
253
|
+
end
|
254
|
+
setup_digest_auth if digest_auth? && response_unauthorized? && response_has_digest_auth_challenge?
|
223
255
|
end
|
224
256
|
|
225
|
-
def
|
226
|
-
|
227
|
-
body.force_encoding(encoding)
|
228
|
-
rescue
|
229
|
-
body
|
257
|
+
def digest_auth?
|
258
|
+
!!options[:digest_auth]
|
230
259
|
end
|
231
260
|
|
232
|
-
def
|
233
|
-
options[:
|
261
|
+
def decompress_content?
|
262
|
+
!options[:skip_decompression]
|
234
263
|
end
|
235
264
|
|
236
|
-
def
|
237
|
-
|
238
|
-
|
239
|
-
return body.force_encoding("UTF-16LE")
|
240
|
-
elsif body.getbyte(0) == 0xFE && body.getbyte(1) == 0xFF
|
241
|
-
return body.force_encoding("UTF-16BE")
|
242
|
-
end
|
243
|
-
end
|
265
|
+
def response_unauthorized?
|
266
|
+
!!last_response && last_response.code == '401'
|
267
|
+
end
|
244
268
|
|
245
|
-
|
246
|
-
|
247
|
-
else
|
248
|
-
body.force_encoding("UTF-16LE")
|
249
|
-
end
|
269
|
+
def response_has_digest_auth_challenge?
|
270
|
+
!last_response['www-authenticate'].nil? && last_response['www-authenticate'].length > 0
|
250
271
|
end
|
251
272
|
|
252
|
-
def
|
253
|
-
|
273
|
+
def setup_digest_auth
|
274
|
+
@raw_request.digest_auth(username, password, last_response)
|
275
|
+
end
|
254
276
|
|
255
|
-
|
256
|
-
|
257
|
-
|
277
|
+
def query_string(uri)
|
278
|
+
query_string_parts = []
|
279
|
+
query_string_parts << uri.query unless uri.query.nil?
|
258
280
|
|
259
|
-
if
|
260
|
-
|
281
|
+
if options[:query].respond_to?(:to_hash)
|
282
|
+
query_string_parts << normalize_query(options[:default_params].merge(options[:query].to_hash))
|
261
283
|
else
|
262
|
-
|
284
|
+
query_string_parts << normalize_query(options[:default_params]) unless options[:default_params].empty?
|
285
|
+
query_string_parts << options[:query] unless options[:query].nil?
|
263
286
|
end
|
287
|
+
|
288
|
+
query_string_parts.reject!(&:empty?) unless query_string_parts == ['']
|
289
|
+
query_string_parts.size > 0 ? query_string_parts.join('&') : nil
|
264
290
|
end
|
265
291
|
|
266
|
-
def
|
267
|
-
|
268
|
-
_encode_body(body)
|
269
|
-
else
|
270
|
-
body
|
271
|
-
end
|
292
|
+
def assume_utf16_is_big_endian
|
293
|
+
options[:assume_utf16_is_big_endian]
|
272
294
|
end
|
273
295
|
|
274
|
-
def handle_response(
|
296
|
+
def handle_response(raw_body, &block)
|
275
297
|
if response_redirects?
|
276
298
|
options[:limit] -= 1
|
277
299
|
if options[:logger]
|
@@ -292,31 +314,26 @@ module HTTParty
|
|
292
314
|
capture_cookies(last_response)
|
293
315
|
perform(&block)
|
294
316
|
else
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
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'])
|
300
323
|
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
324
|
+
if decompress_content?
|
325
|
+
last_response.delete('content-encoding')
|
326
|
+
raw_body = body
|
327
|
+
end
|
328
|
+
end
|
305
329
|
|
306
|
-
|
307
|
-
when "gzip", "x-gzip"
|
308
|
-
body_io = StringIO.new(last_response.body)
|
309
|
-
last_response.body.replace Zlib::GzipReader.new(body_io).read
|
310
|
-
last_response.delete('content-encoding')
|
311
|
-
when "deflate"
|
312
|
-
last_response.body.replace Zlib::Inflate.inflate(last_response.body)
|
313
|
-
last_response.delete('content-encoding')
|
330
|
+
Response.new(self, last_response, lambda { parse_response(body) }, body: raw_body)
|
314
331
|
end
|
315
332
|
end
|
316
333
|
|
317
334
|
def handle_host_redirection
|
318
335
|
check_duplicate_location_header
|
319
|
-
redirect_path = options[:uri_adapter].parse
|
336
|
+
redirect_path = options[:uri_adapter].parse(last_response['location']).normalize
|
320
337
|
return if redirect_path.relative? || path.host == redirect_path.host
|
321
338
|
@changed_hosts = true
|
322
339
|
end
|
@@ -329,7 +346,7 @@ module HTTParty
|
|
329
346
|
end
|
330
347
|
|
331
348
|
def send_authorization_header?
|
332
|
-
|
349
|
+
!@changed_hosts
|
333
350
|
end
|
334
351
|
|
335
352
|
def response_redirects?
|
@@ -350,6 +367,7 @@ module HTTParty
|
|
350
367
|
cookies_hash = HTTParty::CookieHash.new
|
351
368
|
cookies_hash.add_cookies(options[:headers].to_hash['Cookie']) if options[:headers] && options[:headers].to_hash['Cookie']
|
352
369
|
response.get_fields('Set-Cookie').each { |cookie| cookies_hash.add_cookies(cookie) }
|
370
|
+
|
353
371
|
options[:headers] ||= {}
|
354
372
|
options[:headers]['Cookie'] = cookies_hash.to_cookie_string
|
355
373
|
end
|
@@ -381,7 +399,20 @@ module HTTParty
|
|
381
399
|
if path.userinfo
|
382
400
|
username, password = path.userinfo.split(':')
|
383
401
|
options[:basic_auth] = {username: username, password: password}
|
402
|
+
@credentials_sent = true
|
384
403
|
end
|
385
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
|
386
417
|
end
|
387
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(
|
7
|
-
@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
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
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
|
data/lib/httparty/response.rb
CHANGED
@@ -1,9 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module HTTParty
|
2
|
-
class Response <
|
4
|
+
class Response < Object
|
3
5
|
def self.underscore(string)
|
4
6
|
string.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').gsub(/([a-z])([A-Z])/, '\1_\2').downcase
|
5
7
|
end
|
6
8
|
|
9
|
+
def self._load(data)
|
10
|
+
req, resp, parsed_resp, resp_body = Marshal.load(data)
|
11
|
+
|
12
|
+
new(req, resp, -> { parsed_resp }, body: resp_body)
|
13
|
+
end
|
14
|
+
|
7
15
|
attr_reader :request, :response, :body, :headers
|
8
16
|
|
9
17
|
def initialize(request, response, parsed_block, options = {})
|
@@ -14,7 +22,11 @@ module HTTParty
|
|
14
22
|
@headers = Headers.new(response.to_hash)
|
15
23
|
|
16
24
|
if request.options[:logger]
|
17
|
-
logger = ::HTTParty::Logger.build(
|
25
|
+
logger = ::HTTParty::Logger.build(
|
26
|
+
request.options[:logger],
|
27
|
+
request.options[:log_level],
|
28
|
+
request.options[:log_format]
|
29
|
+
)
|
18
30
|
logger.format(request, self)
|
19
31
|
end
|
20
32
|
|
@@ -25,53 +37,87 @@ module HTTParty
|
|
25
37
|
@parsed_response ||= @parsed_block.call
|
26
38
|
end
|
27
39
|
|
28
|
-
def class
|
29
|
-
Response
|
30
|
-
end
|
31
|
-
|
32
|
-
def is_a?(klass)
|
33
|
-
self.class == klass || self.class < klass
|
34
|
-
end
|
35
|
-
|
36
|
-
alias_method :kind_of?, :is_a?
|
37
|
-
|
38
40
|
def code
|
39
41
|
response.code.to_i
|
40
42
|
end
|
41
43
|
|
44
|
+
def http_version
|
45
|
+
response.http_version
|
46
|
+
end
|
47
|
+
|
42
48
|
def tap
|
43
49
|
yield self
|
44
50
|
self
|
45
51
|
end
|
46
52
|
|
47
53
|
def inspect
|
48
|
-
inspect_id = ::Kernel::format
|
54
|
+
inspect_id = ::Kernel::format '%x', (object_id * 2)
|
49
55
|
%(#<#{self.class}:0x#{inspect_id} parsed_response=#{parsed_response.inspect}, @response=#{response.inspect}, @headers=#{headers.inspect}>)
|
50
56
|
end
|
51
57
|
|
52
|
-
RESPOND_TO_METHODS = [:request, :response, :parsed_response, :body, :headers]
|
53
|
-
|
54
58
|
CODES_TO_OBJ = ::Net::HTTPResponse::CODE_CLASS_TO_OBJ.merge ::Net::HTTPResponse::CODE_TO_OBJ
|
55
59
|
|
56
60
|
CODES_TO_OBJ.each do |response_code, klass|
|
57
|
-
name = klass.name.sub(
|
61
|
+
name = klass.name.sub('Net::HTTP', '')
|
58
62
|
name = "#{underscore(name)}?".to_sym
|
59
63
|
|
60
|
-
RESPOND_TO_METHODS << name
|
61
|
-
|
62
64
|
define_method(name) do
|
63
65
|
klass === response
|
64
66
|
end
|
65
67
|
end
|
66
68
|
|
67
69
|
# Support old multiple_choice? method from pre 2.0.0 era.
|
68
|
-
if ::RUBY_VERSION >=
|
70
|
+
if ::RUBY_VERSION >= '2.0.0' && ::RUBY_PLATFORM != 'java'
|
69
71
|
alias_method :multiple_choice?, :multiple_choices?
|
70
72
|
end
|
71
73
|
|
72
|
-
|
73
|
-
|
74
|
-
|
74
|
+
# Support old status codes method from pre 2.6.0 era.
|
75
|
+
if ::RUBY_VERSION >= '2.6.0' && ::RUBY_PLATFORM != 'java'
|
76
|
+
alias_method :gateway_time_out?, :gateway_timeout?
|
77
|
+
alias_method :request_entity_too_large?, :payload_too_large?
|
78
|
+
alias_method :request_time_out?, :request_timeout?
|
79
|
+
alias_method :request_uri_too_long?, :uri_too_long?
|
80
|
+
alias_method :requested_range_not_satisfiable?, :range_not_satisfiable?
|
81
|
+
end
|
82
|
+
|
83
|
+
def nil?
|
84
|
+
warn_about_nil_deprecation
|
85
|
+
response.nil? || response.body.nil? || response.body.empty?
|
86
|
+
end
|
87
|
+
|
88
|
+
def to_s
|
89
|
+
if !response.nil? && !response.body.nil? && response.body.respond_to?(:to_s)
|
90
|
+
response.body.to_s
|
91
|
+
else
|
92
|
+
inspect
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def pretty_print(pp)
|
97
|
+
if !parsed_response.nil? && parsed_response.respond_to?(:pretty_print)
|
98
|
+
parsed_response.pretty_print(pp)
|
99
|
+
else
|
100
|
+
super
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def display(port=$>)
|
105
|
+
if !parsed_response.nil? && parsed_response.respond_to?(:display)
|
106
|
+
parsed_response.display(port)
|
107
|
+
elsif !response.nil? && !response.body.nil? && response.body.respond_to?(:display)
|
108
|
+
response.body.display(port)
|
109
|
+
else
|
110
|
+
port.write(inspect)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def respond_to_missing?(name, *args)
|
115
|
+
return true if super
|
116
|
+
parsed_response.respond_to?(name) || response.respond_to?(name)
|
117
|
+
end
|
118
|
+
|
119
|
+
def _dump(_level)
|
120
|
+
Marshal.dump([request, response, parsed_response, body])
|
75
121
|
end
|
76
122
|
|
77
123
|
protected
|
@@ -91,6 +137,19 @@ module HTTParty
|
|
91
137
|
::Kernel.raise ::HTTParty::ResponseError.new(@response), "Code #{code} - #{body}"
|
92
138
|
end
|
93
139
|
end
|
140
|
+
|
141
|
+
private
|
142
|
+
|
143
|
+
def warn_about_nil_deprecation
|
144
|
+
trace_line = caller.reject { |line| line.include?('httparty') }.first
|
145
|
+
warning = "[DEPRECATION] HTTParty will no longer override `response#nil?`. " \
|
146
|
+
"This functionality will be removed in future versions. " \
|
147
|
+
"Please, add explicit check `response.body.nil? || response.body.empty?`. " \
|
148
|
+
"For more info refer to: https://github.com/jnunemaker/httparty/issues/568\n" \
|
149
|
+
"#{trace_line}"
|
150
|
+
|
151
|
+
warn(warning)
|
152
|
+
end
|
94
153
|
end
|
95
154
|
end
|
96
155
|
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'delegate'
|
4
|
+
|
5
|
+
module HTTParty
|
6
|
+
# Allow access to http_response and code by delegation on fragment
|
7
|
+
class ResponseFragment < SimpleDelegator
|
8
|
+
attr_reader :http_response, :connection
|
9
|
+
|
10
|
+
def code
|
11
|
+
@http_response.code.to_i
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(fragment, http_response, connection)
|
15
|
+
@fragment = fragment
|
16
|
+
@http_response = http_response
|
17
|
+
@connection = connection
|
18
|
+
super fragment
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|