httparty 0.15.6 → 0.21.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.
- checksums.yaml +5 -5
- data/.editorconfig +18 -0
- data/.github/workflows/ci.yml +26 -0
- data/.gitignore +2 -0
- data/.rubocop_todo.yml +1 -1
- data/Changelog.md +105 -0
- data/Gemfile +7 -0
- data/Guardfile +3 -2
- data/README.md +6 -6
- data/docs/README.md +90 -5
- 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 +102 -0
- data/lib/httparty/exceptions.rb +3 -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 +21 -15
- data/lib/httparty/request/body.rb +105 -0
- data/lib/httparty/request/multipart_boundary.rb +13 -0
- data/lib/httparty/request.rb +86 -94
- 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 -25
- data/website/css/common.css +1 -1
- metadata +37 -103
- 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/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 -190
- data/spec/httparty/request_spec.rb +0 -1279
- data/spec/httparty/response_spec.rb +0 -347
- data/spec/httparty/ssl_spec.rb +0 -74
- data/spec/httparty_spec.rb +0 -878
- data/spec/spec_helper.rb +0 -51
- 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,7 +103,7 @@ 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
109
|
@body = body.gsub(/\A#{UTF8_BOM}/, '')
|
@@ -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,105 @@
|
|
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
|
+
# https://html.spec.whatwg.org/#multipart-form-data
|
36
|
+
MULTIPART_FORM_DATA_REPLACEMENT_TABLE = {
|
37
|
+
'"' => '%22',
|
38
|
+
"\r" => '%0D',
|
39
|
+
"\n" => '%0A'
|
40
|
+
}.freeze
|
41
|
+
|
42
|
+
def generate_multipart
|
43
|
+
normalized_params = params.flat_map { |key, value| HashConversions.normalize_keys(key, value) }
|
44
|
+
|
45
|
+
multipart = normalized_params.inject(''.dup) do |memo, (key, value)|
|
46
|
+
memo << "--#{boundary}#{NEWLINE}"
|
47
|
+
memo << %(Content-Disposition: form-data; name="#{key}")
|
48
|
+
# value.path is used to support ActionDispatch::Http::UploadedFile
|
49
|
+
# https://github.com/jnunemaker/httparty/pull/585
|
50
|
+
memo << %(; filename="#{file_name(value).gsub(/["\r\n]/, MULTIPART_FORM_DATA_REPLACEMENT_TABLE)}") if file?(value)
|
51
|
+
memo << NEWLINE
|
52
|
+
memo << "Content-Type: #{content_type(value)}#{NEWLINE}" if file?(value)
|
53
|
+
memo << NEWLINE
|
54
|
+
memo << content_body(value)
|
55
|
+
memo << NEWLINE
|
56
|
+
end
|
57
|
+
|
58
|
+
multipart << "--#{boundary}--#{NEWLINE}"
|
59
|
+
end
|
60
|
+
|
61
|
+
def has_file?(value)
|
62
|
+
if value.respond_to?(:to_hash)
|
63
|
+
value.to_hash.any? { |_, v| has_file?(v) }
|
64
|
+
elsif value.respond_to?(:to_ary)
|
65
|
+
value.to_ary.any? { |v| has_file?(v) }
|
66
|
+
else
|
67
|
+
file?(value)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def file?(object)
|
72
|
+
object.respond_to?(:path) && object.respond_to?(:read)
|
73
|
+
end
|
74
|
+
|
75
|
+
def normalize_query(query)
|
76
|
+
if query_string_normalizer
|
77
|
+
query_string_normalizer.call(query)
|
78
|
+
else
|
79
|
+
HashConversions.to_params(query)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def content_body(object)
|
84
|
+
if file?(object)
|
85
|
+
object = (file = object).read
|
86
|
+
file.rewind if file.respond_to?(:rewind)
|
87
|
+
end
|
88
|
+
|
89
|
+
object.to_s
|
90
|
+
end
|
91
|
+
|
92
|
+
def content_type(object)
|
93
|
+
return object.content_type if object.respond_to?(:content_type)
|
94
|
+
mime = MiniMime.lookup_by_filename(object.path)
|
95
|
+
mime ? mime.content_type : 'application/octet-stream'
|
96
|
+
end
|
97
|
+
|
98
|
+
def file_name(object)
|
99
|
+
object.respond_to?(:original_filename) ? object.original_filename : File.basename(object.path)
|
100
|
+
end
|
101
|
+
|
102
|
+
attr_reader :params, :query_string_normalizer, :force_multipart
|
103
|
+
end
|
104
|
+
end
|
105
|
+
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,15 @@ module HTTParty
|
|
42
46
|
end.flatten.join('&')
|
43
47
|
end
|
44
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
|
+
|
45
58
|
attr_accessor :http_method, :options, :last_response, :redirect, :last_uri
|
46
59
|
attr_reader :path
|
47
60
|
|
@@ -69,7 +82,7 @@ module HTTParty
|
|
69
82
|
@path = if uri.is_a?(uri_adapter)
|
70
83
|
uri
|
71
84
|
elsif String.try_convert(uri)
|
72
|
-
uri_adapter.parse
|
85
|
+
uri_adapter.parse(uri).normalize
|
73
86
|
else
|
74
87
|
raise ArgumentError,
|
75
88
|
"bad argument (expected #{uri_adapter} object or URI string)"
|
@@ -85,17 +98,17 @@ module HTTParty
|
|
85
98
|
end
|
86
99
|
|
87
100
|
def uri
|
88
|
-
if redirect && path.relative? && path.path[0] !=
|
89
|
-
last_uri_host = @last_uri.path.gsub(/[^\/]+$/,
|
101
|
+
if redirect && path.relative? && path.path[0] != '/'
|
102
|
+
last_uri_host = @last_uri.path.gsub(/[^\/]+$/, '')
|
90
103
|
|
91
|
-
path.path = "/#{path.path}" if last_uri_host[-1] !=
|
92
|
-
path.path = last_uri_host
|
104
|
+
path.path = "/#{path.path}" if last_uri_host[-1] != '/'
|
105
|
+
path.path = "#{last_uri_host}#{path.path}"
|
93
106
|
end
|
94
107
|
|
95
108
|
if path.relative? && path.host
|
96
|
-
new_uri = options[:uri_adapter].parse("#{@last_uri.scheme}:#{path}")
|
109
|
+
new_uri = options[:uri_adapter].parse("#{@last_uri.scheme}:#{path}").normalize
|
97
110
|
elsif path.relative?
|
98
|
-
new_uri = options[:uri_adapter].parse("#{base_uri}#{path}")
|
111
|
+
new_uri = options[:uri_adapter].parse("#{base_uri}#{path}").normalize
|
99
112
|
else
|
100
113
|
new_uri = path.clone
|
101
114
|
end
|
@@ -115,7 +128,7 @@ module HTTParty
|
|
115
128
|
def base_uri
|
116
129
|
if redirect
|
117
130
|
base_uri = "#{@last_uri.scheme}://#{@last_uri.host}"
|
118
|
-
base_uri
|
131
|
+
base_uri = "#{base_uri}:#{@last_uri.port}" if @last_uri.port != 80
|
119
132
|
base_uri
|
120
133
|
else
|
121
134
|
options[:base_uri] && HTTParty.normalize_base_uri(options[:base_uri])
|
@@ -138,21 +151,22 @@ module HTTParty
|
|
138
151
|
validate
|
139
152
|
setup_raw_request
|
140
153
|
chunked_body = nil
|
154
|
+
current_http = http
|
141
155
|
|
142
|
-
self.last_response =
|
156
|
+
self.last_response = current_http.request(@raw_request) do |http_response|
|
143
157
|
if block
|
144
158
|
chunks = []
|
145
159
|
|
146
160
|
http_response.read_body do |fragment|
|
147
|
-
|
148
|
-
|
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)
|
149
164
|
end
|
150
165
|
|
151
166
|
chunked_body = chunks.join
|
152
167
|
end
|
153
168
|
end
|
154
169
|
|
155
|
-
|
156
170
|
handle_host_redirection if response_redirects?
|
157
171
|
result = handle_unauthorized
|
158
172
|
result ||= handle_response(chunked_body, &block)
|
@@ -170,16 +184,19 @@ module HTTParty
|
|
170
184
|
@raw_request.body
|
171
185
|
end
|
172
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
|
+
|
173
194
|
private
|
174
195
|
|
175
196
|
def http
|
176
197
|
connection_adapter.call(uri, options)
|
177
198
|
end
|
178
199
|
|
179
|
-
def body
|
180
|
-
options[:body].respond_to?(:to_hash) ? normalize_query(options[:body]) : options[:body]
|
181
|
-
end
|
182
|
-
|
183
200
|
def credentials
|
184
201
|
(options[:basic_auth] || options[:digest_auth]).to_hash
|
185
202
|
end
|
@@ -205,21 +222,31 @@ module HTTParty
|
|
205
222
|
end
|
206
223
|
|
207
224
|
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
225
|
if options[:headers].respond_to?(:to_hash)
|
212
226
|
headers_hash = options[:headers].to_hash
|
227
|
+
else
|
228
|
+
headers_hash = nil
|
229
|
+
end
|
230
|
+
|
231
|
+
@raw_request = http_method.new(request_uri(uri), headers_hash)
|
232
|
+
@raw_request.body_stream = options[:body_stream] if options[:body_stream]
|
233
|
+
|
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
|
-
|
216
|
-
|
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']
|
241
|
+
if body.multipart?
|
242
|
+
content_type = "multipart/form-data; boundary=#{body.boundary}"
|
243
|
+
@raw_request['Content-Type'] = content_type
|
221
244
|
end
|
245
|
+
@raw_request.body = body.call
|
222
246
|
end
|
247
|
+
|
248
|
+
@raw_request.instance_variable_set(:@decode_content, decompress_content?)
|
249
|
+
|
223
250
|
if options[:basic_auth] && send_authorization_header?
|
224
251
|
@raw_request.basic_auth(username, password)
|
225
252
|
@credentials_sent = true
|
@@ -231,6 +258,10 @@ module HTTParty
|
|
231
258
|
!!options[:digest_auth]
|
232
259
|
end
|
233
260
|
|
261
|
+
def decompress_content?
|
262
|
+
!options[:skip_decompression]
|
263
|
+
end
|
264
|
+
|
234
265
|
def response_unauthorized?
|
235
266
|
!!last_response && last_response.code == '401'
|
236
267
|
end
|
@@ -254,77 +285,15 @@ module HTTParty
|
|
254
285
|
query_string_parts << options[:query] unless options[:query].nil?
|
255
286
|
end
|
256
287
|
|
257
|
-
query_string_parts.reject!(&:empty?) unless query_string_parts == [
|
288
|
+
query_string_parts.reject!(&:empty?) unless query_string_parts == ['']
|
258
289
|
query_string_parts.size > 0 ? query_string_parts.join('&') : nil
|
259
290
|
end
|
260
291
|
|
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
|
-
encoding = Encoding.find(charset)
|
280
|
-
body.force_encoding(charset)
|
281
|
-
rescue ArgumentError
|
282
|
-
body
|
283
|
-
end
|
284
|
-
|
285
292
|
def assume_utf16_is_big_endian
|
286
293
|
options[:assume_utf16_is_big_endian]
|
287
294
|
end
|
288
295
|
|
289
|
-
def
|
290
|
-
if body.bytesize >= 2
|
291
|
-
if body.getbyte(0) == 0xFF && body.getbyte(1) == 0xFE
|
292
|
-
return body.force_encoding("UTF-16LE")
|
293
|
-
elsif body.getbyte(0) == 0xFE && body.getbyte(1) == 0xFF
|
294
|
-
return body.force_encoding("UTF-16BE")
|
295
|
-
end
|
296
|
-
end
|
297
|
-
|
298
|
-
if assume_utf16_is_big_endian
|
299
|
-
body.force_encoding("UTF-16BE")
|
300
|
-
else
|
301
|
-
body.force_encoding("UTF-16LE")
|
302
|
-
end
|
303
|
-
end
|
304
|
-
|
305
|
-
def _encode_body(body)
|
306
|
-
charset = get_charset
|
307
|
-
|
308
|
-
if charset.nil?
|
309
|
-
return body
|
310
|
-
end
|
311
|
-
|
312
|
-
if "utf-16".casecmp(charset) == 0
|
313
|
-
encode_utf_16(body)
|
314
|
-
else
|
315
|
-
encode_with_ruby_encoding(body, charset)
|
316
|
-
end
|
317
|
-
end
|
318
|
-
|
319
|
-
def encode_body(body)
|
320
|
-
if "".respond_to?(:encoding)
|
321
|
-
_encode_body(body)
|
322
|
-
else
|
323
|
-
body
|
324
|
-
end
|
325
|
-
end
|
326
|
-
|
327
|
-
def handle_response(body, &block)
|
296
|
+
def handle_response(raw_body, &block)
|
328
297
|
if response_redirects?
|
329
298
|
options[:limit] -= 1
|
330
299
|
if options[:logger]
|
@@ -345,15 +314,26 @@ module HTTParty
|
|
345
314
|
capture_cookies(last_response)
|
346
315
|
perform(&block)
|
347
316
|
else
|
348
|
-
|
349
|
-
|
350
|
-
|
317
|
+
raw_body ||= last_response.body
|
318
|
+
|
319
|
+
body = decompress(raw_body, last_response['content-encoding']) unless raw_body.nil?
|
320
|
+
|
321
|
+
unless body.nil?
|
322
|
+
body = encode_text(body, last_response['content-type'])
|
323
|
+
|
324
|
+
if decompress_content?
|
325
|
+
last_response.delete('content-encoding')
|
326
|
+
raw_body = body
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
Response.new(self, last_response, lambda { parse_response(body) }, body: raw_body)
|
351
331
|
end
|
352
332
|
end
|
353
333
|
|
354
334
|
def handle_host_redirection
|
355
335
|
check_duplicate_location_header
|
356
|
-
redirect_path = options[:uri_adapter].parse
|
336
|
+
redirect_path = options[:uri_adapter].parse(last_response['location']).normalize
|
357
337
|
return if redirect_path.relative? || path.host == redirect_path.host
|
358
338
|
@changed_hosts = true
|
359
339
|
end
|
@@ -422,5 +402,17 @@ module HTTParty
|
|
422
402
|
@credentials_sent = true
|
423
403
|
end
|
424
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
|
425
417
|
end
|
426
418
|
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
|