httparty 0.16.4 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of httparty might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/.github/workflows/ci.yml +23 -0
- data/.rubocop_todo.yml +1 -1
- data/Changelog.md +55 -0
- data/Gemfile +5 -0
- data/README.md +4 -4
- data/docs/README.md +70 -5
- data/examples/README.md +6 -0
- data/examples/aaws.rb +6 -2
- data/examples/idn.rb +10 -0
- data/examples/peer_cert.rb +9 -0
- data/httparty.gemspec +1 -2
- data/lib/httparty/connection_adapter.rb +41 -10
- data/lib/httparty/cookie_hash.rb +10 -8
- data/lib/httparty/decompressor.rb +92 -0
- data/lib/httparty/exceptions.rb +3 -1
- data/lib/httparty/hash_conversions.rb +4 -2
- data/lib/httparty/headers_processor.rb +32 -0
- data/lib/httparty/logger/apache_formatter.rb +4 -2
- data/lib/httparty/logger/curl_formatter.rb +6 -4
- data/lib/httparty/logger/logger.rb +2 -0
- data/lib/httparty/logger/logstash_formatter.rb +4 -2
- data/lib/httparty/module_inheritable_attributes.rb +3 -1
- data/lib/httparty/net_digest_auth.rb +9 -10
- data/lib/httparty/parser.rb +9 -5
- data/lib/httparty/request/body.rb +24 -10
- data/lib/httparty/request/multipart_boundary.rb +2 -0
- data/lib/httparty/request.rb +67 -96
- data/lib/httparty/response/headers.rb +2 -0
- data/lib/httparty/response.rb +24 -4
- data/lib/httparty/{fragment_with_response.rb → response_fragment.rb} +6 -5
- data/lib/httparty/text_encoder.rb +72 -0
- data/lib/httparty/utils.rb +2 -0
- data/lib/httparty/version.rb +3 -1
- data/lib/httparty.rb +58 -35
- metadata +12 -108
- data/.travis.yml +0 -11
- 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/example.html +0 -10
- data/spec/fixtures/ssl/generate.sh +0 -29
- 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/tiny.gif +0 -0
- 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 -502
- data/spec/httparty/cookie_hash_spec.rb +0 -100
- data/spec/httparty/exception_spec.rb +0 -45
- data/spec/httparty/fragment_with_response_spec.rb +0 -14
- data/spec/httparty/hash_conversions_spec.rb +0 -58
- data/spec/httparty/logger/apache_formatter_spec.rb +0 -40
- data/spec/httparty/logger/curl_formatter_spec.rb +0 -119
- data/spec/httparty/logger/logger_spec.rb +0 -43
- data/spec/httparty/logger/logstash_formatter_spec.rb +0 -44
- data/spec/httparty/net_digest_auth_spec.rb +0 -270
- data/spec/httparty/parser_spec.rb +0 -190
- data/spec/httparty/request/body_spec.rb +0 -165
- data/spec/httparty/request_spec.rb +0 -1367
- data/spec/httparty/response_spec.rb +0 -368
- data/spec/httparty/ssl_spec.rb +0 -74
- data/spec/httparty_spec.rb +0 -923
- data/spec/spec_helper.rb +0 -56
- 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
@@ -1,9 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module HTTParty
|
2
4
|
module Logger
|
3
5
|
class CurlFormatter #:nodoc:
|
4
6
|
TAG_NAME = HTTParty.name
|
5
|
-
OUT = '>'
|
6
|
-
IN = '<'
|
7
|
+
OUT = '>'
|
8
|
+
IN = '<'
|
7
9
|
|
8
10
|
attr_accessor :level, :logger
|
9
11
|
|
@@ -20,7 +22,7 @@ module HTTParty
|
|
20
22
|
log_request
|
21
23
|
log_response
|
22
24
|
|
23
|
-
logger.public_send level, messages.join(
|
25
|
+
logger.public_send level, messages.join('\n')
|
24
26
|
end
|
25
27
|
|
26
28
|
private
|
@@ -44,7 +46,7 @@ module HTTParty
|
|
44
46
|
end
|
45
47
|
|
46
48
|
def log_url
|
47
|
-
http_method = request.http_method.name.split(
|
49
|
+
http_method = request.http_method.name.split('::').last.upcase
|
48
50
|
uri = if request.options[:base_uri]
|
49
51
|
request.options[:base_uri] + request.path.path
|
50
52
|
else
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module HTTParty
|
2
4
|
module Logger
|
3
5
|
class LogstashFormatter #:nodoc:
|
@@ -40,11 +42,11 @@ module HTTParty
|
|
40
42
|
end
|
41
43
|
|
42
44
|
def current_time
|
43
|
-
Time.now.strftime(
|
45
|
+
Time.now.strftime('%Y-%m-%d %H:%M:%S %z')
|
44
46
|
end
|
45
47
|
|
46
48
|
def http_method
|
47
|
-
@http_method ||= request.http_method.name.split(
|
49
|
+
@http_method ||= request.http_method.name.split('::').last.upcase
|
48
50
|
end
|
49
51
|
|
50
52
|
def path
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module HTTParty
|
2
4
|
module ModuleInheritableAttributes #:nodoc:
|
3
5
|
def self.included(base)
|
@@ -36,7 +38,7 @@ module HTTParty
|
|
36
38
|
def inherited(subclass)
|
37
39
|
super
|
38
40
|
@mattr_inheritable_attrs.each do |inheritable_attribute|
|
39
|
-
ivar = "@#{inheritable_attribute}"
|
41
|
+
ivar = :"@#{inheritable_attribute}"
|
40
42
|
subclass.instance_variable_set(ivar, instance_variable_get(ivar).clone)
|
41
43
|
|
42
44
|
if instance_variable_get(ivar).respond_to?(:merge)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'digest/md5'
|
2
4
|
require 'net/http'
|
3
5
|
|
@@ -44,12 +46,9 @@ module Net
|
|
44
46
|
header << %(algorithm="#{@response['algorithm']}") if algorithm_present?
|
45
47
|
|
46
48
|
if qop_present?
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
"nc=00000001"
|
51
|
-
]
|
52
|
-
fields.each { |field| header << field }
|
49
|
+
header << %(cnonce="#{@cnonce}")
|
50
|
+
header << %(qop="#{@response['qop']}")
|
51
|
+
header << 'nc=00000001'
|
53
52
|
end
|
54
53
|
|
55
54
|
header << %(opaque="#{@response['opaque']}") if opaque_present?
|
@@ -98,13 +97,13 @@ module Net
|
|
98
97
|
end
|
99
98
|
|
100
99
|
def random
|
101
|
-
format
|
100
|
+
format '%x', (Time.now.to_i + rand(65535))
|
102
101
|
end
|
103
102
|
|
104
103
|
def request_digest
|
105
104
|
a = [md5(a1), @response['nonce'], md5(a2)]
|
106
|
-
a.insert(2,
|
107
|
-
md5(a.join(
|
105
|
+
a.insert(2, '00000001', @cnonce, @response['qop']) if qop_present?
|
106
|
+
md5(a.join(':'))
|
108
107
|
end
|
109
108
|
|
110
109
|
def md5(str)
|
@@ -129,7 +128,7 @@ module Net
|
|
129
128
|
end
|
130
129
|
|
131
130
|
def a2
|
132
|
-
[@method, @path].join(
|
131
|
+
[@method, @path].join(':')
|
133
132
|
end
|
134
133
|
end
|
135
134
|
end
|
data/lib/httparty/parser.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module HTTParty
|
2
4
|
# The default parser used by HTTParty, supports xml, json, html, csv and
|
3
5
|
# plain text.
|
@@ -101,7 +103,7 @@ module HTTParty
|
|
101
103
|
# @return [nil] when the response body is nil, an empty string, spaces only or "null"
|
102
104
|
def parse
|
103
105
|
return nil if body.nil?
|
104
|
-
return nil if body ==
|
106
|
+
return nil if body == 'null'
|
105
107
|
return nil if body.valid_encoding? && body.strip.empty?
|
106
108
|
if body.valid_encoding? && body.encoding == Encoding::UTF_8
|
107
109
|
@body = body.gsub(/\A#{UTF8_BOM}/, '')
|
@@ -119,7 +121,7 @@ module HTTParty
|
|
119
121
|
MultiXml.parse(body)
|
120
122
|
end
|
121
123
|
|
122
|
-
UTF8_BOM = "\xEF\xBB\xBF"
|
124
|
+
UTF8_BOM = "\xEF\xBB\xBF"
|
123
125
|
|
124
126
|
def json
|
125
127
|
JSON.parse(body, :quirks_mode => true, :allow_nan => true)
|
@@ -142,9 +144,11 @@ module HTTParty
|
|
142
144
|
end
|
143
145
|
|
144
146
|
def parse_supported_format
|
145
|
-
|
146
|
-
|
147
|
-
|
147
|
+
if respond_to?(format, true)
|
148
|
+
send(format)
|
149
|
+
else
|
150
|
+
raise NotImplementedError, "#{self.class.name} has not implemented a parsing method for the #{format.inspect} format."
|
151
|
+
end
|
148
152
|
end
|
149
153
|
end
|
150
154
|
end
|
@@ -1,8 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative 'multipart_boundary'
|
2
4
|
|
3
5
|
module HTTParty
|
4
6
|
class Request
|
5
7
|
class Body
|
8
|
+
NEWLINE = "\r\n"
|
9
|
+
private_constant :NEWLINE
|
10
|
+
|
6
11
|
def initialize(params, query_string_normalizer: nil, force_multipart: false)
|
7
12
|
@params = params
|
8
13
|
@query_string_normalizer = query_string_normalizer
|
@@ -30,20 +35,20 @@ module HTTParty
|
|
30
35
|
def generate_multipart
|
31
36
|
normalized_params = params.flat_map { |key, value| HashConversions.normalize_keys(key, value) }
|
32
37
|
|
33
|
-
multipart = normalized_params.inject('') do |memo, (key, value)|
|
34
|
-
memo
|
35
|
-
memo
|
38
|
+
multipart = normalized_params.inject(''.dup) do |memo, (key, value)|
|
39
|
+
memo << "--#{boundary}#{NEWLINE}"
|
40
|
+
memo << %(Content-Disposition: form-data; name="#{key}")
|
36
41
|
# value.path is used to support ActionDispatch::Http::UploadedFile
|
37
42
|
# https://github.com/jnunemaker/httparty/pull/585
|
38
|
-
memo
|
39
|
-
memo
|
40
|
-
memo
|
41
|
-
memo
|
42
|
-
memo
|
43
|
-
memo
|
43
|
+
memo << %(; filename="#{file_name(value)}") if file?(value)
|
44
|
+
memo << NEWLINE
|
45
|
+
memo << "Content-Type: #{content_type(value)}#{NEWLINE}" if file?(value)
|
46
|
+
memo << NEWLINE
|
47
|
+
memo << content_body(value)
|
48
|
+
memo << NEWLINE
|
44
49
|
end
|
45
50
|
|
46
|
-
multipart
|
51
|
+
multipart << "--#{boundary}--#{NEWLINE}"
|
47
52
|
end
|
48
53
|
|
49
54
|
def has_file?(value)
|
@@ -68,6 +73,15 @@ module HTTParty
|
|
68
73
|
end
|
69
74
|
end
|
70
75
|
|
76
|
+
def content_body(object)
|
77
|
+
if file?(object)
|
78
|
+
object = (file = object).read
|
79
|
+
file.rewind if file.respond_to?(:rewind)
|
80
|
+
end
|
81
|
+
|
82
|
+
object.to_s
|
83
|
+
end
|
84
|
+
|
71
85
|
def content_type(object)
|
72
86
|
return object.content_type if object.respond_to?(:content_type)
|
73
87
|
mime = MIME::Types.type_for(object.path)
|
data/lib/httparty/request.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'erb'
|
2
|
-
require 'httparty/request/body'
|
3
|
-
require 'httparty/fragment_with_response'
|
4
4
|
|
5
5
|
module HTTParty
|
6
6
|
class Request #:nodoc:
|
@@ -46,6 +46,11 @@ module HTTParty
|
|
46
46
|
end.flatten.join('&')
|
47
47
|
end
|
48
48
|
|
49
|
+
def self._load(data)
|
50
|
+
http_method, path, options = Marshal.load(data)
|
51
|
+
new(http_method, path, options)
|
52
|
+
end
|
53
|
+
|
49
54
|
attr_accessor :http_method, :options, :last_response, :redirect, :last_uri
|
50
55
|
attr_reader :path
|
51
56
|
|
@@ -73,7 +78,7 @@ module HTTParty
|
|
73
78
|
@path = if uri.is_a?(uri_adapter)
|
74
79
|
uri
|
75
80
|
elsif String.try_convert(uri)
|
76
|
-
uri_adapter.parse
|
81
|
+
uri_adapter.parse(uri).normalize
|
77
82
|
else
|
78
83
|
raise ArgumentError,
|
79
84
|
"bad argument (expected #{uri_adapter} object or URI string)"
|
@@ -89,17 +94,17 @@ module HTTParty
|
|
89
94
|
end
|
90
95
|
|
91
96
|
def uri
|
92
|
-
if redirect && path.relative? && path.path[0] !=
|
93
|
-
last_uri_host = @last_uri.path.gsub(/[^\/]+$/,
|
97
|
+
if redirect && path.relative? && path.path[0] != '/'
|
98
|
+
last_uri_host = @last_uri.path.gsub(/[^\/]+$/, '')
|
94
99
|
|
95
|
-
path.path = "/#{path.path}" if last_uri_host[-1] !=
|
96
|
-
path.path = last_uri_host
|
100
|
+
path.path = "/#{path.path}" if last_uri_host[-1] != '/'
|
101
|
+
path.path = "#{last_uri_host}#{path.path}"
|
97
102
|
end
|
98
103
|
|
99
104
|
if path.relative? && path.host
|
100
|
-
new_uri = options[:uri_adapter].parse("#{@last_uri.scheme}:#{path}")
|
105
|
+
new_uri = options[:uri_adapter].parse("#{@last_uri.scheme}:#{path}").normalize
|
101
106
|
elsif path.relative?
|
102
|
-
new_uri = options[:uri_adapter].parse("#{base_uri}#{path}")
|
107
|
+
new_uri = options[:uri_adapter].parse("#{base_uri}#{path}").normalize
|
103
108
|
else
|
104
109
|
new_uri = path.clone
|
105
110
|
end
|
@@ -119,7 +124,7 @@ module HTTParty
|
|
119
124
|
def base_uri
|
120
125
|
if redirect
|
121
126
|
base_uri = "#{@last_uri.scheme}://#{@last_uri.host}"
|
122
|
-
base_uri
|
127
|
+
base_uri = "#{base_uri}:#{@last_uri.port}" if @last_uri.port != 80
|
123
128
|
base_uri
|
124
129
|
else
|
125
130
|
options[:base_uri] && HTTParty.normalize_base_uri(options[:base_uri])
|
@@ -142,21 +147,22 @@ module HTTParty
|
|
142
147
|
validate
|
143
148
|
setup_raw_request
|
144
149
|
chunked_body = nil
|
150
|
+
current_http = http
|
145
151
|
|
146
|
-
self.last_response =
|
152
|
+
self.last_response = current_http.request(@raw_request) do |http_response|
|
147
153
|
if block
|
148
154
|
chunks = []
|
149
155
|
|
150
156
|
http_response.read_body do |fragment|
|
151
|
-
|
152
|
-
|
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)
|
153
160
|
end
|
154
161
|
|
155
162
|
chunked_body = chunks.join
|
156
163
|
end
|
157
164
|
end
|
158
165
|
|
159
|
-
|
160
166
|
handle_host_redirection if response_redirects?
|
161
167
|
result = handle_unauthorized
|
162
168
|
result ||= handle_response(chunked_body, &block)
|
@@ -174,6 +180,13 @@ module HTTParty
|
|
174
180
|
@raw_request.body
|
175
181
|
end
|
176
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
|
+
|
177
190
|
private
|
178
191
|
|
179
192
|
def http
|
@@ -205,22 +218,15 @@ module HTTParty
|
|
205
218
|
end
|
206
219
|
|
207
220
|
def setup_raw_request
|
208
|
-
@raw_request = http_method.new(request_uri(uri))
|
209
|
-
@raw_request.body_stream = options[:body_stream] if options[:body_stream]
|
210
|
-
|
211
221
|
if options[:headers].respond_to?(:to_hash)
|
212
222
|
headers_hash = options[:headers].to_hash
|
213
|
-
|
214
|
-
|
215
|
-
# If the caller specified a header of 'Accept-Encoding', assume they want to
|
216
|
-
# deal with encoding of content. Disable the internal logic in Net:HTTP
|
217
|
-
# that handles encoding, if the platform supports it.
|
218
|
-
if @raw_request.respond_to?(:decode_content) && (headers_hash.key?('Accept-Encoding') || headers_hash.key?('accept-encoding'))
|
219
|
-
# Using the '[]=' sets decode_content to false
|
220
|
-
@raw_request['accept-encoding'] = @raw_request['accept-encoding']
|
221
|
-
end
|
223
|
+
else
|
224
|
+
headers_hash = nil
|
222
225
|
end
|
223
226
|
|
227
|
+
@raw_request = http_method.new(request_uri(uri), headers_hash)
|
228
|
+
@raw_request.body_stream = options[:body_stream] if options[:body_stream]
|
229
|
+
|
224
230
|
if options[:body]
|
225
231
|
body = Body.new(
|
226
232
|
options[:body],
|
@@ -235,6 +241,8 @@ module HTTParty
|
|
235
241
|
@raw_request.body = body.call
|
236
242
|
end
|
237
243
|
|
244
|
+
@raw_request.instance_variable_set(:@decode_content, decompress_content?)
|
245
|
+
|
238
246
|
if options[:basic_auth] && send_authorization_header?
|
239
247
|
@raw_request.basic_auth(username, password)
|
240
248
|
@credentials_sent = true
|
@@ -246,6 +254,10 @@ module HTTParty
|
|
246
254
|
!!options[:digest_auth]
|
247
255
|
end
|
248
256
|
|
257
|
+
def decompress_content?
|
258
|
+
!options[:skip_decompression]
|
259
|
+
end
|
260
|
+
|
249
261
|
def response_unauthorized?
|
250
262
|
!!last_response && last_response.code == '401'
|
251
263
|
end
|
@@ -269,79 +281,15 @@ module HTTParty
|
|
269
281
|
query_string_parts << options[:query] unless options[:query].nil?
|
270
282
|
end
|
271
283
|
|
272
|
-
query_string_parts.reject!(&:empty?) unless query_string_parts == [
|
284
|
+
query_string_parts.reject!(&:empty?) unless query_string_parts == ['']
|
273
285
|
query_string_parts.size > 0 ? query_string_parts.join('&') : nil
|
274
286
|
end
|
275
287
|
|
276
|
-
def get_charset
|
277
|
-
content_type = last_response["content-type"]
|
278
|
-
if content_type.nil?
|
279
|
-
return nil
|
280
|
-
end
|
281
|
-
|
282
|
-
if content_type =~ /;\s*charset\s*=\s*([^=,;"\s]+)/i
|
283
|
-
return $1
|
284
|
-
end
|
285
|
-
|
286
|
-
if content_type =~ /;\s*charset\s*=\s*"((\\.|[^\\"])+)"/i
|
287
|
-
return $1.gsub(/\\(.)/, '\1')
|
288
|
-
end
|
289
|
-
|
290
|
-
nil
|
291
|
-
end
|
292
|
-
|
293
|
-
def encode_with_ruby_encoding(body, charset)
|
294
|
-
# NOTE: This will raise an argument error if the
|
295
|
-
# charset does not exist
|
296
|
-
encoding = Encoding.find(charset)
|
297
|
-
body.force_encoding(encoding.to_s)
|
298
|
-
rescue ArgumentError
|
299
|
-
body
|
300
|
-
end
|
301
|
-
|
302
288
|
def assume_utf16_is_big_endian
|
303
289
|
options[:assume_utf16_is_big_endian]
|
304
290
|
end
|
305
291
|
|
306
|
-
def
|
307
|
-
if body.bytesize >= 2
|
308
|
-
if body.getbyte(0) == 0xFF && body.getbyte(1) == 0xFE
|
309
|
-
return body.force_encoding("UTF-16LE")
|
310
|
-
elsif body.getbyte(0) == 0xFE && body.getbyte(1) == 0xFF
|
311
|
-
return body.force_encoding("UTF-16BE")
|
312
|
-
end
|
313
|
-
end
|
314
|
-
|
315
|
-
if assume_utf16_is_big_endian
|
316
|
-
body.force_encoding("UTF-16BE")
|
317
|
-
else
|
318
|
-
body.force_encoding("UTF-16LE")
|
319
|
-
end
|
320
|
-
end
|
321
|
-
|
322
|
-
def _encode_body(body)
|
323
|
-
charset = get_charset
|
324
|
-
|
325
|
-
if charset.nil?
|
326
|
-
return body
|
327
|
-
end
|
328
|
-
|
329
|
-
if "utf-16".casecmp(charset) == 0
|
330
|
-
encode_utf_16(body)
|
331
|
-
else
|
332
|
-
encode_with_ruby_encoding(body, charset)
|
333
|
-
end
|
334
|
-
end
|
335
|
-
|
336
|
-
def encode_body(body)
|
337
|
-
if "".respond_to?(:encoding)
|
338
|
-
_encode_body(body)
|
339
|
-
else
|
340
|
-
body
|
341
|
-
end
|
342
|
-
end
|
343
|
-
|
344
|
-
def handle_response(body, &block)
|
292
|
+
def handle_response(raw_body, &block)
|
345
293
|
if response_redirects?
|
346
294
|
options[:limit] -= 1
|
347
295
|
if options[:logger]
|
@@ -362,15 +310,26 @@ module HTTParty
|
|
362
310
|
capture_cookies(last_response)
|
363
311
|
perform(&block)
|
364
312
|
else
|
365
|
-
|
366
|
-
|
367
|
-
|
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)
|
368
327
|
end
|
369
328
|
end
|
370
329
|
|
371
330
|
def handle_host_redirection
|
372
331
|
check_duplicate_location_header
|
373
|
-
redirect_path = options[:uri_adapter].parse
|
332
|
+
redirect_path = options[:uri_adapter].parse(last_response['location']).normalize
|
374
333
|
return if redirect_path.relative? || path.host == redirect_path.host
|
375
334
|
@changed_hosts = true
|
376
335
|
end
|
@@ -439,5 +398,17 @@ module HTTParty
|
|
439
398
|
@credentials_sent = true
|
440
399
|
end
|
441
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
|
442
413
|
end
|
443
414
|
end
|
data/lib/httparty/response.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module HTTParty
|
2
4
|
class Response < Object
|
3
5
|
def self.underscore(string)
|
@@ -39,20 +41,24 @@ module HTTParty
|
|
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
58
|
CODES_TO_OBJ = ::Net::HTTPResponse::CODE_CLASS_TO_OBJ.merge ::Net::HTTPResponse::CODE_TO_OBJ
|
53
59
|
|
54
60
|
CODES_TO_OBJ.each do |response_code, klass|
|
55
|
-
name = klass.name.sub(
|
61
|
+
name = klass.name.sub('Net::HTTP', '')
|
56
62
|
name = "#{underscore(name)}?".to_sym
|
57
63
|
|
58
64
|
define_method(name) do
|
@@ -61,12 +67,12 @@ module HTTParty
|
|
61
67
|
end
|
62
68
|
|
63
69
|
# Support old multiple_choice? method from pre 2.0.0 era.
|
64
|
-
if ::RUBY_VERSION >=
|
70
|
+
if ::RUBY_VERSION >= '2.0.0' && ::RUBY_PLATFORM != 'java'
|
65
71
|
alias_method :multiple_choice?, :multiple_choices?
|
66
72
|
end
|
67
73
|
|
68
74
|
# Support old status codes method from pre 2.6.0 era.
|
69
|
-
if ::RUBY_VERSION >=
|
75
|
+
if ::RUBY_VERSION >= '2.6.0' && ::RUBY_PLATFORM != 'java'
|
70
76
|
alias_method :gateway_time_out?, :gateway_timeout?
|
71
77
|
alias_method :request_entity_too_large?, :payload_too_large?
|
72
78
|
alias_method :request_time_out?, :request_timeout?
|
@@ -75,6 +81,7 @@ module HTTParty
|
|
75
81
|
end
|
76
82
|
|
77
83
|
def nil?
|
84
|
+
warn_about_nil_deprecation
|
78
85
|
response.nil? || response.body.nil? || response.body.empty?
|
79
86
|
end
|
80
87
|
|
@@ -130,6 +137,19 @@ module HTTParty
|
|
130
137
|
::Kernel.raise ::HTTParty::ResponseError.new(@response), "Code #{code} - #{body}"
|
131
138
|
end
|
132
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
|
133
153
|
end
|
134
154
|
end
|
135
155
|
|
@@ -1,19 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'delegate'
|
2
4
|
|
3
5
|
module HTTParty
|
4
6
|
# Allow access to http_response and code by delegation on fragment
|
5
|
-
class
|
6
|
-
|
7
|
-
|
8
|
-
attr_reader :http_response
|
7
|
+
class ResponseFragment < SimpleDelegator
|
8
|
+
attr_reader :http_response, :connection
|
9
9
|
|
10
10
|
def code
|
11
11
|
@http_response.code.to_i
|
12
12
|
end
|
13
13
|
|
14
|
-
def initialize(fragment, http_response)
|
14
|
+
def initialize(fragment, http_response, connection)
|
15
15
|
@fragment = fragment
|
16
16
|
@http_response = http_response
|
17
|
+
@connection = connection
|
17
18
|
super fragment
|
18
19
|
end
|
19
20
|
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module HTTParty
|
4
|
+
class TextEncoder
|
5
|
+
attr_reader :text, :content_type, :assume_utf16_is_big_endian
|
6
|
+
|
7
|
+
def initialize(text, assume_utf16_is_big_endian: true, content_type: nil)
|
8
|
+
@text = text.dup
|
9
|
+
@content_type = content_type
|
10
|
+
@assume_utf16_is_big_endian = assume_utf16_is_big_endian
|
11
|
+
end
|
12
|
+
|
13
|
+
def call
|
14
|
+
if can_encode?
|
15
|
+
encoded_text
|
16
|
+
else
|
17
|
+
text
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def can_encode?
|
24
|
+
''.respond_to?(:encoding) && charset
|
25
|
+
end
|
26
|
+
|
27
|
+
def encoded_text
|
28
|
+
if 'utf-16'.casecmp(charset) == 0
|
29
|
+
encode_utf_16
|
30
|
+
else
|
31
|
+
encode_with_ruby_encoding
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def encode_utf_16
|
36
|
+
if text.bytesize >= 2
|
37
|
+
if text.getbyte(0) == 0xFF && text.getbyte(1) == 0xFE
|
38
|
+
return text.force_encoding('UTF-16LE')
|
39
|
+
elsif text.getbyte(0) == 0xFE && text.getbyte(1) == 0xFF
|
40
|
+
return text.force_encoding('UTF-16BE')
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
if assume_utf16_is_big_endian # option
|
45
|
+
text.force_encoding('UTF-16BE')
|
46
|
+
else
|
47
|
+
text.force_encoding('UTF-16LE')
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def encode_with_ruby_encoding
|
52
|
+
# NOTE: This will raise an argument error if the
|
53
|
+
# charset does not exist
|
54
|
+
encoding = Encoding.find(charset)
|
55
|
+
text.force_encoding(encoding.to_s)
|
56
|
+
rescue ArgumentError
|
57
|
+
text
|
58
|
+
end
|
59
|
+
|
60
|
+
def charset
|
61
|
+
return nil if content_type.nil?
|
62
|
+
|
63
|
+
if (matchdata = content_type.match(/;\s*charset\s*=\s*([^=,;"\s]+)/i))
|
64
|
+
return matchdata.captures.first
|
65
|
+
end
|
66
|
+
|
67
|
+
if (matchdata = content_type.match(/;\s*charset\s*=\s*"((\\.|[^\\"])+)"/i))
|
68
|
+
return matchdata.captures.first.gsub(/\\(.)/, '\1')
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|