excon 0.109.0 → 1.5.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.
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+ module Excon
3
+ # This factory produces new +resolv+ gem resolver instances. Users who wants
4
+ # to configure a custom resolver (varying settings for varying resolvers) can
5
+ # provide a custom resolver factory class and configure it globally on the
6
+ # Excon defaults:
7
+ #
8
+ # Excon.defaults[:resolver_factory] = MyCustomResolverFactory
9
+ #
10
+ # Then you just need to provide a static method called +.create_resolver+
11
+ # which returns a new +Resolv+ instance. This allows the customization.
12
+ class ResolverFactory
13
+ # @return [Resolv] the new resolver instance
14
+ def self.create_resolver
15
+ Resolv.new
16
+ end
17
+ end
18
+ end
@@ -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
data/lib/excon/socket.rb CHANGED
@@ -11,19 +11,19 @@ module Excon
11
11
 
12
12
  # read/write drawn from https://github.com/ruby-amqp/bunny/commit/75d9dd79551b31a5dd3d1254c537bad471f108cf
13
13
  CONNECT_RETRY_EXCEPTION_CLASSES = if defined?(IO::EINPROGRESSWaitWritable) # Ruby >= 2.1
14
- [Errno::EINPROGRESS, IO::EINPROGRESSWaitWritable]
14
+ [Errno::EINPROGRESS, IO::EINPROGRESSWaitWritable].freeze
15
15
  else # Ruby <= 2.0
16
- [Errno::EINPROGRESS]
16
+ [Errno::EINPROGRESS].freeze
17
17
  end
18
18
  READ_RETRY_EXCEPTION_CLASSES = if defined?(IO::EAGAINWaitReadable) # Ruby >= 2.1
19
- [Errno::EAGAIN, Errno::EWOULDBLOCK, IO::WaitReadable, IO::EAGAINWaitReadable, IO::EWOULDBLOCKWaitReadable]
19
+ [Errno::EAGAIN, Errno::EWOULDBLOCK, IO::WaitReadable, IO::EAGAINWaitReadable, IO::EWOULDBLOCKWaitReadable].freeze
20
20
  else # Ruby <= 2.0
21
- [Errno::EAGAIN, Errno::EWOULDBLOCK, IO::WaitReadable]
21
+ [Errno::EAGAIN, Errno::EWOULDBLOCK, IO::WaitReadable].freeze
22
22
  end
23
23
  WRITE_RETRY_EXCEPTION_CLASSES = if defined?(IO::EAGAINWaitWritable) # Ruby >= 2.1
24
- [Errno::EAGAIN, Errno::EWOULDBLOCK, IO::WaitWritable, IO::EAGAINWaitWritable, IO::EWOULDBLOCKWaitWritable]
24
+ [Errno::EAGAIN, Errno::EWOULDBLOCK, IO::WaitWritable, IO::EAGAINWaitWritable, IO::EWOULDBLOCKWaitWritable].freeze
25
25
  else # Ruby <= 2.0
26
- [Errno::EAGAIN, Errno::EWOULDBLOCK, IO::WaitWritable]
26
+ [Errno::EAGAIN, Errno::EWOULDBLOCK, IO::WaitWritable].freeze
27
27
  end
28
28
  # Maps a socket operation to a timeout property.
29
29
  OPERATION_TO_TIMEOUT = {
@@ -132,7 +132,7 @@ module Excon
132
132
  family = @data[:proxy][:family]
133
133
  end
134
134
 
135
- resolver = @data[:resolv_resolver] || Resolv::DefaultResolver
135
+ resolver = @data[:resolv_resolver] || @data[:resolver_factory].create_resolver
136
136
 
137
137
  # Deprecated
138
138
  if @data[:dns_timeouts]
@@ -181,7 +181,7 @@ module Excon
181
181
  socket.close rescue nil
182
182
  end
183
183
  rescue SystemCallError => exception
184
- socket.close rescue nil if socket
184
+ socket&.close rescue nil
185
185
  end
186
186
  end
187
187
 
@@ -252,15 +252,11 @@ module Excon
252
252
  end
253
253
  end
254
254
  end
255
- rescue OpenSSL::SSL::SSLError => error
256
- if error.message == 'read would block'
257
- if @read_buffer.empty?
258
- select_with_timeout(@socket, :read) && retry
259
- end
260
- else
261
- raise(error)
262
- end
263
- rescue *READ_RETRY_EXCEPTION_CLASSES
255
+ rescue OpenSSL::SSL::SSLError => e
256
+ raise(e) unless e.message == 'read would block'
257
+
258
+ select_with_timeout(@socket, :read) && retry if @read_buffer.empty?
259
+ rescue *READ_RETRY_EXCEPTION_CLASSES => e
264
260
  if @read_buffer.empty?
265
261
  # if we didn't read anything, try again...
266
262
  select_with_timeout(@socket, :read) && retry
@@ -299,12 +295,10 @@ module Excon
299
295
 
300
296
  def read_block(max_length)
301
297
  @socket.read(max_length)
302
- rescue OpenSSL::SSL::SSLError => error
303
- if error.message == 'read would block'
304
- select_with_timeout(@socket, :read) && retry
305
- else
306
- raise(error)
307
- end
298
+ rescue OpenSSL::SSL::SSLError => e
299
+ select_with_timeout(@socket, :read) && retry if e.message == 'read would block'
300
+
301
+ raise(error)
308
302
  rescue *READ_RETRY_EXCEPTION_CLASSES
309
303
  select_with_timeout(@socket, :read) && retry
310
304
  rescue EOFError
@@ -327,12 +321,10 @@ module Excon
327
321
  else
328
322
  raise error
329
323
  end
330
- rescue OpenSSL::SSL::SSLError, *WRITE_RETRY_EXCEPTION_CLASSES => error
331
- if error.is_a?(OpenSSL::SSL::SSLError) && error.message != 'write would block'
332
- raise error
333
- else
334
- select_with_timeout(@socket, :write) && retry
335
- end
324
+ rescue OpenSSL::SSL::SSLError, *WRITE_RETRY_EXCEPTION_CLASSES => e
325
+ raise e if error.is_a?(OpenSSL::SSL::SSLError) && e.message != 'write would block'
326
+
327
+ select_with_timeout(@socket, :write) && retry
336
328
  end
337
329
 
338
330
  # Fast, common case.
@@ -348,12 +340,10 @@ module Excon
348
340
 
349
341
  def write_block(data)
350
342
  @socket.write(data)
351
- rescue OpenSSL::SSL::SSLError, *WRITE_RETRY_EXCEPTION_CLASSES => error
352
- if error.is_a?(OpenSSL::SSL::SSLError) && error.message != 'write would block'
353
- raise error
354
- else
355
- select_with_timeout(@socket, :write) && retry
356
- end
343
+ rescue OpenSSL::SSL::SSLError, *WRITE_RETRY_EXCEPTION_CLASSES => e
344
+ raise e if e.is_a?(OpenSSL::SSL::SSLError) && e.message != 'write would block'
345
+
346
+ select_with_timeout(@socket, :write) && retry
357
347
  end
358
348
 
359
349
  def select_with_timeout(socket, type)
@@ -373,25 +363,19 @@ module Excon
373
363
  end
374
364
 
375
365
  select = case type
376
- when :connect_read
377
- IO.select([socket], nil, nil, timeout)
378
- when :connect_write
379
- IO.select(nil, [socket], nil, timeout)
380
- when :read
381
- IO.select([socket], nil, nil, timeout)
382
- when :write
383
- IO.select(nil, [socket], nil, timeout)
384
- end
366
+ when :connect_read, :read
367
+ IO.select([socket], nil, nil, timeout)
368
+ when :connect_write, :write
369
+ IO.select(nil, [socket], nil, timeout)
370
+ end
385
371
 
386
- select || raise(Excon::Errors::Timeout.new("#{timeout_kind} timeout reached"))
372
+ select || raise(Excon::Errors::Timeout.new, "#{timeout_kind} timeout reached")
387
373
  end
388
374
 
389
375
  def unpacked_sockaddr
390
376
  @unpacked_sockaddr ||= ::Socket.unpack_sockaddr_in(@socket.to_io.getsockname)
391
377
  rescue ArgumentError => e
392
- unless e.message == 'not an AF_INET/AF_INET6 sockaddr'
393
- raise
394
- end
378
+ raise unless e.message == 'not an AF_INET/AF_INET6 sockaddr'
395
379
  end
396
380
 
397
381
  # Returns the remaining time in seconds until we reach the deadline for the request timeout.
@@ -0,0 +1,194 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Excon
4
+ # SOCKS5 protocol implementation (RFC 1928, RFC 1929)
5
+ # Shared module for SOCKS5Socket and SOCKS5SSLSocket
6
+ module SOCKS5
7
+ SOCKS5_VERSION = 0x05
8
+ SOCKS5_RESERVED = 0x00
9
+
10
+ # Authentication methods
11
+ SOCKS5_NO_AUTH = 0x00
12
+ SOCKS5_AUTH_USERNAME_PASSWORD = 0x02
13
+ SOCKS5_NO_ACCEPTABLE_AUTH = 0xFF
14
+
15
+ # Commands
16
+ SOCKS5_CMD_CONNECT = 0x01
17
+
18
+ # Address types
19
+ SOCKS5_ATYP_IPV4 = 0x01
20
+ SOCKS5_ATYP_DOMAIN = 0x03
21
+ SOCKS5_ATYP_IPV6 = 0x04
22
+
23
+ # Reply codes
24
+ SOCKS5_SUCCESS = 0x00
25
+ SOCKS5_ERRORS = {
26
+ 0x01 => 'General SOCKS server failure',
27
+ 0x02 => 'Connection not allowed by ruleset',
28
+ 0x03 => 'Network unreachable',
29
+ 0x04 => 'Host unreachable',
30
+ 0x05 => 'Connection refused',
31
+ 0x06 => 'TTL expired',
32
+ 0x07 => 'Command not supported',
33
+ 0x08 => 'Address type not supported'
34
+ }.freeze
35
+
36
+ # Maximum hostname length per RFC 1928
37
+ MAX_HOSTNAME_LENGTH = 255
38
+
39
+ private
40
+
41
+ # Parse SOCKS5 proxy string into components
42
+ # @param proxy_string [String] Proxy specification in various formats
43
+ # @return [Array<String, String, String, String>] host, port, user, pass
44
+ def parse_socks5_proxy(proxy_string)
45
+ # Support formats:
46
+ # host:port
47
+ # user:pass@host:port
48
+ # socks5://host:port
49
+ # socks5://user:pass@host:port
50
+ proxy_string = proxy_string.to_s.sub(%r{^socks5://}, '')
51
+
52
+ user = nil
53
+ pass = nil
54
+
55
+ if proxy_string.include?('@')
56
+ auth, host_port = proxy_string.split('@', 2)
57
+ user, pass = auth.split(':', 2)
58
+ else
59
+ host_port = proxy_string
60
+ end
61
+
62
+ host, port = host_port.split(':', 2)
63
+ port ||= '1080'
64
+
65
+ [host, port, user, pass]
66
+ end
67
+
68
+ # Perform SOCKS5 authentication handshake
69
+ def socks5_authenticate
70
+ auth_methods = if @proxy_user && @proxy_pass
71
+ [SOCKS5_NO_AUTH, SOCKS5_AUTH_USERNAME_PASSWORD]
72
+ else
73
+ [SOCKS5_NO_AUTH]
74
+ end
75
+
76
+ greeting = [SOCKS5_VERSION, auth_methods.length, *auth_methods].pack('C*')
77
+ @socket.write(greeting)
78
+
79
+ response = socks5_read_exactly(2)
80
+ version, chosen_method = response.unpack('CC')
81
+
82
+ if version != SOCKS5_VERSION
83
+ raise Excon::Error::Socket.new(Exception.new("SOCKS5 proxy returned invalid version: #{version}"))
84
+ end
85
+
86
+ case chosen_method
87
+ when SOCKS5_NO_AUTH
88
+ # No authentication required
89
+ when SOCKS5_AUTH_USERNAME_PASSWORD
90
+ unless @proxy_user && @proxy_pass
91
+ raise Excon::Error::Socket.new(Exception.new('SOCKS5 proxy requires authentication but no credentials provided'))
92
+ end
93
+ socks5_username_password_auth
94
+ when SOCKS5_NO_ACCEPTABLE_AUTH
95
+ raise Excon::Error::Socket.new(Exception.new('SOCKS5 proxy: no acceptable authentication methods'))
96
+ else
97
+ raise Excon::Error::Socket.new(Exception.new("SOCKS5 proxy: unsupported authentication method #{chosen_method}"))
98
+ end
99
+ end
100
+
101
+ # RFC 1929: Username/Password Authentication
102
+ def socks5_username_password_auth
103
+ auth_request = [
104
+ 0x01, # auth protocol version
105
+ @proxy_user.bytesize,
106
+ @proxy_user,
107
+ @proxy_pass.bytesize,
108
+ @proxy_pass
109
+ ].pack('CCA*CA*')
110
+
111
+ @socket.write(auth_request)
112
+
113
+ response = socks5_read_exactly(2)
114
+ _, status = response.unpack('CC')
115
+
116
+ unless status == 0x00
117
+ raise Excon::Error::Socket.new(Exception.new('SOCKS5 proxy authentication failed'))
118
+ end
119
+ end
120
+
121
+ # Request connection to target through SOCKS5 proxy
122
+ def socks5_connect(host, port)
123
+ if host.bytesize > MAX_HOSTNAME_LENGTH
124
+ raise Excon::Error::Socket.new(Exception.new("SOCKS5: hostname exceeds maximum length of #{MAX_HOSTNAME_LENGTH} bytes"))
125
+ end
126
+
127
+ # Build CONNECT request with domain name (let proxy resolve DNS)
128
+ request = [SOCKS5_VERSION, SOCKS5_CMD_CONNECT, SOCKS5_RESERVED].pack('CCC')
129
+ request += [SOCKS5_ATYP_DOMAIN, host.bytesize, host].pack('CCA*')
130
+ request += [port.to_i].pack('n')
131
+
132
+ @socket.write(request)
133
+
134
+ response = socks5_read_exactly(4)
135
+ version, reply, _, atyp = response.unpack('CCCC')
136
+
137
+ if version != SOCKS5_VERSION
138
+ raise Excon::Error::Socket.new(Exception.new("SOCKS5 proxy returned invalid version: #{version}"))
139
+ end
140
+
141
+ unless reply == SOCKS5_SUCCESS
142
+ error_msg = SOCKS5_ERRORS[reply] || "Unknown error (#{reply})"
143
+ raise Excon::Error::Socket.new(Exception.new("SOCKS5 proxy connect failed: #{error_msg}"))
144
+ end
145
+
146
+ # Read and discard bound address (not needed for CONNECT)
147
+ socks5_read_bound_address(atyp)
148
+ end
149
+
150
+ def socks5_read_bound_address(atyp)
151
+ case atyp
152
+ when SOCKS5_ATYP_IPV4
153
+ socks5_read_exactly(4 + 2) # 4 bytes IP + 2 bytes port
154
+ when SOCKS5_ATYP_DOMAIN
155
+ domain_len = socks5_read_exactly(1).unpack1('C')
156
+ socks5_read_exactly(domain_len + 2)
157
+ when SOCKS5_ATYP_IPV6
158
+ socks5_read_exactly(16 + 2) # 16 bytes IP + 2 bytes port
159
+ else
160
+ raise Excon::Error::Socket.new(Exception.new("SOCKS5 proxy returned unknown address type: #{atyp}"))
161
+ end
162
+ end
163
+
164
+ # Read exact number of bytes with timeout support
165
+ def socks5_read_exactly(nbytes)
166
+ data = ''.dup
167
+ deadline = @data[:read_timeout] ? Time.now + @data[:read_timeout] : nil
168
+
169
+ while data.bytesize < nbytes
170
+ if deadline
171
+ remaining = deadline - Time.now
172
+ if remaining <= 0
173
+ raise Excon::Error::Timeout.new('SOCKS5 read timeout')
174
+ end
175
+ ready = IO.select([@socket], nil, nil, remaining)
176
+ unless ready
177
+ raise Excon::Error::Timeout.new('SOCKS5 read timeout')
178
+ end
179
+ end
180
+
181
+ chunk = @socket.read_nonblock(nbytes - data.bytesize, exception: false)
182
+ case chunk
183
+ when :wait_readable
184
+ IO.select([@socket], nil, nil, deadline ? [deadline - Time.now, 0].max : nil)
185
+ when nil, ''
186
+ raise Excon::Error::Socket.new(Exception.new('SOCKS5 proxy connection closed unexpectedly'))
187
+ else
188
+ data << chunk
189
+ end
190
+ end
191
+ data
192
+ end
193
+ end
194
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Excon
4
+ class SOCKS5Socket < Socket
5
+ include SOCKS5
6
+
7
+ def initialize(data = {})
8
+ @socks5_proxy = data[:socks5_proxy]
9
+ @proxy_host, @proxy_port, @proxy_user, @proxy_pass = parse_socks5_proxy(@socks5_proxy)
10
+ super(data)
11
+ end
12
+
13
+ private
14
+
15
+ # Proxy-swap pattern: temporarily set @data[:proxy] to the SOCKS5 proxy
16
+ # so that Socket#connect routes the TCP connection there (inheriting DNS
17
+ # resolution, nonblock, retry, keepalive, reuseaddr, remote_ip tracking).
18
+ # After TCP is up, clear :proxy and run the SOCKS5 handshake.
19
+ def connect
20
+ @data[:proxy] = {
21
+ host: @proxy_host,
22
+ hostname: @proxy_host,
23
+ port: @proxy_port.to_i
24
+ }
25
+
26
+ begin
27
+ super
28
+ ensure
29
+ @data.delete(:proxy)
30
+ end
31
+
32
+ socks5_authenticate
33
+ socks5_connect(@data[:host], @data[:port])
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Excon
4
+ class SOCKS5SSLSocket < SSLSocket
5
+ include SOCKS5
6
+
7
+ def initialize(data = {})
8
+ @socks5_proxy = data[:socks5_proxy]
9
+ @proxy_host, @proxy_port, @proxy_user, @proxy_pass = parse_socks5_proxy(@socks5_proxy)
10
+ super(data)
11
+ end
12
+
13
+ private
14
+
15
+ # Proxy-swap pattern (same as SOCKS5Socket#connect).
16
+ #
17
+ # Call chain:
18
+ # SOCKS5SSLSocket#initialize -> super (SSLSocket#initialize)
19
+ # -> super (Socket#initialize) -> connect
20
+ # -> SOCKS5SSLSocket#connect (this method)
21
+ # -> super -> SSLSocket#connect -> Socket#connect (TCP to proxy)
22
+ # -> SOCKS5 handshake on raw TCP socket
23
+ # <- returns to SSLSocket#initialize
24
+ # -> @data[:proxy] is nil, so HTTP CONNECT is skipped (line 111)
25
+ # -> SSL wrapping on the SOCKS5-tunneled socket
26
+ def connect
27
+ @data[:proxy] = {
28
+ host: @proxy_host,
29
+ hostname: @proxy_host,
30
+ port: @proxy_port.to_i
31
+ }
32
+
33
+ begin
34
+ super
35
+ ensure
36
+ # Clear :proxy so SSLSocket#initialize skips HTTP CONNECT (line 111)
37
+ @data.delete(:proxy)
38
+ end
39
+
40
+ socks5_authenticate
41
+ socks5_connect(@data[:host], @data[:port])
42
+ end
43
+ end
44
+ end
@@ -26,6 +26,7 @@ module Excon
26
26
  if defined?(OpenSSL::SSL::OP_NO_COMPRESSION)
27
27
  ssl_context_options |= OpenSSL::SSL::OP_NO_COMPRESSION
28
28
  end
29
+ ssl_context_options |= OpenSSL::SSL::OP_IGNORE_UNEXPECTED_EOF if @data[:ignore_unexpected_eof]
29
30
  ssl_context.options = ssl_context_options
30
31
 
31
32
  ssl_context.ciphers = @data[:ciphers]
@@ -63,7 +64,7 @@ module Excon
63
64
  unless ca_file || ca_path || cert_store
64
65
  # workaround issue #257 (JRUBY-6970)
65
66
  ca_file = DEFAULT_CA_FILE
66
- ca_file = ca_file.gsub(/^jar:/, '') if ca_file =~ /^jar:file:\//
67
+ ca_file = ca_file.gsub(/^jar:/, '') if ca_file.match?(/^jar:file:\//)
67
68
 
68
69
  begin
69
70
  ssl_context.cert_store.add_file(ca_file)
@@ -108,8 +109,8 @@ module Excon
108
109
  end
109
110
 
110
111
  if @data[:proxy]
111
- request = "CONNECT #{@data[:host]}#{port_string(@data.merge(:omit_default_port => false))}#{Excon::HTTP_1_1}" +
112
- "Host: #{@data[:host]}#{port_string(@data)}#{Excon::CR_NL}"
112
+ request = "CONNECT #{@data[:host]}:#{@data[:port]}#{Excon::HTTP_1_1}" \
113
+ "Host: #{@data[:host]}:#{@data[:port]}#{Excon::CR_NL}"
113
114
 
114
115
  if @data[:proxy].has_key?(:user) || @data[:proxy].has_key?(:password)
115
116
  user, pass = Utils.unescape_form(@data[:proxy][:user].to_s), Utils.unescape_form(@data[:proxy][:password].to_s)
@@ -7,7 +7,7 @@ module Excon
7
7
  open_process(RbConfig.ruby, '-S', 'puma', '-b', bind_uri.to_s, app_str)
8
8
  process_stderr = ""
9
9
  line = ''
10
- until line =~ /Use Ctrl-C to stop/
10
+ until line.include?('Use Ctrl-C to stop')
11
11
  line = read.gets
12
12
  raise process_stderr if line.nil?
13
13
  process_stderr << line
@@ -12,19 +12,19 @@ module Excon
12
12
  host = bind_uri.host.gsub(/[\[\]]/, '')
13
13
  bind_str = "#{host}:#{bind_uri.port}"
14
14
  end
15
- args = [
15
+ args = [
16
16
  RbConfig.ruby,
17
17
  '-S',
18
- 'unicorn',
19
- '--no-default-middleware',
18
+ 'unicorn',
19
+ '--no-default-middleware',
20
20
  '-l',
21
- bind_str,
21
+ bind_str,
22
22
  app_str
23
23
  ]
24
24
  open_process(*args)
25
25
  process_stderr = ''
26
26
  line = ''
27
- until line =~ /worker\=0 ready/
27
+ until line.include?('worker=0 ready')
28
28
  line = error.gets
29
29
  raise process_stderr if line.nil?
30
30
  process_stderr << line
@@ -10,7 +10,7 @@ module Excon
10
10
  open_process(RbConfig.ruby, '-S', 'rackup', '-s', 'webrick', '--host', host, '--port', port, app_str)
11
11
  process_stderr = ""
12
12
  line = ''
13
- until line =~ /HTTPServer#start/
13
+ until line.include?('Server#start')
14
14
  line = error.gets
15
15
  raise process_stderr if line.nil?
16
16
  process_stderr << line
@@ -13,11 +13,6 @@ module Excon
13
13
 
14
14
  # Methods that must be implemented by a plugin
15
15
  INSTANCE_REQUIRES = [:start]
16
- Excon.defaults.merge!(
17
- connect_timeout: 5,
18
- read_timeout: 5,
19
- write_timeout: 5
20
- )
21
16
 
22
17
  def initialize(args)
23
18
  # TODO: Validate these args
@@ -55,7 +50,7 @@ module Excon
55
50
  if RUBY_PLATFORM == 'java'
56
51
  Process.kill('USR1', pid)
57
52
  else
58
- Process.kill(9, pid)
53
+ Process.kill('KILL', pid)
59
54
  Process.wait(pid)
60
55
  end
61
56
 
@@ -73,7 +68,7 @@ module Excon
73
68
  while (line = lines.shift)
74
69
  case line
75
70
  when /(ERROR|Error)/
76
- unless line =~ /(null cert chain|did not return a certificate|SSL_read:: internal error)/
71
+ unless line.match?(/(null cert chain|did not return a certificate|SSL_read:: internal error)/)
77
72
  in_err = true
78
73
  puts
79
74
  end
@@ -34,7 +34,7 @@ module Excon
34
34
  end
35
35
 
36
36
  rescue => error
37
- @socket.close rescue nil if @socket
37
+ @socket&.close rescue nil
38
38
  raise error
39
39
  end
40
40