excon 0.99.0 → 1.2.5
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 +4 -4
- data/README.md +24 -2
- data/data/cacert.pem +545 -275
- data/excon.gemspec +24 -17
- data/lib/excon/connection.rb +27 -14
- data/lib/excon/constants.rb +122 -113
- data/lib/excon/error.rb +2 -2
- data/lib/excon/middlewares/capture_cookies.rb +1 -1
- data/lib/excon/middlewares/decompress.rb +17 -22
- data/lib/excon/middlewares/redirect_follower.rb +3 -3
- data/lib/excon/response.rb +4 -4
- data/lib/excon/socket.rb +115 -25
- data/lib/excon/ssl_socket.rb +3 -2
- data/lib/excon/test/plugin/server/puma.rb +1 -1
- data/lib/excon/test/plugin/server/unicorn.rb +5 -5
- data/lib/excon/test/plugin/server/webrick.rb +1 -1
- data/lib/excon/test/server.rb +1 -3
- data/lib/excon/unix_socket.rb +1 -1
- data/lib/excon/utils.rb +39 -36
- data/lib/excon/version.rb +2 -1
- data/lib/excon.rb +39 -47
- metadata +49 -20
data/excon.gemspec
CHANGED
@@ -1,44 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
$LOAD_PATH.unshift File.join(File.dirname(__FILE__), 'lib')
|
2
4
|
require 'excon/version'
|
3
5
|
|
4
6
|
Gem::Specification.new do |s|
|
5
7
|
s.name = 'excon'
|
6
8
|
s.version = Excon::VERSION
|
7
|
-
s.summary =
|
8
|
-
s.description =
|
9
|
-
s.authors = [
|
9
|
+
s.summary = 'speed, persistence, http(s)'
|
10
|
+
s.description = 'EXtended http(s) CONnections'
|
11
|
+
s.authors = ['dpiddy (Dan Peterson)', 'geemus (Wesley Beary)', 'nextmat (Matt Sanders)']
|
10
12
|
s.email = 'geemus@gmail.com'
|
11
13
|
s.homepage = 'https://github.com/excon/excon'
|
12
14
|
s.license = 'MIT'
|
13
|
-
s.rdoc_options = [
|
15
|
+
s.rdoc_options = ['--charset=UTF-8']
|
14
16
|
s.extra_rdoc_files = %w[README.md CONTRIBUTORS.md CONTRIBUTING.md]
|
15
17
|
s.files = `git ls-files -- data/* lib/*`.split("\n") + [
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
18
|
+
'CONTRIBUTING.md',
|
19
|
+
'CONTRIBUTORS.md',
|
20
|
+
'LICENSE.md',
|
21
|
+
'README.md',
|
22
|
+
'excon.gemspec'
|
21
23
|
]
|
24
|
+
s.required_ruby_version = '>= 2.7.0'
|
25
|
+
|
26
|
+
s.add_dependency 'logger'
|
22
27
|
|
23
|
-
s.add_development_dependency('rspec', '>= 3.5.0')
|
24
28
|
s.add_development_dependency('activesupport')
|
25
29
|
s.add_development_dependency('delorean')
|
26
30
|
s.add_development_dependency('eventmachine', '>= 1.0.4')
|
31
|
+
s.add_development_dependency('json', '>= 1.8.5')
|
27
32
|
s.add_development_dependency('open4')
|
33
|
+
s.add_development_dependency('puma')
|
28
34
|
s.add_development_dependency('rake')
|
35
|
+
s.add_development_dependency('rdoc')
|
36
|
+
s.add_development_dependency('rspec', '>= 3.5.0')
|
29
37
|
s.add_development_dependency('shindo')
|
30
38
|
s.add_development_dependency('sinatra')
|
31
39
|
s.add_development_dependency('sinatra-contrib')
|
32
|
-
s.add_development_dependency('json', '>= 1.8.5')
|
33
|
-
s.add_development_dependency('puma')
|
34
40
|
s.add_development_dependency('webrick')
|
35
41
|
|
36
42
|
s.metadata = {
|
37
|
-
'
|
38
|
-
'
|
39
|
-
'changelog_uri' => 'https://github.com/excon/excon/blob/master/changelog.txt',
|
43
|
+
'bug_tracker_uri' => 'https://github.com/excon/excon/issues',
|
44
|
+
'changelog_uri' => 'https://github.com/excon/excon/blob/master/changelog.txt',
|
40
45
|
'documentation_uri' => 'https://github.com/excon/excon/blob/master/README.md',
|
41
|
-
'
|
42
|
-
'
|
46
|
+
'funding_uri' => 'https://github.com/sponsors/geemus',
|
47
|
+
'homepage_uri' => 'https://github.com/excon/excon',
|
48
|
+
'source_code_uri' => 'https://github.com/excon/excon',
|
49
|
+
'wiki_uri' => 'https://github.com/excon/excon/wiki'
|
43
50
|
}
|
44
51
|
end
|
data/lib/excon/connection.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
require 'ipaddr'
|
3
2
|
|
4
3
|
module Excon
|
5
4
|
class Connection
|
@@ -139,7 +138,7 @@ module Excon
|
|
139
138
|
|
140
139
|
# The HTTP spec isn't clear on it, but specifically, GET requests don't usually send bodies;
|
141
140
|
# if they don't, sending Content-Length:0 can cause issues.
|
142
|
-
unless datum[:method].to_s.casecmp('GET')
|
141
|
+
unless datum[:method].to_s.casecmp?('GET') && body.nil?
|
143
142
|
unless datum[:headers].has_key?('Content-Length')
|
144
143
|
datum[:headers]['Content-Length'] = detect_content_length(body)
|
145
144
|
end
|
@@ -160,7 +159,7 @@ module Excon
|
|
160
159
|
if chunk.length > 0
|
161
160
|
socket(datum).write(chunk.length.to_s(16) << CR_NL << chunk << CR_NL)
|
162
161
|
else
|
163
|
-
socket(datum).write(
|
162
|
+
socket(datum).write("0#{CR_NL}#{CR_NL}")
|
164
163
|
break
|
165
164
|
end
|
166
165
|
end
|
@@ -195,7 +194,7 @@ module Excon
|
|
195
194
|
raise(error)
|
196
195
|
when Errno::EPIPE
|
197
196
|
# Read whatever remains in the pipe to aid in debugging
|
198
|
-
response = socket.read
|
197
|
+
response = socket.read rescue ""
|
199
198
|
error = Excon::Error.new(response + error.message)
|
200
199
|
raise_socket_error(error)
|
201
200
|
else
|
@@ -230,6 +229,13 @@ module Excon
|
|
230
229
|
def request(params={}, &block)
|
231
230
|
# @data has defaults, merge in new params to override
|
232
231
|
datum = @data.merge(params)
|
232
|
+
|
233
|
+
# Set the deadline for the current request in order to determine when we have run out of time.
|
234
|
+
# Only set when a request timeout has been defined.
|
235
|
+
if datum[:timeout]
|
236
|
+
datum[:deadline] = Process.clock_gettime(Process::CLOCK_MONOTONIC) + datum[:timeout]
|
237
|
+
end
|
238
|
+
|
233
239
|
datum[:headers] = @data[:headers].merge(datum[:headers] || {})
|
234
240
|
|
235
241
|
validate_params(:request, params, datum[:middlewares])
|
@@ -244,16 +250,17 @@ module Excon
|
|
244
250
|
datum[:headers]['Authorization'] ||= 'Basic ' + ["#{user}:#{pass}"].pack('m').delete(Excon::CR_NL)
|
245
251
|
end
|
246
252
|
|
253
|
+
host_key = datum[:headers].keys.detect {|k| k.casecmp?('Host') } || 'Host'
|
247
254
|
if datum[:scheme] == UNIX
|
248
|
-
datum[:headers][
|
255
|
+
datum[:headers][host_key] ||= ''
|
249
256
|
else
|
250
|
-
datum[:headers][
|
257
|
+
datum[:headers][host_key] ||= datum[:host] + port_string(datum)
|
251
258
|
end
|
252
259
|
|
253
260
|
# RFC 7230, section 5.4, states that the Host header SHOULD be the first one # to be present.
|
254
261
|
# Some web servers will reject the request if it comes too late, so let's hoist it to the top.
|
255
|
-
if (host = datum[:headers].delete(
|
256
|
-
datum[:headers] = {
|
262
|
+
if (host = datum[:headers].delete(host_key))
|
263
|
+
datum[:headers] = { host_key => host }.merge(datum[:headers])
|
257
264
|
end
|
258
265
|
|
259
266
|
# default to GET if no method specified
|
@@ -291,8 +298,8 @@ module Excon
|
|
291
298
|
@persistent_socket_reusable = true
|
292
299
|
|
293
300
|
if datum[:persistent]
|
294
|
-
if (key = datum[:response][:headers].keys.detect {|k| k.casecmp('Connection')
|
295
|
-
if datum[:response][:headers][key].casecmp('close')
|
301
|
+
if (key = datum[:response][:headers].keys.detect {|k| k.casecmp?('Connection') })
|
302
|
+
if datum[:response][:headers][key].casecmp?('close')
|
296
303
|
reset
|
297
304
|
end
|
298
305
|
end
|
@@ -322,7 +329,7 @@ module Excon
|
|
322
329
|
# @param pipeline_params [Array<Hash>] An array of one or more optional params, override defaults set in Connection.new, see #request for details
|
323
330
|
def requests(pipeline_params)
|
324
331
|
pipeline_params.each {|params| params.merge!(:pipeline => true, :persistent => true) }
|
325
|
-
pipeline_params.last
|
332
|
+
pipeline_params.last[:persistent] = @data[:persistent]
|
326
333
|
|
327
334
|
responses = pipeline_params.map do |params|
|
328
335
|
request(params)
|
@@ -331,8 +338,8 @@ module Excon
|
|
331
338
|
end
|
332
339
|
|
333
340
|
if @data[:persistent]
|
334
|
-
if (key = responses.last[:headers].keys.detect {|k| k.casecmp('Connection')
|
335
|
-
if responses.last[:headers][key].casecmp('close')
|
341
|
+
if (key = responses.last[:headers].keys.detect {|k| k.casecmp?('Connection') })
|
342
|
+
if responses.last[:headers][key].casecmp?('close')
|
336
343
|
reset
|
337
344
|
end
|
338
345
|
end
|
@@ -439,6 +446,12 @@ module Excon
|
|
439
446
|
raise ArgumentError.new("Invalid validation type '#{validation}'")
|
440
447
|
end
|
441
448
|
|
449
|
+
if validation == :connection && params[:omit_default_port] != true
|
450
|
+
Excon.display_warning(
|
451
|
+
'The `omit_default_port` connection option is deprecated, please use `include_default_port` instead.'
|
452
|
+
)
|
453
|
+
end
|
454
|
+
|
442
455
|
invalid_keys = params.keys - valid_keys
|
443
456
|
unless invalid_keys.empty?
|
444
457
|
Excon.display_warning("Invalid Excon #{validation} keys: #{invalid_keys.map(&:inspect).join(', ')}")
|
@@ -498,7 +511,7 @@ module Excon
|
|
498
511
|
end
|
499
512
|
|
500
513
|
def raise_socket_error(error)
|
501
|
-
if error.message
|
514
|
+
if error.message.include?('certificate verify failed')
|
502
515
|
raise(Excon::Errors::CertificateError.new(error))
|
503
516
|
else
|
504
517
|
raise(Excon::Errors::SocketError.new(error))
|
data/lib/excon/constants.rb
CHANGED
@@ -1,32 +1,31 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
module Excon
|
3
|
-
|
4
3
|
CR_NL = "\r\n"
|
5
4
|
|
6
|
-
DEFAULT_CA_FILE = File.expand_path(File.join(File.dirname(__FILE__),
|
5
|
+
DEFAULT_CA_FILE = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'data', 'cacert.pem'))
|
7
6
|
|
8
|
-
DEFAULT_CHUNK_SIZE =
|
7
|
+
DEFAULT_CHUNK_SIZE = 1_048_576 # 1 megabyte
|
9
8
|
|
10
9
|
# avoid overwrite if somebody has redefined
|
11
|
-
unless const_defined?(:CHUNK_SIZE)
|
12
|
-
CHUNK_SIZE = DEFAULT_CHUNK_SIZE
|
13
|
-
end
|
10
|
+
CHUNK_SIZE = DEFAULT_CHUNK_SIZE unless const_defined?(:CHUNK_SIZE)
|
14
11
|
|
15
12
|
DEFAULT_REDIRECT_LIMIT = 10
|
16
13
|
|
17
14
|
DEFAULT_RETRY_LIMIT = 4
|
18
15
|
|
19
16
|
DEFAULT_RETRY_ERRORS = [
|
20
|
-
Excon::Error::
|
17
|
+
Excon::Error::RequestTimeout,
|
18
|
+
Excon::Error::Server,
|
21
19
|
Excon::Error::Socket,
|
22
|
-
Excon::Error::
|
23
|
-
|
20
|
+
Excon::Error::Timeout,
|
21
|
+
Excon::Error::TooManyRequests
|
22
|
+
].freeze
|
24
23
|
|
25
24
|
FORCE_ENC = CR_NL.respond_to?(:force_encoding)
|
26
25
|
|
27
26
|
HTTP_1_1 = " HTTP/1.1\r\n"
|
28
27
|
|
29
|
-
HTTP_VERBS = %w
|
28
|
+
HTTP_VERBS = %w[connect delete get head options patch post put trace].freeze
|
30
29
|
|
31
30
|
HTTPS = 'https'
|
32
31
|
|
@@ -40,86 +39,91 @@ module Excon
|
|
40
39
|
|
41
40
|
VERSIONS = "#{USER_AGENT} (#{RUBY_PLATFORM}) ruby/#{RUBY_VERSION}"
|
42
41
|
|
43
|
-
VALID_REQUEST_KEYS = [
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
42
|
+
VALID_REQUEST_KEYS = %i[
|
43
|
+
allow_unstubbed_requests
|
44
|
+
body
|
45
|
+
chunk_size
|
46
|
+
debug_request
|
47
|
+
debug_response
|
48
|
+
dns_timeouts
|
49
|
+
headers
|
50
|
+
instrumentor
|
51
|
+
logger
|
52
|
+
method
|
53
|
+
middlewares
|
54
|
+
password
|
55
|
+
path
|
56
|
+
persistent
|
57
|
+
pipeline
|
58
|
+
query
|
59
|
+
read_timeout
|
60
|
+
request_block
|
61
|
+
resolv_resolver
|
62
|
+
response_block
|
63
|
+
stubs
|
64
|
+
timeout
|
65
|
+
user
|
66
|
+
versions
|
67
|
+
write_timeout
|
68
|
+
].freeze
|
69
|
+
|
70
|
+
VALID_CONNECTION_KEYS = VALID_REQUEST_KEYS + %i[
|
71
|
+
ciphers
|
72
|
+
client_key
|
73
|
+
client_key_data
|
74
|
+
client_key_pass
|
75
|
+
client_cert
|
76
|
+
client_cert_data
|
77
|
+
client_chain
|
78
|
+
client_chain_data
|
79
|
+
certificate
|
80
|
+
certificate_path
|
81
|
+
disable_proxy
|
82
|
+
private_key
|
83
|
+
private_key_path
|
84
|
+
connect_timeout
|
85
|
+
family
|
86
|
+
keepalive
|
87
|
+
host
|
88
|
+
hostname
|
89
|
+
ignore_unexpected_eof
|
90
|
+
include_default_port
|
91
|
+
omit_default_port
|
92
|
+
nonblock
|
93
|
+
reuseaddr
|
94
|
+
port
|
95
|
+
proxy
|
96
|
+
scheme
|
97
|
+
socket
|
98
|
+
ssl_ca_file
|
99
|
+
ssl_ca_path
|
100
|
+
ssl_cert_store
|
101
|
+
ssl_verify_callback
|
102
|
+
ssl_verify_peer
|
103
|
+
ssl_verify_peer_host
|
104
|
+
ssl_verify_hostname
|
105
|
+
ssl_version
|
106
|
+
ssl_min_version
|
107
|
+
ssl_max_version
|
108
|
+
ssl_security_level
|
109
|
+
ssl_proxy_headers
|
110
|
+
ssl_uri_schemes
|
111
|
+
tcp_nodelay
|
112
|
+
thread_safe_sockets
|
113
|
+
uri_parser
|
110
114
|
]
|
111
115
|
|
112
116
|
DEPRECATED_VALID_REQUEST_KEYS = {
|
113
|
-
:
|
114
|
-
:
|
115
|
-
:
|
116
|
-
:
|
117
|
-
:
|
118
|
-
:
|
119
|
-
:
|
120
|
-
:
|
121
|
-
:
|
122
|
-
}
|
117
|
+
captures: 'Mock',
|
118
|
+
expects: 'Expects',
|
119
|
+
idempotent: 'Idempotent',
|
120
|
+
instrumentor_name: 'Instrumentor',
|
121
|
+
mock: 'Mock',
|
122
|
+
retries_remaining: 'Idempotent', # referenced in Instrumentor, but only relevant with Idempotent
|
123
|
+
retry_errors: 'Idempotent',
|
124
|
+
retry_interval: 'Idempotent',
|
125
|
+
retry_limit: 'Idempotent' # referenced in Instrumentor, but only relevant with Idempotent
|
126
|
+
}.freeze
|
123
127
|
|
124
128
|
unless ::IO.const_defined?(:WaitReadable)
|
125
129
|
class ::IO
|
@@ -132,43 +136,48 @@ module Excon
|
|
132
136
|
module WaitWritable; end
|
133
137
|
end
|
134
138
|
end
|
139
|
+
|
135
140
|
# these come last as they rely on the above
|
136
141
|
DEFAULTS = {
|
137
|
-
:
|
142
|
+
chunk_size: CHUNK_SIZE || DEFAULT_CHUNK_SIZE,
|
138
143
|
# see https://wiki.mozilla.org/Security/Server_Side_TLS#Intermediate_compatibility_.28default.29
|
139
144
|
# list provided then had DES related things sorted to the end
|
140
|
-
:
|
141
|
-
:
|
142
|
-
:
|
143
|
-
:
|
144
|
-
:
|
145
|
+
ciphers: 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:DES-CBC3-SHA:!DSS',
|
146
|
+
connect_timeout: 60,
|
147
|
+
debug_request: false,
|
148
|
+
debug_response: false,
|
149
|
+
dns_timeouts: nil, # nil allows Resolv::DNS default timeout value (see https://ruby-doc.org/3.2.2/stdlibs/resolv/Resolv/DNS.html#method-i-timeouts-3D)
|
150
|
+
headers: {
|
145
151
|
'User-Agent' => USER_AGENT,
|
146
|
-
'Accept'
|
152
|
+
'Accept' => '*/*'
|
147
153
|
},
|
148
|
-
:
|
149
|
-
:
|
150
|
-
:
|
154
|
+
idempotent: false,
|
155
|
+
instrumentor_name: 'excon',
|
156
|
+
middlewares: [
|
151
157
|
Excon::Middleware::ResponseParser,
|
158
|
+
Excon::Middleware::Decompress,
|
152
159
|
Excon::Middleware::Expects,
|
153
160
|
Excon::Middleware::Idempotent,
|
154
161
|
Excon::Middleware::Instrumentor,
|
155
162
|
Excon::Middleware::Mock
|
156
163
|
],
|
157
|
-
:
|
158
|
-
:
|
159
|
-
:
|
160
|
-
:
|
161
|
-
:
|
162
|
-
:
|
163
|
-
:
|
164
|
-
:
|
165
|
-
:
|
166
|
-
:
|
167
|
-
:
|
168
|
-
:
|
169
|
-
:
|
170
|
-
:
|
171
|
-
:
|
164
|
+
mock: false,
|
165
|
+
include_default_port: false,
|
166
|
+
nonblock: true,
|
167
|
+
omit_default_port: true,
|
168
|
+
persistent: false,
|
169
|
+
read_timeout: 60,
|
170
|
+
resolv_resolver: nil,
|
171
|
+
retry_errors: DEFAULT_RETRY_ERRORS,
|
172
|
+
retry_limit: DEFAULT_RETRY_LIMIT,
|
173
|
+
ssl_verify_peer: true,
|
174
|
+
ssl_uri_schemes: [HTTPS],
|
175
|
+
stubs: :global,
|
176
|
+
tcp_nodelay: false,
|
177
|
+
thread_safe_sockets: true,
|
178
|
+
timeout: nil,
|
179
|
+
uri_parser: URI,
|
180
|
+
versions: VERSIONS,
|
181
|
+
write_timeout: 60
|
172
182
|
}
|
173
|
-
|
174
183
|
end
|
data/lib/excon/error.rb
CHANGED
@@ -216,8 +216,8 @@ or:
|
|
216
216
|
|
217
217
|
klasses.each do |klass|
|
218
218
|
class_name = klass.to_s
|
219
|
-
unless class_name
|
220
|
-
class_name = klass.to_s + 'Error' if class_name
|
219
|
+
unless class_name.match?(/Error\Z/)
|
220
|
+
class_name = klass.to_s + 'Error' if class_name.match?(legacy_re)
|
221
221
|
end
|
222
222
|
Excon::Errors.const_set(class_name, Excon::Error.const_get(klass))
|
223
223
|
end
|
@@ -1,41 +1,36 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module Excon
|
3
4
|
module Middleware
|
4
5
|
class Decompress < Excon::Middleware::Base
|
5
|
-
|
6
6
|
INFLATE_ZLIB_OR_GZIP = 47 # Zlib::MAX_WBITS + 32
|
7
7
|
INFLATE_RAW = -15 # Zlib::MAX_WBITS * -1
|
8
8
|
|
9
9
|
def request_call(datum)
|
10
|
-
unless datum.
|
11
|
-
key = datum[:headers].keys.detect {|k| k.to_s.casecmp('Accept-Encoding')
|
12
|
-
if datum[:headers][key].to_s.empty?
|
13
|
-
datum[:headers][key] = 'deflate, gzip'
|
14
|
-
end
|
10
|
+
unless datum.key?(:response_block)
|
11
|
+
key = datum[:headers].keys.detect { |k| k.to_s.casecmp?('Accept-Encoding') } || 'Accept-Encoding'
|
12
|
+
datum[:headers][key] = 'deflate, gzip' if datum[:headers][key].to_s.empty?
|
15
13
|
end
|
16
14
|
@stack.request_call(datum)
|
17
15
|
end
|
18
16
|
|
19
17
|
def response_call(datum)
|
20
18
|
body = datum[:response][:body]
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
Zlib::Inflate.new(INFLATE_RAW).inflate(body)
|
30
|
-
end
|
31
|
-
encodings.pop
|
32
|
-
elsif encoding.casecmp('gzip') == 0 || encoding.casecmp('x-gzip') == 0
|
33
|
-
datum[:response][:body] = Zlib::GzipReader.new(StringIO.new(body)).read
|
34
|
-
encodings.pop
|
35
|
-
end
|
36
|
-
datum[:response][:headers][key] = encodings.join(', ')
|
19
|
+
if !(datum.key?(:response_block) || body.nil? || body.empty?) &&
|
20
|
+
(key = datum[:response][:headers].keys.detect { |k| k.casecmp?('Content-Encoding') })
|
21
|
+
encodings = Utils.split_header_value(datum[:response][:headers][key])
|
22
|
+
if encodings&.last&.casecmp?('deflate')
|
23
|
+
datum[:response][:body] = begin
|
24
|
+
Zlib::Inflate.new(INFLATE_ZLIB_OR_GZIP).inflate(body)
|
25
|
+
rescue Zlib::DataError # fallback to raw on error
|
26
|
+
Zlib::Inflate.new(INFLATE_RAW).inflate(body)
|
37
27
|
end
|
28
|
+
encodings.pop
|
29
|
+
elsif encodings&.last&.casecmp?('gzip') || encodings&.last&.casecmp?('x-gzip')
|
30
|
+
datum[:response][:body] = Zlib::GzipReader.new(StringIO.new(body)).read
|
31
|
+
encodings.pop
|
38
32
|
end
|
33
|
+
datum[:response][:headers][key] = encodings.join(', ')
|
39
34
|
end
|
40
35
|
@stack.response_call(datum)
|
41
36
|
end
|
@@ -17,7 +17,7 @@ module Excon
|
|
17
17
|
|
18
18
|
def get_header(datum, header)
|
19
19
|
_, header_value = datum[:response][:headers].detect do |key, _|
|
20
|
-
key.casecmp(header)
|
20
|
+
key.casecmp?(header)
|
21
21
|
end
|
22
22
|
header_value
|
23
23
|
end
|
@@ -67,8 +67,8 @@ module Excon
|
|
67
67
|
:query => uri.query
|
68
68
|
)
|
69
69
|
|
70
|
-
params
|
71
|
-
params
|
70
|
+
params[:user] = Utils.unescape_uri(uri.user) if uri.user
|
71
|
+
params[:password] = Utils.unescape_uri(uri.password) if uri.password
|
72
72
|
|
73
73
|
response = Excon::Connection.new(params).request
|
74
74
|
datum.merge!({
|
data/lib/excon/response.rb
CHANGED
@@ -106,9 +106,9 @@ module Excon
|
|
106
106
|
|
107
107
|
unless (['HEAD', 'CONNECT'].include?(datum[:method].to_s.upcase)) || NO_ENTITY.include?(datum[:response][:status])
|
108
108
|
|
109
|
-
if (key = datum[:response][:headers].keys.detect {|k| k.casecmp('Transfer-Encoding')
|
109
|
+
if (key = datum[:response][:headers].keys.detect {|k| k.casecmp?('Transfer-Encoding') })
|
110
110
|
encodings = Utils.split_header_value(datum[:response][:headers][key])
|
111
|
-
if (encoding = encodings.last) && encoding.casecmp('chunked')
|
111
|
+
if (encoding = encodings.last) && encoding.casecmp?('chunked')
|
112
112
|
transfer_encoding_chunked = true
|
113
113
|
if encodings.length == 1
|
114
114
|
datum[:response][:headers].delete(key)
|
@@ -156,7 +156,7 @@ module Excon
|
|
156
156
|
end
|
157
157
|
parse_headers(socket, datum) # merge trailers into headers
|
158
158
|
else
|
159
|
-
if (key = datum[:response][:headers].keys.detect {|k| k.casecmp('Content-Length')
|
159
|
+
if (key = datum[:response][:headers].keys.detect {|k| k.casecmp?('Content-Length') })
|
160
160
|
content_length = datum[:response][:headers][key].to_i
|
161
161
|
end
|
162
162
|
|
@@ -202,7 +202,7 @@ module Excon
|
|
202
202
|
raise Excon::Error::ResponseParse, 'malformed header' unless value
|
203
203
|
# add key/value or append value to existing values
|
204
204
|
datum[:response][:headers][key] = ([datum[:response][:headers][key]] << value.strip).compact.join(', ')
|
205
|
-
if key.casecmp('Set-Cookie')
|
205
|
+
if key.casecmp?('Set-Cookie')
|
206
206
|
datum[:response][:cookies] << value.strip
|
207
207
|
end
|
208
208
|
last_key = key
|