httparty 0.13.7 → 0.20.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.
- checksums.yaml +5 -5
- data/.editorconfig +18 -0
- data/.github/workflows/ci.yml +23 -0
- data/.gitignore +2 -0
- data/.rubocop_todo.yml +1 -1
- data/{History → Changelog.md} +220 -59
- data/Gemfile +8 -3
- data/README.md +8 -7
- data/bin/httparty +3 -1
- data/docs/README.md +171 -0
- 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 +17 -6
- data/examples/twitter.rb +2 -2
- data/examples/whoismyrep.rb +1 -1
- data/httparty.gemspec +7 -5
- data/lib/httparty/connection_adapter.rb +86 -20
- data/lib/httparty/cookie_hash.rb +10 -8
- data/lib/httparty/decompressor.rb +92 -0
- data/lib/httparty/exceptions.rb +8 -2
- data/lib/httparty/hash_conversions.rb +30 -8
- data/lib/httparty/headers_processor.rb +32 -0
- data/lib/httparty/logger/apache_formatter.rb +31 -6
- data/lib/httparty/logger/curl_formatter.rb +68 -23
- 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 +23 -21
- data/lib/httparty/parser.rb +25 -14
- data/lib/httparty/request/body.rb +98 -0
- data/lib/httparty/request/multipart_boundary.rb +13 -0
- data/lib/httparty/request.rb +156 -106
- data/lib/httparty/response/headers.rb +23 -19
- data/lib/httparty/response.rb +92 -13
- 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 +98 -34
- data/website/css/common.css +1 -1
- metadata +34 -113
- data/.travis.yml +0 -7
- 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 -52
- data/features/steps/httparty_steps.rb +0 -43
- data/features/steps/mongrel_helper.rb +0 -127
- data/features/steps/remote_service_steps.rb +0 -90
- 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 -468
- data/spec/httparty/cookie_hash_spec.rb +0 -83
- data/spec/httparty/exception_spec.rb +0 -38
- data/spec/httparty/hash_conversions_spec.rb +0 -41
- data/spec/httparty/logger/apache_formatter_spec.rb +0 -41
- data/spec/httparty/logger/curl_formatter_spec.rb +0 -18
- data/spec/httparty/logger/logger_spec.rb +0 -38
- data/spec/httparty/net_digest_auth_spec.rb +0 -230
- data/spec/httparty/parser_spec.rb +0 -173
- data/spec/httparty/request_spec.rb +0 -1073
- data/spec/httparty/response_spec.rb +0 -241
- data/spec/httparty/ssl_spec.rb +0 -74
- data/spec/httparty_spec.rb +0 -850
- 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 = [
|
@@ -9,7 +13,10 @@ 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
22
|
SupportedURISchemes = ['http', 'https', 'webcal', nil]
|
@@ -26,10 +33,31 @@ module HTTParty
|
|
26
33
|
end.flatten.join('&')
|
27
34
|
end
|
28
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 = Marshal.load(data)
|
51
|
+
new(http_method, path, options)
|
52
|
+
end
|
53
|
+
|
29
54
|
attr_accessor :http_method, :options, :last_response, :redirect, :last_uri
|
30
55
|
attr_reader :path
|
31
56
|
|
32
57
|
def initialize(http_method, path, o = {})
|
58
|
+
@changed_hosts = false
|
59
|
+
@credentials_sent = false
|
60
|
+
|
33
61
|
self.http_method = http_method
|
34
62
|
self.options = {
|
35
63
|
limit: o.delete(:no_follow) ? 1 : 5,
|
@@ -50,7 +78,7 @@ module HTTParty
|
|
50
78
|
@path = if uri.is_a?(uri_adapter)
|
51
79
|
uri
|
52
80
|
elsif String.try_convert(uri)
|
53
|
-
uri_adapter.parse
|
81
|
+
uri_adapter.parse(uri).normalize
|
54
82
|
else
|
55
83
|
raise ArgumentError,
|
56
84
|
"bad argument (expected #{uri_adapter} object or URI string)"
|
@@ -66,14 +94,20 @@ module HTTParty
|
|
66
94
|
end
|
67
95
|
|
68
96
|
def uri
|
69
|
-
if redirect && path.relative? && path.path[0] !=
|
70
|
-
last_uri_host = @last_uri.path.gsub(/[^\/]+$/,
|
97
|
+
if redirect && path.relative? && path.path[0] != '/'
|
98
|
+
last_uri_host = @last_uri.path.gsub(/[^\/]+$/, '')
|
71
99
|
|
72
|
-
path.path = "/#{path.path}" if last_uri_host[-1] !=
|
73
|
-
path.path = last_uri_host
|
100
|
+
path.path = "/#{path.path}" if last_uri_host[-1] != '/'
|
101
|
+
path.path = "#{last_uri_host}#{path.path}"
|
74
102
|
end
|
75
103
|
|
76
|
-
|
104
|
+
if path.relative? && path.host
|
105
|
+
new_uri = options[:uri_adapter].parse("#{@last_uri.scheme}:#{path}").normalize
|
106
|
+
elsif path.relative?
|
107
|
+
new_uri = options[:uri_adapter].parse("#{base_uri}#{path}").normalize
|
108
|
+
else
|
109
|
+
new_uri = path.clone
|
110
|
+
end
|
77
111
|
|
78
112
|
# avoid double query string on redirects [#12]
|
79
113
|
unless redirect
|
@@ -90,10 +124,10 @@ module HTTParty
|
|
90
124
|
def base_uri
|
91
125
|
if redirect
|
92
126
|
base_uri = "#{@last_uri.scheme}://#{@last_uri.host}"
|
93
|
-
base_uri
|
127
|
+
base_uri = "#{base_uri}:#{@last_uri.port}" if @last_uri.port != 80
|
94
128
|
base_uri
|
95
129
|
else
|
96
|
-
options[:base_uri]
|
130
|
+
options[:base_uri] && HTTParty.normalize_base_uri(options[:base_uri])
|
97
131
|
end
|
98
132
|
end
|
99
133
|
|
@@ -113,38 +147,52 @@ module HTTParty
|
|
113
147
|
validate
|
114
148
|
setup_raw_request
|
115
149
|
chunked_body = nil
|
150
|
+
current_http = http
|
116
151
|
|
117
|
-
self.last_response =
|
152
|
+
self.last_response = current_http.request(@raw_request) do |http_response|
|
118
153
|
if block
|
119
154
|
chunks = []
|
120
155
|
|
121
156
|
http_response.read_body do |fragment|
|
122
|
-
|
123
|
-
|
157
|
+
encoded_fragment = encode_text(fragment, http_response['content-type'])
|
158
|
+
chunks << encoded_fragment if !options[:stream_body]
|
159
|
+
block.call ResponseFragment.new(encoded_fragment, http_response, current_http)
|
124
160
|
end
|
125
161
|
|
126
162
|
chunked_body = chunks.join
|
127
163
|
end
|
128
164
|
end
|
129
165
|
|
130
|
-
|
131
|
-
|
166
|
+
handle_host_redirection if response_redirects?
|
167
|
+
result = handle_unauthorized
|
168
|
+
result ||= handle_response(chunked_body, &block)
|
169
|
+
result
|
170
|
+
end
|
171
|
+
|
172
|
+
def handle_unauthorized(&block)
|
173
|
+
return unless digest_auth? && response_unauthorized? && response_has_digest_auth_challenge?
|
174
|
+
return if @credentials_sent
|
175
|
+
@credentials_sent = true
|
176
|
+
perform(&block)
|
132
177
|
end
|
133
178
|
|
134
179
|
def raw_body
|
135
180
|
@raw_request.body
|
136
181
|
end
|
137
182
|
|
183
|
+
def _dump(_level)
|
184
|
+
opts = options.dup
|
185
|
+
opts.delete(:logger)
|
186
|
+
opts.delete(:parser) if opts[:parser] && opts[:parser].is_a?(Proc)
|
187
|
+
Marshal.dump([http_method, path, opts])
|
188
|
+
end
|
189
|
+
|
138
190
|
private
|
139
191
|
|
140
192
|
def http
|
141
193
|
connection_adapter.call(uri, options)
|
142
194
|
end
|
143
195
|
|
144
|
-
def body
|
145
|
-
options[:body].respond_to?(:to_hash) ? normalize_query(options[:body]) : options[:body]
|
146
|
-
end
|
147
|
-
|
148
196
|
def credentials
|
149
197
|
(options[:basic_auth] || options[:digest_auth]).to_hash
|
150
198
|
end
|
@@ -170,106 +218,78 @@ module HTTParty
|
|
170
218
|
end
|
171
219
|
|
172
220
|
def setup_raw_request
|
173
|
-
|
174
|
-
|
175
|
-
@raw_request.body_stream = options[:body_stream] if options[:body_stream]
|
176
|
-
@raw_request.initialize_http_header(options[:headers].to_hash) if options[:headers].respond_to?(:to_hash)
|
177
|
-
@raw_request.basic_auth(username, password) if options[:basic_auth]
|
178
|
-
setup_digest_auth if options[:digest_auth]
|
179
|
-
end
|
180
|
-
|
181
|
-
def setup_digest_auth
|
182
|
-
auth_request = http_method.new(uri.request_uri)
|
183
|
-
auth_request.initialize_http_header(options[:headers].to_hash) if options[:headers].respond_to?(:to_hash)
|
184
|
-
res = http.request(auth_request)
|
185
|
-
|
186
|
-
if !res['www-authenticate'].nil? && res['www-authenticate'].length > 0
|
187
|
-
@raw_request.digest_auth(username, password, res)
|
188
|
-
end
|
189
|
-
end
|
190
|
-
|
191
|
-
def query_string(uri)
|
192
|
-
query_string_parts = []
|
193
|
-
query_string_parts << uri.query unless uri.query.nil?
|
194
|
-
|
195
|
-
if options[:query].respond_to?(:to_hash)
|
196
|
-
query_string_parts << normalize_query(options[:default_params].merge(options[:query].to_hash))
|
221
|
+
if options[:headers].respond_to?(:to_hash)
|
222
|
+
headers_hash = options[:headers].to_hash
|
197
223
|
else
|
198
|
-
|
199
|
-
query_string_parts << options[:query] unless options[:query].nil?
|
224
|
+
headers_hash = nil
|
200
225
|
end
|
201
226
|
|
202
|
-
|
203
|
-
|
204
|
-
end
|
227
|
+
@raw_request = http_method.new(request_uri(uri), headers_hash)
|
228
|
+
@raw_request.body_stream = options[:body_stream] if options[:body_stream]
|
205
229
|
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
230
|
+
if options[:body]
|
231
|
+
body = Body.new(
|
232
|
+
options[:body],
|
233
|
+
query_string_normalizer: query_string_normalizer,
|
234
|
+
force_multipart: options[:multipart]
|
235
|
+
)
|
211
236
|
|
212
|
-
|
213
|
-
|
237
|
+
if body.multipart?
|
238
|
+
content_type = "multipart/form-data; boundary=#{body.boundary}"
|
239
|
+
@raw_request['Content-Type'] = content_type
|
240
|
+
end
|
241
|
+
@raw_request.body = body.call
|
214
242
|
end
|
215
243
|
|
216
|
-
|
217
|
-
return $1.gsub(/\\(.)/, '\1')
|
218
|
-
end
|
244
|
+
@raw_request.instance_variable_set(:@decode_content, decompress_content?)
|
219
245
|
|
220
|
-
|
246
|
+
if options[:basic_auth] && send_authorization_header?
|
247
|
+
@raw_request.basic_auth(username, password)
|
248
|
+
@credentials_sent = true
|
249
|
+
end
|
250
|
+
setup_digest_auth if digest_auth? && response_unauthorized? && response_has_digest_auth_challenge?
|
221
251
|
end
|
222
252
|
|
223
|
-
def
|
224
|
-
|
225
|
-
body.force_encoding(encoding)
|
226
|
-
rescue
|
227
|
-
body
|
253
|
+
def digest_auth?
|
254
|
+
!!options[:digest_auth]
|
228
255
|
end
|
229
256
|
|
230
|
-
def
|
231
|
-
options[:
|
257
|
+
def decompress_content?
|
258
|
+
!options[:skip_decompression]
|
232
259
|
end
|
233
260
|
|
234
|
-
def
|
235
|
-
|
236
|
-
|
237
|
-
return body.force_encoding("UTF-16LE")
|
238
|
-
elsif body.getbyte(0) == 0xFE && body.getbyte(1) == 0xFF
|
239
|
-
return body.force_encoding("UTF-16BE")
|
240
|
-
end
|
241
|
-
end
|
261
|
+
def response_unauthorized?
|
262
|
+
!!last_response && last_response.code == '401'
|
263
|
+
end
|
242
264
|
|
243
|
-
|
244
|
-
|
245
|
-
else
|
246
|
-
body.force_encoding("UTF-16LE")
|
247
|
-
end
|
265
|
+
def response_has_digest_auth_challenge?
|
266
|
+
!last_response['www-authenticate'].nil? && last_response['www-authenticate'].length > 0
|
248
267
|
end
|
249
268
|
|
250
|
-
def
|
251
|
-
|
269
|
+
def setup_digest_auth
|
270
|
+
@raw_request.digest_auth(username, password, last_response)
|
271
|
+
end
|
252
272
|
|
253
|
-
|
254
|
-
|
255
|
-
|
273
|
+
def query_string(uri)
|
274
|
+
query_string_parts = []
|
275
|
+
query_string_parts << uri.query unless uri.query.nil?
|
256
276
|
|
257
|
-
if
|
258
|
-
|
277
|
+
if options[:query].respond_to?(:to_hash)
|
278
|
+
query_string_parts << normalize_query(options[:default_params].merge(options[:query].to_hash))
|
259
279
|
else
|
260
|
-
|
280
|
+
query_string_parts << normalize_query(options[:default_params]) unless options[:default_params].empty?
|
281
|
+
query_string_parts << options[:query] unless options[:query].nil?
|
261
282
|
end
|
283
|
+
|
284
|
+
query_string_parts.reject!(&:empty?) unless query_string_parts == ['']
|
285
|
+
query_string_parts.size > 0 ? query_string_parts.join('&') : nil
|
262
286
|
end
|
263
287
|
|
264
|
-
def
|
265
|
-
|
266
|
-
_encode_body(body)
|
267
|
-
else
|
268
|
-
body
|
269
|
-
end
|
288
|
+
def assume_utf16_is_big_endian
|
289
|
+
options[:assume_utf16_is_big_endian]
|
270
290
|
end
|
271
291
|
|
272
|
-
def handle_response(
|
292
|
+
def handle_response(raw_body, &block)
|
273
293
|
if response_redirects?
|
274
294
|
options[:limit] -= 1
|
275
295
|
if options[:logger]
|
@@ -290,25 +310,41 @@ module HTTParty
|
|
290
310
|
capture_cookies(last_response)
|
291
311
|
perform(&block)
|
292
312
|
else
|
293
|
-
|
294
|
-
|
295
|
-
|
313
|
+
raw_body ||= last_response.body
|
314
|
+
|
315
|
+
body = decompress(raw_body, last_response['content-encoding']) unless raw_body.nil?
|
316
|
+
|
317
|
+
unless body.nil?
|
318
|
+
body = encode_text(body, last_response['content-type'])
|
319
|
+
|
320
|
+
if decompress_content?
|
321
|
+
last_response.delete('content-encoding')
|
322
|
+
raw_body = body
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
Response.new(self, last_response, lambda { parse_response(body) }, body: raw_body)
|
296
327
|
end
|
297
328
|
end
|
298
329
|
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
330
|
+
def handle_host_redirection
|
331
|
+
check_duplicate_location_header
|
332
|
+
redirect_path = options[:uri_adapter].parse(last_response['location']).normalize
|
333
|
+
return if redirect_path.relative? || path.host == redirect_path.host
|
334
|
+
@changed_hosts = true
|
335
|
+
end
|
336
|
+
|
337
|
+
def check_duplicate_location_header
|
338
|
+
location = last_response.get_fields('location')
|
339
|
+
if location.is_a?(Array) && location.count > 1
|
340
|
+
raise DuplicateLocationHeader.new(last_response)
|
309
341
|
end
|
310
342
|
end
|
311
343
|
|
344
|
+
def send_authorization_header?
|
345
|
+
!@changed_hosts
|
346
|
+
end
|
347
|
+
|
312
348
|
def response_redirects?
|
313
349
|
case last_response
|
314
350
|
when Net::HTTPNotModified # 304
|
@@ -327,6 +363,7 @@ module HTTParty
|
|
327
363
|
cookies_hash = HTTParty::CookieHash.new
|
328
364
|
cookies_hash.add_cookies(options[:headers].to_hash['Cookie']) if options[:headers] && options[:headers].to_hash['Cookie']
|
329
365
|
response.get_fields('Set-Cookie').each { |cookie| cookies_hash.add_cookies(cookie) }
|
366
|
+
|
330
367
|
options[:headers] ||= {}
|
331
368
|
options[:headers]['Cookie'] = cookies_hash.to_cookie_string
|
332
369
|
end
|
@@ -358,7 +395,20 @@ module HTTParty
|
|
358
395
|
if path.userinfo
|
359
396
|
username, password = path.userinfo.split(':')
|
360
397
|
options[:basic_auth] = {username: username, password: password}
|
398
|
+
@credentials_sent = true
|
361
399
|
end
|
362
400
|
end
|
401
|
+
|
402
|
+
def decompress(body, encoding)
|
403
|
+
Decompressor.new(body, encoding).decompress
|
404
|
+
end
|
405
|
+
|
406
|
+
def encode_text(text, content_type)
|
407
|
+
TextEncoder.new(
|
408
|
+
text,
|
409
|
+
content_type: content_type,
|
410
|
+
assume_utf16_is_big_endian: assume_utf16_is_big_endian
|
411
|
+
).call
|
412
|
+
end
|
363
413
|
end
|
364
414
|
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,50 +22,102 @@ 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
|
32
|
+
|
33
|
+
throw_exception
|
20
34
|
end
|
21
35
|
|
22
36
|
def parsed_response
|
23
37
|
@parsed_response ||= @parsed_block.call
|
24
38
|
end
|
25
39
|
|
26
|
-
def class
|
27
|
-
Response
|
28
|
-
end
|
29
|
-
|
30
40
|
def code
|
31
41
|
response.code.to_i
|
32
42
|
end
|
33
43
|
|
44
|
+
def http_version
|
45
|
+
response.http_version
|
46
|
+
end
|
47
|
+
|
34
48
|
def tap
|
35
49
|
yield self
|
36
50
|
self
|
37
51
|
end
|
38
52
|
|
39
53
|
def inspect
|
40
|
-
inspect_id = ::Kernel::format
|
54
|
+
inspect_id = ::Kernel::format '%x', (object_id * 2)
|
41
55
|
%(#<#{self.class}:0x#{inspect_id} parsed_response=#{parsed_response.inspect}, @response=#{response.inspect}, @headers=#{headers.inspect}>)
|
42
56
|
end
|
43
57
|
|
44
58
|
CODES_TO_OBJ = ::Net::HTTPResponse::CODE_CLASS_TO_OBJ.merge ::Net::HTTPResponse::CODE_TO_OBJ
|
45
59
|
|
46
60
|
CODES_TO_OBJ.each do |response_code, klass|
|
47
|
-
name = klass.name.sub(
|
48
|
-
|
61
|
+
name = klass.name.sub('Net::HTTP', '')
|
62
|
+
name = "#{underscore(name)}?".to_sym
|
63
|
+
|
64
|
+
define_method(name) do
|
49
65
|
klass === response
|
50
66
|
end
|
51
67
|
end
|
52
68
|
|
53
69
|
# Support old multiple_choice? method from pre 2.0.0 era.
|
54
|
-
if ::RUBY_VERSION >=
|
70
|
+
if ::RUBY_VERSION >= '2.0.0' && ::RUBY_PLATFORM != 'java'
|
55
71
|
alias_method :multiple_choice?, :multiple_choices?
|
56
72
|
end
|
57
73
|
|
58
|
-
|
59
|
-
|
60
|
-
|
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])
|
61
121
|
end
|
62
122
|
|
63
123
|
protected
|
@@ -71,6 +131,25 @@ module HTTParty
|
|
71
131
|
super
|
72
132
|
end
|
73
133
|
end
|
134
|
+
|
135
|
+
def throw_exception
|
136
|
+
if @request.options[:raise_on] && @request.options[:raise_on].include?(code)
|
137
|
+
::Kernel.raise ::HTTParty::ResponseError.new(@response), "Code #{code} - #{body}"
|
138
|
+
end
|
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
|
74
153
|
end
|
75
154
|
end
|
76
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
|