excon 0.99.0 → 1.3.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.
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 = "speed, persistence, http(s)"
8
- s.description = "EXtended http(s) CONnections"
9
- s.authors = ["dpiddy (Dan Peterson)", "geemus (Wesley Beary)", "nextmat (Matt Sanders)"]
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 = ["--charset=UTF-8"]
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
- "CONTRIBUTING.md",
17
- "CONTRIBUTORS.md",
18
- "LICENSE.md",
19
- "README.md",
20
- "excon.gemspec"
18
+ 'CONTRIBUTING.md',
19
+ 'CONTRIBUTORS.md',
20
+ 'LICENSE.md',
21
+ 'README.md',
22
+ 'excon.gemspec'
21
23
  ]
24
+ s.required_ruby_version = '>= 3.1.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
- 'homepage_uri' => 'https://github.com/excon/excon',
38
- 'bug_tracker_uri' => 'https://github.com/excon/excon/issues',
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
- 'source_code_uri' => 'https://github.com/excon/excon',
42
- 'wiki_uri' => 'https://github.com/excon/excon/wiki'
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
@@ -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') == 0 && body.nil?
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(String.new("0#{CR_NL}#{CR_NL}"))
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]['Host'] ||= ''
255
+ datum[:headers][host_key] ||= ''
249
256
  else
250
- datum[:headers]['Host'] ||= datum[:host] + port_string(datum)
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('Host'))
256
- datum[:headers] = { 'Host' => host }.merge(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') == 0 })
295
- if datum[:response][:headers][key].casecmp('close') == 0
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.merge!(:persistent => @data[:persistent])
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') == 0 })
335
- if responses.last[:headers][key].casecmp('close') == 0
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 =~ /certificate verify failed/
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))
@@ -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__), "..", "..", "data", "cacert.pem"))
5
+ DEFAULT_CA_FILE = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'data', 'cacert.pem'))
7
6
 
8
- DEFAULT_CHUNK_SIZE = 1048576 # 1 megabyte
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::Timeout,
17
+ Excon::Error::RequestTimeout,
18
+ Excon::Error::Server,
21
19
  Excon::Error::Socket,
22
- Excon::Error::HTTPStatus
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{connect delete get head options patch post put trace}
28
+ HTTP_VERBS = %w[connect delete get head options patch post put trace].freeze
30
29
 
31
30
  HTTPS = 'https'
32
31
 
@@ -36,90 +35,97 @@ module Excon
36
35
 
37
36
  UNIX = 'unix'
38
37
 
39
- USER_AGENT = "excon/#{VERSION}"
40
-
41
- VERSIONS = "#{USER_AGENT} (#{RUBY_PLATFORM}) ruby/#{RUBY_VERSION}"
42
-
43
- VALID_REQUEST_KEYS = [
44
- :allow_unstubbed_requests,
45
- :body,
46
- :chunk_size,
47
- :debug_request,
48
- :debug_response,
49
- :headers,
50
- :instrumentor, # Used for setting logging within Connection
51
- :logger,
52
- :method,
53
- :middlewares,
54
- :password,
55
- :path,
56
- :persistent,
57
- :pipeline,
58
- :query,
59
- :read_timeout,
60
- :request_block,
61
- :response_block,
62
- :stubs,
63
- :user,
64
- :versions,
65
- :write_timeout
38
+ USER_AGENT = "excon/#{VERSION}".freeze
39
+
40
+ VERSIONS = "#{USER_AGENT} (#{RUBY_PLATFORM}) ruby/#{RUBY_VERSION}".freeze
41
+
42
+ # FIXME: should be frozen, but with a way to change them, similar to defaults
43
+ VALID_REQUEST_KEYS = %i[
44
+ allow_unstubbed_requests
45
+ body
46
+ chunk_size
47
+ debug_request
48
+ debug_response
49
+ dns_timeouts
50
+ headers
51
+ instrumentor
52
+ logger
53
+ method
54
+ middlewares
55
+ password
56
+ path
57
+ persistent
58
+ pipeline
59
+ query
60
+ read_timeout
61
+ request_block
62
+ resolv_resolver
63
+ response_block
64
+ stubs
65
+ timeout
66
+ user
67
+ versions
68
+ write_timeout
66
69
  ]
67
70
 
68
- VALID_CONNECTION_KEYS = VALID_REQUEST_KEYS + [
69
- :ciphers,
70
- :client_key,
71
- :client_key_data,
72
- :client_key_pass,
73
- :client_cert,
74
- :client_cert_data,
75
- :client_chain,
76
- :client_chain_data,
77
- :certificate,
78
- :certificate_path,
79
- :disable_proxy,
80
- :private_key,
81
- :private_key_path,
82
- :connect_timeout,
83
- :family,
84
- :keepalive,
85
- :host,
86
- :hostname,
87
- :omit_default_port,
88
- :nonblock,
89
- :reuseaddr,
90
- :port,
91
- :proxy,
92
- :scheme,
93
- :socket,
94
- :ssl_ca_file,
95
- :ssl_ca_path,
96
- :ssl_cert_store,
97
- :ssl_verify_callback,
98
- :ssl_verify_peer,
99
- :ssl_verify_peer_host,
100
- :ssl_verify_hostname,
101
- :ssl_version,
102
- :ssl_min_version,
103
- :ssl_max_version,
104
- :ssl_security_level,
105
- :ssl_proxy_headers,
106
- :ssl_uri_schemes,
107
- :tcp_nodelay,
108
- :thread_safe_sockets,
109
- :uri_parser,
110
- ]
71
+ # FIXME: should be frozen, but with a way to change them, similar to defaults
72
+ VALID_CONNECTION_KEYS = (VALID_REQUEST_KEYS + %i[
73
+ ciphers
74
+ client_key
75
+ client_key_data
76
+ client_key_pass
77
+ client_cert
78
+ client_cert_data
79
+ client_chain
80
+ client_chain_data
81
+ certificate
82
+ certificate_path
83
+ disable_proxy
84
+ private_key
85
+ private_key_path
86
+ connect_timeout
87
+ family
88
+ keepalive
89
+ host
90
+ hostname
91
+ ignore_unexpected_eof
92
+ include_default_port
93
+ omit_default_port
94
+ nonblock
95
+ reuseaddr
96
+ port
97
+ proxy
98
+ scheme
99
+ socket
100
+ ssl_ca_file
101
+ ssl_ca_path
102
+ ssl_cert_store
103
+ ssl_verify_callback
104
+ ssl_verify_peer
105
+ ssl_verify_peer_host
106
+ ssl_verify_hostname
107
+ ssl_version
108
+ ssl_min_version
109
+ ssl_max_version
110
+ ssl_security_level
111
+ ssl_proxy_headers
112
+ ssl_uri_schemes
113
+ tcp_nodelay
114
+ thread_safe_sockets
115
+ uri_parser
116
+ ])
111
117
 
112
118
  DEPRECATED_VALID_REQUEST_KEYS = {
113
- :captures => 'Mock',
114
- :expects => 'Expects',
115
- :idempotent => 'Idempotent',
116
- :instrumentor_name => 'Instrumentor',
117
- :mock => 'Mock',
118
- :retries_remaining => 'Idempotent', # referenced in Instrumentor, but only relevant with Idempotent
119
- :retry_errors => 'Idempotent',
120
- :retry_interval => 'Idempotent',
121
- :retry_limit => 'Idempotent' # referenced in Instrumentor, but only relevant with Idempotent
122
- }
119
+ captures: 'Mock',
120
+ expects: 'Expects',
121
+ idempotent: 'Idempotent',
122
+ instrumentor_name: 'Instrumentor',
123
+ mock: 'Mock',
124
+ retries_remaining: 'Idempotent', # referenced in Instrumentor, but only relevant with Idempotent
125
+ retry_errors: 'Idempotent',
126
+ retry_interval: 'Idempotent',
127
+ retry_limit: 'Idempotent' # referenced in Instrumentor, but only relevant with Idempotent
128
+ }.freeze
123
129
 
124
130
  unless ::IO.const_defined?(:WaitReadable)
125
131
  class ::IO
@@ -132,43 +138,54 @@ module Excon
132
138
  module WaitWritable; end
133
139
  end
134
140
  end
141
+
135
142
  # these come last as they rely on the above
136
- DEFAULTS = {
137
- :chunk_size => CHUNK_SIZE || DEFAULT_CHUNK_SIZE,
143
+ base_defaults = {
144
+ chunk_size: CHUNK_SIZE || DEFAULT_CHUNK_SIZE,
138
145
  # see https://wiki.mozilla.org/Security/Server_Side_TLS#Intermediate_compatibility_.28default.29
139
146
  # list provided then had DES related things sorted to the end
140
- :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',
141
- :connect_timeout => 60,
142
- :debug_request => false,
143
- :debug_response => false,
144
- :headers => {
147
+ 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',
148
+ connect_timeout: 60,
149
+ debug_request: false,
150
+ debug_response: false,
151
+ 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)
152
+ headers: {
145
153
  'User-Agent' => USER_AGENT,
146
- 'Accept' => '*/*'
147
- },
148
- :idempotent => false,
149
- :instrumentor_name => 'excon',
150
- :middlewares => [
154
+ 'Accept' => '*/*'
155
+ }.freeze,
156
+ idempotent: false,
157
+ instrumentor_name: 'excon',
158
+ middlewares: [
151
159
  Excon::Middleware::ResponseParser,
160
+ Excon::Middleware::Decompress,
152
161
  Excon::Middleware::Expects,
153
162
  Excon::Middleware::Idempotent,
154
163
  Excon::Middleware::Instrumentor,
155
164
  Excon::Middleware::Mock
156
165
  ],
157
- :mock => false,
158
- :nonblock => true,
159
- :omit_default_port => false,
160
- :persistent => false,
161
- :read_timeout => 60,
162
- :retry_errors => DEFAULT_RETRY_ERRORS,
163
- :retry_limit => DEFAULT_RETRY_LIMIT,
164
- :ssl_verify_peer => true,
165
- :ssl_uri_schemes => [HTTPS],
166
- :stubs => :global,
167
- :tcp_nodelay => false,
168
- :thread_safe_sockets => true,
169
- :uri_parser => URI,
170
- :versions => VERSIONS,
171
- :write_timeout => 60
172
- }
173
-
166
+ mock: false,
167
+ include_default_port: false,
168
+ nonblock: true,
169
+ omit_default_port: true,
170
+ persistent: false,
171
+ read_timeout: 60,
172
+ resolv_resolver: nil,
173
+ retry_errors: DEFAULT_RETRY_ERRORS,
174
+ retry_limit: DEFAULT_RETRY_LIMIT,
175
+ ssl_verify_peer: true,
176
+ ssl_uri_schemes: [HTTPS].freeze,
177
+ stubs: :global,
178
+ tcp_nodelay: false,
179
+ thread_safe_sockets: true,
180
+ timeout: nil,
181
+ uri_parser: URI,
182
+ versions: VERSIONS,
183
+ write_timeout: 60
184
+ }.freeze
185
+
186
+ DEFAULTS = if defined? TEST_SUITE_DEFAULTS
187
+ base_defaults.merge(TEST_SUITE_DEFAULTS).freeze
188
+ else
189
+ base_defaults.freeze
190
+ end
174
191
  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 =~ /Error\Z/
220
- class_name = klass.to_s + 'Error' if class_name =~ legacy_re
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
@@ -9,7 +9,7 @@ module Excon
9
9
 
10
10
  def get_header(datum, header)
11
11
  _, header_value = datum[:response][:headers].detect do |key, _|
12
- key.casecmp(header) == 0
12
+ key.casecmp?(header)
13
13
  end
14
14
  header_value
15
15
  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.has_key?(:response_block)
11
- key = datum[:headers].keys.detect {|k| k.to_s.casecmp('Accept-Encoding') == 0 } || '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
- unless datum.has_key?(:response_block) || body.nil? || body.empty?
22
- if (key = datum[:response][:headers].keys.detect {|k| k.casecmp('Content-Encoding') == 0 })
23
- encodings = Utils.split_header_value(datum[:response][:headers][key])
24
- if (encoding = encodings.last)
25
- if encoding.casecmp('deflate') == 0
26
- datum[:response][:body] = begin
27
- Zlib::Inflate.new(INFLATE_ZLIB_OR_GZIP).inflate(body)
28
- rescue Zlib::DataError # fallback to raw on error
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) == 0
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.merge!(:user => Utils.unescape_uri(uri.user)) if uri.user
71
- params.merge!(:password => Utils.unescape_uri(uri.password)) if uri.password
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!({
@@ -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') == 0 })
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') == 0
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') == 0 })
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') == 0
205
+ if key.casecmp?('Set-Cookie')
206
206
  datum[:response][:cookies] << value.strip
207
207
  end
208
208
  last_key = key