httparty 0.15.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/.editorconfig +18 -0
- data/.github/workflows/ci.yml +23 -0
- data/.gitignore +2 -0
- data/.rubocop_todo.yml +1 -1
- data/Changelog.md +105 -0
- data/Gemfile +6 -1
- data/README.md +6 -6
- data/docs/README.md +100 -38
- data/examples/README.md +28 -11
- data/examples/aaws.rb +6 -2
- data/examples/body_stream.rb +14 -0
- data/examples/custom_parsers.rb +4 -0
- data/examples/headers_and_user_agents.rb +7 -3
- data/examples/idn.rb +10 -0
- data/examples/logging.rb +3 -3
- data/examples/microsoft_graph.rb +52 -0
- data/examples/multipart.rb +22 -0
- data/examples/peer_cert.rb +9 -0
- data/examples/stream_download.rb +8 -2
- data/httparty.gemspec +3 -3
- data/lib/httparty/connection_adapter.rb +59 -16
- data/lib/httparty/cookie_hash.rb +10 -8
- data/lib/httparty/decompressor.rb +92 -0
- data/lib/httparty/exceptions.rb +4 -1
- data/lib/httparty/hash_conversions.rb +28 -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 +15 -15
- data/lib/httparty/parser.rb +22 -16
- data/lib/httparty/request/body.rb +98 -0
- data/lib/httparty/request/multipart_boundary.rb +13 -0
- data/lib/httparty/request.rb +82 -95
- data/lib/httparty/response/headers.rb +4 -2
- data/lib/httparty/response.rb +59 -8
- 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 +70 -24
- data/website/css/common.css +1 -1
- metadata +35 -100
- data/.travis.yml +0 -8
- 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/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 -268
- data/spec/httparty/parser_spec.rb +0 -185
- data/spec/httparty/request_spec.rb +0 -1251
- data/spec/httparty/response_spec.rb +0 -347
- data/spec/httparty/ssl_spec.rb +0 -74
- data/spec/httparty_spec.rb +0 -877
- 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
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'digest/md5'
|
2
4
|
require 'net/http'
|
3
5
|
|
@@ -14,11 +16,11 @@ module Net
|
|
14
16
|
|
15
17
|
authenticator.authorization_header.each do |v|
|
16
18
|
add_field('Authorization', v)
|
17
|
-
end
|
19
|
+
end
|
18
20
|
|
19
21
|
authenticator.cookie_header.each do |v|
|
20
22
|
add_field('Cookie', v)
|
21
|
-
end
|
23
|
+
end
|
22
24
|
end
|
23
25
|
|
24
26
|
class DigestAuthenticator
|
@@ -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?
|
@@ -64,7 +63,8 @@ module Net
|
|
64
63
|
|
65
64
|
def parse(response_header)
|
66
65
|
header = response_header['www-authenticate']
|
67
|
-
|
66
|
+
|
67
|
+
header = header.gsub(/qop=(auth(?:-int)?)/, 'qop="\\1"')
|
68
68
|
|
69
69
|
header =~ /Digest (.*)/
|
70
70
|
params = {}
|
@@ -97,13 +97,13 @@ module Net
|
|
97
97
|
end
|
98
98
|
|
99
99
|
def random
|
100
|
-
format
|
100
|
+
format '%x', (Time.now.to_i + rand(65535))
|
101
101
|
end
|
102
102
|
|
103
103
|
def request_digest
|
104
104
|
a = [md5(a1), @response['nonce'], md5(a2)]
|
105
|
-
a.insert(2,
|
106
|
-
md5(a.join(
|
105
|
+
a.insert(2, '00000001', @cnonce, @response['qop']) if qop_present?
|
106
|
+
md5(a.join(':'))
|
107
107
|
end
|
108
108
|
|
109
109
|
def md5(str)
|
@@ -113,11 +113,11 @@ module Net
|
|
113
113
|
def algorithm_present?
|
114
114
|
@response.key?('algorithm') && !@response['algorithm'].empty?
|
115
115
|
end
|
116
|
-
|
116
|
+
|
117
117
|
def use_md5_sess?
|
118
118
|
algorithm_present? && @response['algorithm'] == 'MD5-sess'
|
119
119
|
end
|
120
|
-
|
120
|
+
|
121
121
|
def a1
|
122
122
|
a1_user_realm_pwd = [@username, @response['realm'], @password].join(':')
|
123
123
|
if use_md5_sess?
|
@@ -128,7 +128,7 @@ module Net
|
|
128
128
|
end
|
129
129
|
|
130
130
|
def a2
|
131
|
-
[@method, @path].join(
|
131
|
+
[@method, @path].join(':')
|
132
132
|
end
|
133
133
|
end
|
134
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.
|
@@ -38,16 +40,18 @@ module HTTParty
|
|
38
40
|
# @abstract Read the Custom Parsers section for more information.
|
39
41
|
class Parser
|
40
42
|
SupportedFormats = {
|
41
|
-
'text/xml'
|
42
|
-
'application/xml'
|
43
|
-
'application/json'
|
44
|
-
'
|
45
|
-
'application/
|
46
|
-
'text/
|
47
|
-
'
|
48
|
-
'text/
|
49
|
-
'text/
|
50
|
-
'
|
43
|
+
'text/xml' => :xml,
|
44
|
+
'application/xml' => :xml,
|
45
|
+
'application/json' => :json,
|
46
|
+
'application/vnd.api+json' => :json,
|
47
|
+
'application/hal+json' => :json,
|
48
|
+
'text/json' => :json,
|
49
|
+
'application/javascript' => :plain,
|
50
|
+
'text/javascript' => :plain,
|
51
|
+
'text/html' => :html,
|
52
|
+
'text/plain' => :plain,
|
53
|
+
'text/csv' => :csv,
|
54
|
+
'application/csv' => :csv,
|
51
55
|
'text/comma-separated-values' => :csv
|
52
56
|
}
|
53
57
|
|
@@ -99,10 +103,10 @@ module HTTParty
|
|
99
103
|
# @return [nil] when the response body is nil, an empty string, spaces only or "null"
|
100
104
|
def parse
|
101
105
|
return nil if body.nil?
|
102
|
-
return nil if body ==
|
106
|
+
return nil if body == 'null'
|
103
107
|
return nil if body.valid_encoding? && body.strip.empty?
|
104
108
|
if body.valid_encoding? && body.encoding == Encoding::UTF_8
|
105
|
-
body.gsub
|
109
|
+
@body = body.gsub(/\A#{UTF8_BOM}/, '')
|
106
110
|
end
|
107
111
|
if supports_format?
|
108
112
|
parse_supported_format
|
@@ -117,7 +121,7 @@ module HTTParty
|
|
117
121
|
MultiXml.parse(body)
|
118
122
|
end
|
119
123
|
|
120
|
-
UTF8_BOM = "\xEF\xBB\xBF"
|
124
|
+
UTF8_BOM = "\xEF\xBB\xBF"
|
121
125
|
|
122
126
|
def json
|
123
127
|
JSON.parse(body, :quirks_mode => true, :allow_nan => true)
|
@@ -140,9 +144,11 @@ module HTTParty
|
|
140
144
|
end
|
141
145
|
|
142
146
|
def parse_supported_format
|
143
|
-
|
144
|
-
|
145
|
-
|
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
|
146
152
|
end
|
147
153
|
end
|
148
154
|
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'multipart_boundary'
|
4
|
+
|
5
|
+
module HTTParty
|
6
|
+
class Request
|
7
|
+
class Body
|
8
|
+
NEWLINE = "\r\n"
|
9
|
+
private_constant :NEWLINE
|
10
|
+
|
11
|
+
def initialize(params, query_string_normalizer: nil, force_multipart: false)
|
12
|
+
@params = params
|
13
|
+
@query_string_normalizer = query_string_normalizer
|
14
|
+
@force_multipart = force_multipart
|
15
|
+
end
|
16
|
+
|
17
|
+
def call
|
18
|
+
if params.respond_to?(:to_hash)
|
19
|
+
multipart? ? generate_multipart : normalize_query(params)
|
20
|
+
else
|
21
|
+
params
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def boundary
|
26
|
+
@boundary ||= MultipartBoundary.generate
|
27
|
+
end
|
28
|
+
|
29
|
+
def multipart?
|
30
|
+
params.respond_to?(:to_hash) && (force_multipart || has_file?(params))
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def generate_multipart
|
36
|
+
normalized_params = params.flat_map { |key, value| HashConversions.normalize_keys(key, value) }
|
37
|
+
|
38
|
+
multipart = normalized_params.inject(''.dup) do |memo, (key, value)|
|
39
|
+
memo << "--#{boundary}#{NEWLINE}"
|
40
|
+
memo << %(Content-Disposition: form-data; name="#{key}")
|
41
|
+
# value.path is used to support ActionDispatch::Http::UploadedFile
|
42
|
+
# https://github.com/jnunemaker/httparty/pull/585
|
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
|
49
|
+
end
|
50
|
+
|
51
|
+
multipart << "--#{boundary}--#{NEWLINE}"
|
52
|
+
end
|
53
|
+
|
54
|
+
def has_file?(value)
|
55
|
+
if value.respond_to?(:to_hash)
|
56
|
+
value.to_hash.any? { |_, v| has_file?(v) }
|
57
|
+
elsif value.respond_to?(:to_ary)
|
58
|
+
value.to_ary.any? { |v| has_file?(v) }
|
59
|
+
else
|
60
|
+
file?(value)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def file?(object)
|
65
|
+
object.respond_to?(:path) && object.respond_to?(:read)
|
66
|
+
end
|
67
|
+
|
68
|
+
def normalize_query(query)
|
69
|
+
if query_string_normalizer
|
70
|
+
query_string_normalizer.call(query)
|
71
|
+
else
|
72
|
+
HashConversions.to_params(query)
|
73
|
+
end
|
74
|
+
end
|
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
|
+
|
85
|
+
def content_type(object)
|
86
|
+
return object.content_type if object.respond_to?(:content_type)
|
87
|
+
mime = MIME::Types.type_for(object.path)
|
88
|
+
mime.empty? ? 'application/octet-stream' : mime[0].content_type
|
89
|
+
end
|
90
|
+
|
91
|
+
def file_name(object)
|
92
|
+
object.respond_to?(:original_filename) ? object.original_filename : File.basename(object.path)
|
93
|
+
end
|
94
|
+
|
95
|
+
attr_reader :params, :query_string_normalizer, :force_multipart
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
data/lib/httparty/request.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'erb'
|
2
4
|
|
3
5
|
module HTTParty
|
@@ -13,6 +15,8 @@ module HTTParty
|
|
13
15
|
Net::HTTP::Move,
|
14
16
|
Net::HTTP::Copy,
|
15
17
|
Net::HTTP::Mkcol,
|
18
|
+
Net::HTTP::Lock,
|
19
|
+
Net::HTTP::Unlock,
|
16
20
|
]
|
17
21
|
|
18
22
|
SupportedURISchemes = ['http', 'https', 'webcal', nil]
|
@@ -42,6 +46,11 @@ module HTTParty
|
|
42
46
|
end.flatten.join('&')
|
43
47
|
end
|
44
48
|
|
49
|
+
def self._load(data)
|
50
|
+
http_method, path, options = Marshal.load(data)
|
51
|
+
new(http_method, path, options)
|
52
|
+
end
|
53
|
+
|
45
54
|
attr_accessor :http_method, :options, :last_response, :redirect, :last_uri
|
46
55
|
attr_reader :path
|
47
56
|
|
@@ -69,7 +78,7 @@ module HTTParty
|
|
69
78
|
@path = if uri.is_a?(uri_adapter)
|
70
79
|
uri
|
71
80
|
elsif String.try_convert(uri)
|
72
|
-
uri_adapter.parse
|
81
|
+
uri_adapter.parse(uri).normalize
|
73
82
|
else
|
74
83
|
raise ArgumentError,
|
75
84
|
"bad argument (expected #{uri_adapter} object or URI string)"
|
@@ -85,17 +94,17 @@ module HTTParty
|
|
85
94
|
end
|
86
95
|
|
87
96
|
def uri
|
88
|
-
if redirect && path.relative? && path.path[0] !=
|
89
|
-
last_uri_host = @last_uri.path.gsub(/[^\/]+$/,
|
97
|
+
if redirect && path.relative? && path.path[0] != '/'
|
98
|
+
last_uri_host = @last_uri.path.gsub(/[^\/]+$/, '')
|
90
99
|
|
91
|
-
path.path = "/#{path.path}" if last_uri_host[-1] !=
|
92
|
-
path.path = last_uri_host
|
100
|
+
path.path = "/#{path.path}" if last_uri_host[-1] != '/'
|
101
|
+
path.path = "#{last_uri_host}#{path.path}"
|
93
102
|
end
|
94
103
|
|
95
104
|
if path.relative? && path.host
|
96
|
-
new_uri = options[:uri_adapter].parse("#{@last_uri.scheme}:#{path}")
|
105
|
+
new_uri = options[:uri_adapter].parse("#{@last_uri.scheme}:#{path}").normalize
|
97
106
|
elsif path.relative?
|
98
|
-
new_uri = options[:uri_adapter].parse("#{base_uri}#{path}")
|
107
|
+
new_uri = options[:uri_adapter].parse("#{base_uri}#{path}").normalize
|
99
108
|
else
|
100
109
|
new_uri = path.clone
|
101
110
|
end
|
@@ -115,7 +124,7 @@ module HTTParty
|
|
115
124
|
def base_uri
|
116
125
|
if redirect
|
117
126
|
base_uri = "#{@last_uri.scheme}://#{@last_uri.host}"
|
118
|
-
base_uri
|
127
|
+
base_uri = "#{base_uri}:#{@last_uri.port}" if @last_uri.port != 80
|
119
128
|
base_uri
|
120
129
|
else
|
121
130
|
options[:base_uri] && HTTParty.normalize_base_uri(options[:base_uri])
|
@@ -138,21 +147,22 @@ module HTTParty
|
|
138
147
|
validate
|
139
148
|
setup_raw_request
|
140
149
|
chunked_body = nil
|
150
|
+
current_http = http
|
141
151
|
|
142
|
-
self.last_response =
|
152
|
+
self.last_response = current_http.request(@raw_request) do |http_response|
|
143
153
|
if block
|
144
154
|
chunks = []
|
145
155
|
|
146
156
|
http_response.read_body do |fragment|
|
147
|
-
|
148
|
-
|
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)
|
149
160
|
end
|
150
161
|
|
151
162
|
chunked_body = chunks.join
|
152
163
|
end
|
153
164
|
end
|
154
165
|
|
155
|
-
|
156
166
|
handle_host_redirection if response_redirects?
|
157
167
|
result = handle_unauthorized
|
158
168
|
result ||= handle_response(chunked_body, &block)
|
@@ -170,16 +180,19 @@ module HTTParty
|
|
170
180
|
@raw_request.body
|
171
181
|
end
|
172
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
|
+
|
173
190
|
private
|
174
191
|
|
175
192
|
def http
|
176
193
|
connection_adapter.call(uri, options)
|
177
194
|
end
|
178
195
|
|
179
|
-
def body
|
180
|
-
options[:body].respond_to?(:to_hash) ? normalize_query(options[:body]) : options[:body]
|
181
|
-
end
|
182
|
-
|
183
196
|
def credentials
|
184
197
|
(options[:basic_auth] || options[:digest_auth]).to_hash
|
185
198
|
end
|
@@ -205,21 +218,31 @@ 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 = body if body
|
210
|
-
@raw_request.body_stream = options[:body_stream] if options[:body_stream]
|
211
221
|
if options[:headers].respond_to?(:to_hash)
|
212
222
|
headers_hash = options[:headers].to_hash
|
223
|
+
else
|
224
|
+
headers_hash = nil
|
225
|
+
end
|
213
226
|
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
227
|
+
@raw_request = http_method.new(request_uri(uri), headers_hash)
|
228
|
+
@raw_request.body_stream = options[:body_stream] if options[:body_stream]
|
229
|
+
|
230
|
+
if options[:body]
|
231
|
+
body = Body.new(
|
232
|
+
options[:body],
|
233
|
+
query_string_normalizer: query_string_normalizer,
|
234
|
+
force_multipart: options[:multipart]
|
235
|
+
)
|
236
|
+
|
237
|
+
if body.multipart?
|
238
|
+
content_type = "multipart/form-data; boundary=#{body.boundary}"
|
239
|
+
@raw_request['Content-Type'] = content_type
|
221
240
|
end
|
241
|
+
@raw_request.body = body.call
|
222
242
|
end
|
243
|
+
|
244
|
+
@raw_request.instance_variable_set(:@decode_content, decompress_content?)
|
245
|
+
|
223
246
|
if options[:basic_auth] && send_authorization_header?
|
224
247
|
@raw_request.basic_auth(username, password)
|
225
248
|
@credentials_sent = true
|
@@ -231,6 +254,10 @@ module HTTParty
|
|
231
254
|
!!options[:digest_auth]
|
232
255
|
end
|
233
256
|
|
257
|
+
def decompress_content?
|
258
|
+
!options[:skip_decompression]
|
259
|
+
end
|
260
|
+
|
234
261
|
def response_unauthorized?
|
235
262
|
!!last_response && last_response.code == '401'
|
236
263
|
end
|
@@ -254,78 +281,15 @@ module HTTParty
|
|
254
281
|
query_string_parts << options[:query] unless options[:query].nil?
|
255
282
|
end
|
256
283
|
|
257
|
-
query_string_parts.reject!(&:empty?) unless query_string_parts == [
|
284
|
+
query_string_parts.reject!(&:empty?) unless query_string_parts == ['']
|
258
285
|
query_string_parts.size > 0 ? query_string_parts.join('&') : nil
|
259
286
|
end
|
260
287
|
|
261
|
-
def get_charset
|
262
|
-
content_type = last_response["content-type"]
|
263
|
-
if content_type.nil?
|
264
|
-
return nil
|
265
|
-
end
|
266
|
-
|
267
|
-
if content_type =~ /;\s*charset\s*=\s*([^=,;"\s]+)/i
|
268
|
-
return $1
|
269
|
-
end
|
270
|
-
|
271
|
-
if content_type =~ /;\s*charset\s*=\s*"((\\.|[^\\"])+)"/i
|
272
|
-
return $1.gsub(/\\(.)/, '\1')
|
273
|
-
end
|
274
|
-
|
275
|
-
nil
|
276
|
-
end
|
277
|
-
|
278
|
-
def encode_with_ruby_encoding(body, charset)
|
279
|
-
if !body.nil? && Encoding.name_list.include?(charset)
|
280
|
-
body.force_encoding(charset)
|
281
|
-
else
|
282
|
-
body
|
283
|
-
end
|
284
|
-
end
|
285
|
-
|
286
288
|
def assume_utf16_is_big_endian
|
287
289
|
options[:assume_utf16_is_big_endian]
|
288
290
|
end
|
289
291
|
|
290
|
-
def
|
291
|
-
if body.bytesize >= 2
|
292
|
-
if body.getbyte(0) == 0xFF && body.getbyte(1) == 0xFE
|
293
|
-
return body.force_encoding("UTF-16LE")
|
294
|
-
elsif body.getbyte(0) == 0xFE && body.getbyte(1) == 0xFF
|
295
|
-
return body.force_encoding("UTF-16BE")
|
296
|
-
end
|
297
|
-
end
|
298
|
-
|
299
|
-
if assume_utf16_is_big_endian
|
300
|
-
body.force_encoding("UTF-16BE")
|
301
|
-
else
|
302
|
-
body.force_encoding("UTF-16LE")
|
303
|
-
end
|
304
|
-
end
|
305
|
-
|
306
|
-
def _encode_body(body)
|
307
|
-
charset = get_charset
|
308
|
-
|
309
|
-
if charset.nil?
|
310
|
-
return body
|
311
|
-
end
|
312
|
-
|
313
|
-
if "utf-16".casecmp(charset) == 0
|
314
|
-
encode_utf_16(body)
|
315
|
-
else
|
316
|
-
encode_with_ruby_encoding(body, charset)
|
317
|
-
end
|
318
|
-
end
|
319
|
-
|
320
|
-
def encode_body(body)
|
321
|
-
if "".respond_to?(:encoding)
|
322
|
-
_encode_body(body)
|
323
|
-
else
|
324
|
-
body
|
325
|
-
end
|
326
|
-
end
|
327
|
-
|
328
|
-
def handle_response(body, &block)
|
292
|
+
def handle_response(raw_body, &block)
|
329
293
|
if response_redirects?
|
330
294
|
options[:limit] -= 1
|
331
295
|
if options[:logger]
|
@@ -346,15 +310,26 @@ module HTTParty
|
|
346
310
|
capture_cookies(last_response)
|
347
311
|
perform(&block)
|
348
312
|
else
|
349
|
-
|
350
|
-
|
351
|
-
|
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)
|
352
327
|
end
|
353
328
|
end
|
354
329
|
|
355
330
|
def handle_host_redirection
|
356
331
|
check_duplicate_location_header
|
357
|
-
redirect_path = options[:uri_adapter].parse
|
332
|
+
redirect_path = options[:uri_adapter].parse(last_response['location']).normalize
|
358
333
|
return if redirect_path.relative? || path.host == redirect_path.host
|
359
334
|
@changed_hosts = true
|
360
335
|
end
|
@@ -423,5 +398,17 @@ module HTTParty
|
|
423
398
|
@credentials_sent = true
|
424
399
|
end
|
425
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
|
426
413
|
end
|
427
414
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'delegate'
|
2
4
|
|
3
5
|
module HTTParty
|
@@ -22,10 +24,10 @@ module HTTParty
|
|
22
24
|
end
|
23
25
|
|
24
26
|
def ==(other)
|
25
|
-
if other.is_a?(::Net::HTTPHeader)
|
27
|
+
if other.is_a?(::Net::HTTPHeader)
|
26
28
|
@header == other.instance_variable_get(:@header)
|
27
29
|
elsif other.is_a?(Hash)
|
28
|
-
@header == other || @header == Headers.new(other).instance_variable_get(:@header)
|
30
|
+
@header == other || @header == Headers.new(other).instance_variable_get(:@header)
|
29
31
|
end
|
30
32
|
end
|
31
33
|
end
|