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.
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 = '>= 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
- '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
 
@@ -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
- :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
66
- ]
67
-
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,
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
- :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
- }
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
- :chunk_size => CHUNK_SIZE || DEFAULT_CHUNK_SIZE,
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
- :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 => {
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
- :idempotent => false,
149
- :instrumentor_name => 'excon',
150
- :middlewares => [
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
- :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
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 =~ /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