httpx 0.11.2 → 0.13.2
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 +2 -2
- data/doc/release_notes/0_11_1.md +5 -1
- data/doc/release_notes/0_11_3.md +5 -0
- data/doc/release_notes/0_12_0.md +55 -0
- data/doc/release_notes/0_13_0.md +58 -0
- data/doc/release_notes/0_13_1.md +5 -0
- data/doc/release_notes/0_13_2.md +9 -0
- data/lib/httpx.rb +2 -1
- data/lib/httpx/adapters/faraday.rb +4 -6
- data/lib/httpx/altsvc.rb +1 -0
- data/lib/httpx/chainable.rb +2 -2
- data/lib/httpx/connection.rb +80 -28
- data/lib/httpx/connection/http1.rb +19 -6
- data/lib/httpx/connection/http2.rb +32 -25
- data/lib/httpx/io.rb +16 -3
- data/lib/httpx/io/ssl.rb +35 -24
- data/lib/httpx/io/tcp.rb +50 -28
- data/lib/httpx/io/tls.rb +218 -0
- data/lib/httpx/io/tls/box.rb +365 -0
- data/lib/httpx/io/tls/context.rb +199 -0
- data/lib/httpx/io/tls/ffi.rb +390 -0
- data/lib/httpx/io/udp.rb +31 -7
- data/lib/httpx/io/unix.rb +27 -12
- data/lib/httpx/options.rb +11 -23
- data/lib/httpx/parser/http1.rb +4 -4
- data/lib/httpx/plugins/aws_sdk_authentication.rb +81 -0
- data/lib/httpx/plugins/aws_sigv4.rb +219 -0
- data/lib/httpx/plugins/compression.rb +20 -8
- data/lib/httpx/plugins/compression/brotli.rb +8 -6
- data/lib/httpx/plugins/compression/deflate.rb +4 -7
- data/lib/httpx/plugins/compression/gzip.rb +2 -2
- data/lib/httpx/plugins/digest_authentication.rb +1 -1
- data/lib/httpx/plugins/follow_redirects.rb +1 -1
- data/lib/httpx/plugins/h2c.rb +43 -58
- data/lib/httpx/plugins/internal_telemetry.rb +93 -0
- data/lib/httpx/plugins/multipart.rb +2 -0
- data/lib/httpx/plugins/multipart/encoder.rb +4 -9
- data/lib/httpx/plugins/proxy.rb +1 -1
- data/lib/httpx/plugins/proxy/http.rb +1 -1
- data/lib/httpx/plugins/proxy/socks4.rb +8 -0
- data/lib/httpx/plugins/proxy/socks5.rb +8 -0
- data/lib/httpx/plugins/push_promise.rb +3 -2
- data/lib/httpx/plugins/retries.rb +2 -2
- data/lib/httpx/plugins/stream.rb +6 -6
- data/lib/httpx/plugins/upgrade.rb +84 -0
- data/lib/httpx/plugins/upgrade/h2.rb +54 -0
- data/lib/httpx/pool.rb +14 -6
- data/lib/httpx/registry.rb +1 -7
- data/lib/httpx/request.rb +11 -1
- data/lib/httpx/resolver/https.rb +3 -11
- data/lib/httpx/resolver/native.rb +7 -3
- data/lib/httpx/response.rb +14 -7
- data/lib/httpx/selector.rb +5 -0
- data/lib/httpx/session.rb +25 -2
- data/lib/httpx/transcoder/body.rb +3 -5
- data/lib/httpx/version.rb +1 -1
- data/sig/chainable.rbs +2 -1
- data/sig/connection/http1.rbs +3 -2
- data/sig/connection/http2.rbs +5 -3
- data/sig/options.rbs +7 -20
- data/sig/plugins/aws_sdk_authentication.rbs +17 -0
- data/sig/plugins/aws_sigv4.rbs +64 -0
- data/sig/plugins/compression.rbs +5 -3
- data/sig/plugins/compression/brotli.rbs +1 -1
- data/sig/plugins/compression/deflate.rbs +1 -1
- data/sig/plugins/compression/gzip.rbs +1 -1
- data/sig/plugins/cookies.rbs +0 -1
- data/sig/plugins/digest_authentication.rbs +0 -1
- data/sig/plugins/expect.rbs +0 -2
- data/sig/plugins/follow_redirects.rbs +0 -2
- data/sig/plugins/h2c.rbs +5 -10
- data/sig/plugins/persistent.rbs +0 -1
- data/sig/plugins/proxy.rbs +0 -1
- data/sig/plugins/push_promise.rbs +1 -1
- data/sig/plugins/retries.rbs +0 -4
- data/sig/plugins/upgrade.rbs +23 -0
- data/sig/response.rbs +3 -1
- metadata +24 -2
@@ -10,7 +10,7 @@ module HTTPX
|
|
10
10
|
MAX_REQUESTS = 100
|
11
11
|
CRLF = "\r\n"
|
12
12
|
|
13
|
-
attr_reader :pending
|
13
|
+
attr_reader :pending, :requests
|
14
14
|
|
15
15
|
def initialize(buffer, options)
|
16
16
|
@options = Options.new(options)
|
@@ -74,9 +74,10 @@ module HTTPX
|
|
74
74
|
end
|
75
75
|
|
76
76
|
def consume
|
77
|
-
requests_limit = [@
|
77
|
+
requests_limit = [@max_requests, @requests.size].min
|
78
|
+
concurrent_requests_limit = [@max_concurrent_requests, requests_limit].min
|
78
79
|
@requests.each_with_index do |request, idx|
|
79
|
-
break if idx >=
|
80
|
+
break if idx >= concurrent_requests_limit
|
80
81
|
next if request.state == :done
|
81
82
|
|
82
83
|
request.headers["connection"] ||= request.options.persistent || idx < requests_limit - 1 ? "keep-alive" : "close"
|
@@ -115,7 +116,7 @@ module HTTPX
|
|
115
116
|
response = @request.response
|
116
117
|
log(level: 2) { "trailer headers received" }
|
117
118
|
|
118
|
-
log(color: :yellow) { h.each.map { |f, v| "-> HEADER: #{f}: #{v}" }.join("\n") }
|
119
|
+
log(color: :yellow) { h.each.map { |f, v| "-> HEADER: #{f}: #{v.join(", ")}" }.join("\n") }
|
119
120
|
response.merge_headers(h)
|
120
121
|
end
|
121
122
|
|
@@ -161,6 +162,16 @@ module HTTPX
|
|
161
162
|
end
|
162
163
|
|
163
164
|
def handle_error(ex)
|
165
|
+
if (ex.is_a?(EOFError) || ex.is_a?(TimeoutError)) && @request && @request.response &&
|
166
|
+
!@request.response.headers.key?("content-length") &&
|
167
|
+
!@request.response.headers.key?("transfer-encoding")
|
168
|
+
# if the response does not contain a content-length header, the server closing the
|
169
|
+
# connnection is the indicator of response consumed.
|
170
|
+
# https://greenbytes.de/tech/webdav/rfc2616.html#rfc.section.4.4
|
171
|
+
catch(:called) { on_complete }
|
172
|
+
return
|
173
|
+
end
|
174
|
+
|
164
175
|
if @pipelining
|
165
176
|
disable
|
166
177
|
else
|
@@ -224,6 +235,8 @@ module HTTPX
|
|
224
235
|
|
225
236
|
def disable_pipelining
|
226
237
|
return if @requests.empty?
|
238
|
+
# do not disable pipelining if already set to 1 request at a time
|
239
|
+
return if @max_concurrent_requests == 1
|
227
240
|
|
228
241
|
@requests.each do |r|
|
229
242
|
r.transition(:idle)
|
@@ -240,7 +253,7 @@ module HTTPX
|
|
240
253
|
@pipelining = false
|
241
254
|
end
|
242
255
|
|
243
|
-
def
|
256
|
+
def set_protocol_headers(request)
|
244
257
|
request.headers["host"] ||= request.authority
|
245
258
|
request.headers["connection"] ||= request.options.persistent ? "keep-alive" : "close"
|
246
259
|
if !request.headers.key?("content-length") &&
|
@@ -254,7 +267,6 @@ module HTTPX
|
|
254
267
|
end
|
255
268
|
|
256
269
|
def handle(request)
|
257
|
-
set_request_headers(request)
|
258
270
|
catch(:buffer_full) do
|
259
271
|
request.transition(:headers)
|
260
272
|
join_headers(request) if request.state == :headers
|
@@ -270,6 +282,7 @@ module HTTPX
|
|
270
282
|
log(color: :yellow) { "<- HEADLINE: #{buffer.chomp.inspect}" }
|
271
283
|
@buffer << buffer
|
272
284
|
buffer.clear
|
285
|
+
set_protocol_headers(request)
|
273
286
|
request.headers.each do |field, value|
|
274
287
|
buffer << "#{capitalized(field)}: #{value}" << CRLF
|
275
288
|
log(color: :yellow) { "<- HEADER: #{buffer.chomp}" }
|
@@ -42,11 +42,15 @@ module HTTPX
|
|
42
42
|
return @buffer.empty? ? :r : :rw
|
43
43
|
end
|
44
44
|
|
45
|
-
return :w
|
45
|
+
return :w if !@pending.empty? && can_buffer_more_requests?
|
46
46
|
|
47
47
|
return :w if @streams.each_key.any? { |r| r.interests == :w }
|
48
48
|
|
49
|
-
|
49
|
+
if @buffer.empty?
|
50
|
+
return if @streams.empty? && @pings.empty?
|
51
|
+
|
52
|
+
return :r
|
53
|
+
end
|
50
54
|
|
51
55
|
:rw
|
52
56
|
end
|
@@ -70,10 +74,14 @@ module HTTPX
|
|
70
74
|
@connection << data
|
71
75
|
end
|
72
76
|
|
77
|
+
def can_buffer_more_requests?
|
78
|
+
@handshake_completed &&
|
79
|
+
@streams.size < @max_concurrent_requests &&
|
80
|
+
@streams.size < @max_requests
|
81
|
+
end
|
82
|
+
|
73
83
|
def send(request)
|
74
|
-
|
75
|
-
@streams.size >= @max_concurrent_requests ||
|
76
|
-
@streams.size >= @max_requests
|
84
|
+
unless can_buffer_more_requests?
|
77
85
|
@pending << request
|
78
86
|
return
|
79
87
|
end
|
@@ -126,8 +134,6 @@ module HTTPX
|
|
126
134
|
request.path
|
127
135
|
end
|
128
136
|
|
129
|
-
def set_request_headers(request); end
|
130
|
-
|
131
137
|
def handle(request, stream)
|
132
138
|
catch(:buffer_full) do
|
133
139
|
request.transition(:headers)
|
@@ -172,18 +178,19 @@ module HTTPX
|
|
172
178
|
stream.on(:data, &method(:on_stream_data).curry(3)[stream, request])
|
173
179
|
end
|
174
180
|
|
181
|
+
def set_protocol_headers(request)
|
182
|
+
request.headers[":scheme"] = request.scheme
|
183
|
+
request.headers[":method"] = request.verb.to_s.upcase
|
184
|
+
request.headers[":path"] = headline_uri(request)
|
185
|
+
request.headers[":authority"] = request.authority
|
186
|
+
end
|
187
|
+
|
175
188
|
def join_headers(stream, request)
|
176
|
-
|
177
|
-
headers = {}
|
178
|
-
headers[":scheme"] = request.scheme
|
179
|
-
headers[":method"] = request.verb.to_s.upcase
|
180
|
-
headers[":path"] = headline_uri(request)
|
181
|
-
headers[":authority"] = request.authority
|
182
|
-
headers = headers.merge(request.headers)
|
189
|
+
set_protocol_headers(request)
|
183
190
|
log(level: 1, color: :yellow) do
|
184
|
-
headers.map { |k, v| "#{stream.id}: -> HEADER: #{k}: #{v}" }.join("\n")
|
191
|
+
request.headers.each.map { |k, v| "#{stream.id}: -> HEADER: #{k}: #{v}" }.join("\n")
|
185
192
|
end
|
186
|
-
stream.headers(headers, end_stream: request.empty?)
|
193
|
+
stream.headers(request.headers.each, end_stream: request.empty?)
|
187
194
|
end
|
188
195
|
|
189
196
|
def join_body(stream, request)
|
@@ -227,10 +234,15 @@ module HTTPX
|
|
227
234
|
end
|
228
235
|
|
229
236
|
def on_stream_close(stream, request, error)
|
237
|
+
log(level: 2) { "#{stream.id}: closing stream" }
|
238
|
+
@drains.delete(request)
|
239
|
+
@streams.delete(request)
|
240
|
+
|
230
241
|
if error && error != :no_error
|
231
242
|
ex = Error.new(stream.id, error)
|
232
243
|
ex.set_backtrace(caller)
|
233
|
-
|
244
|
+
response = ErrorResponse.new(request, ex, request.options)
|
245
|
+
emit(:response, request, response)
|
234
246
|
else
|
235
247
|
response = request.response
|
236
248
|
if response.status == 421
|
@@ -241,9 +253,6 @@ module HTTPX
|
|
241
253
|
emit(:response, request, response)
|
242
254
|
end
|
243
255
|
end
|
244
|
-
log(level: 2) { "#{stream.id}: closing stream" }
|
245
|
-
|
246
|
-
@streams.delete(request)
|
247
256
|
send(@pending.shift) unless @pending.empty?
|
248
257
|
return unless @streams.empty? && exhausted?
|
249
258
|
|
@@ -328,11 +337,9 @@ module HTTPX
|
|
328
337
|
end
|
329
338
|
|
330
339
|
def method_missing(meth, *args, &blk)
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
super
|
335
|
-
end
|
340
|
+
return super unless @connection.respond_to?(meth)
|
341
|
+
|
342
|
+
@connection.__send__(meth, *args, &blk)
|
336
343
|
end
|
337
344
|
end
|
338
345
|
Connection.register "h2", Connection::HTTP2
|
data/lib/httpx/io.rb
CHANGED
@@ -2,16 +2,29 @@
|
|
2
2
|
|
3
3
|
require "socket"
|
4
4
|
require "httpx/io/tcp"
|
5
|
-
require "httpx/io/ssl"
|
6
5
|
require "httpx/io/unix"
|
7
6
|
require "httpx/io/udp"
|
8
7
|
|
9
8
|
module HTTPX
|
10
9
|
module IO
|
11
10
|
extend Registry
|
12
|
-
register "tcp", TCP
|
13
|
-
register "ssl", SSL
|
14
11
|
register "udp", UDP
|
15
12
|
register "unix", HTTPX::UNIX
|
13
|
+
register "tcp", TCP
|
14
|
+
|
15
|
+
if RUBY_ENGINE == "jruby"
|
16
|
+
begin
|
17
|
+
require "httpx/io/tls"
|
18
|
+
register "ssl", TLS
|
19
|
+
rescue LoadError
|
20
|
+
# :nocov:
|
21
|
+
require "httpx/io/ssl"
|
22
|
+
register "ssl", SSL
|
23
|
+
# :nocov:
|
24
|
+
end
|
25
|
+
else
|
26
|
+
require "httpx/io/ssl"
|
27
|
+
register "ssl", SSL
|
28
|
+
end
|
16
29
|
end
|
17
30
|
end
|
data/lib/httpx/io/ssl.rb
CHANGED
@@ -3,6 +3,8 @@
|
|
3
3
|
require "openssl"
|
4
4
|
|
5
5
|
module HTTPX
|
6
|
+
TLSError = OpenSSL::SSL::SSLError
|
7
|
+
|
6
8
|
class SSL < TCP
|
7
9
|
TLS_OPTIONS = if OpenSSL::SSL::SSLContext.instance_methods.include?(:alpn_protocols)
|
8
10
|
{ alpn_protocols: %w[h2 http/1.1] }
|
@@ -11,19 +13,14 @@ module HTTPX
|
|
11
13
|
end
|
12
14
|
|
13
15
|
def initialize(_, _, options)
|
16
|
+
super
|
14
17
|
@ctx = OpenSSL::SSL::SSLContext.new
|
15
18
|
ctx_options = TLS_OPTIONS.merge(options.ssl)
|
16
|
-
@
|
19
|
+
@sni_hostname = ctx_options.delete(:hostname) || @hostname
|
17
20
|
@ctx.set_params(ctx_options) unless ctx_options.empty?
|
18
|
-
super
|
19
|
-
@tls_hostname ||= @hostname
|
20
21
|
@state = :negotiated if @keep_open
|
21
22
|
end
|
22
23
|
|
23
|
-
def interests
|
24
|
-
@interests || super
|
25
|
-
end
|
26
|
-
|
27
24
|
def protocol
|
28
25
|
@io.alpn_protocol || super
|
29
26
|
rescue StandardError
|
@@ -50,28 +47,30 @@ module HTTPX
|
|
50
47
|
|
51
48
|
def connect
|
52
49
|
super
|
53
|
-
if @keep_open
|
54
|
-
@state = :negotiated
|
55
|
-
return
|
56
|
-
end
|
57
50
|
return if @state == :negotiated ||
|
58
51
|
@state != :connected
|
59
52
|
|
60
53
|
unless @io.is_a?(OpenSSL::SSL::SSLSocket)
|
61
54
|
@io = OpenSSL::SSL::SSLSocket.new(@io, @ctx)
|
62
|
-
@io.hostname = @
|
55
|
+
@io.hostname = @sni_hostname
|
63
56
|
@io.sync_close = true
|
64
57
|
end
|
65
|
-
|
66
|
-
@io.post_connection_check(@tls_hostname) if @ctx.verify_mode != OpenSSL::SSL::VERIFY_NONE
|
67
|
-
transition(:negotiated)
|
68
|
-
rescue ::IO::WaitReadable
|
69
|
-
@interests = :r
|
70
|
-
rescue ::IO::WaitWritable
|
71
|
-
@interests = :w
|
58
|
+
try_ssl_connect
|
72
59
|
end
|
73
60
|
|
74
61
|
if RUBY_VERSION < "2.3"
|
62
|
+
# :nocov:
|
63
|
+
def try_ssl_connect
|
64
|
+
@io.connect_nonblock
|
65
|
+
@io.post_connection_check(@sni_hostname) if @ctx.verify_mode != OpenSSL::SSL::VERIFY_NONE
|
66
|
+
transition(:negotiated)
|
67
|
+
@interests = :w
|
68
|
+
rescue ::IO::WaitReadable
|
69
|
+
@interests = :r
|
70
|
+
rescue ::IO::WaitWritable
|
71
|
+
@interests = :w
|
72
|
+
end
|
73
|
+
|
75
74
|
def read(_, buffer)
|
76
75
|
super
|
77
76
|
rescue ::IO::WaitWritable
|
@@ -84,7 +83,23 @@ module HTTPX
|
|
84
83
|
rescue ::IO::WaitReadable
|
85
84
|
0
|
86
85
|
end
|
86
|
+
# :nocov:
|
87
87
|
else
|
88
|
+
def try_ssl_connect
|
89
|
+
case @io.connect_nonblock(exception: false)
|
90
|
+
when :wait_readable
|
91
|
+
@interests = :r
|
92
|
+
return
|
93
|
+
when :wait_writable
|
94
|
+
@interests = :w
|
95
|
+
return
|
96
|
+
end
|
97
|
+
@io.post_connection_check(@sni_hostname) if @ctx.verify_mode != OpenSSL::SSL::VERIFY_NONE
|
98
|
+
transition(:negotiated)
|
99
|
+
@interests = :w
|
100
|
+
end
|
101
|
+
|
102
|
+
# :nocov:
|
88
103
|
if OpenSSL::VERSION < "2.0.6"
|
89
104
|
def read(size, buffer)
|
90
105
|
@io.read_nonblock(size, buffer)
|
@@ -97,11 +112,7 @@ module HTTPX
|
|
97
112
|
nil
|
98
113
|
end
|
99
114
|
end
|
100
|
-
|
101
|
-
|
102
|
-
def inspect
|
103
|
-
id = @io.closed? ? "closed" : @io.to_io.fileno
|
104
|
-
"#<SSL(fd: #{id}): #{@ip}:#{@port} state: #{@state}>"
|
115
|
+
# :nocov:
|
105
116
|
end
|
106
117
|
|
107
118
|
private
|
data/lib/httpx/io/tcp.rb
CHANGED
@@ -7,17 +7,19 @@ module HTTPX
|
|
7
7
|
class TCP
|
8
8
|
include Loggable
|
9
9
|
|
10
|
-
|
10
|
+
using URIExtensions
|
11
|
+
|
12
|
+
attr_reader :ip, :port, :addresses, :state, :interests
|
11
13
|
|
12
14
|
alias_method :host, :ip
|
13
15
|
|
14
16
|
def initialize(origin, addresses, options)
|
15
17
|
@state = :idle
|
16
18
|
@hostname = origin.host
|
17
|
-
@addresses = addresses
|
18
19
|
@options = Options.new(options)
|
19
20
|
@fallback_protocol = @options.fallback_protocol
|
20
21
|
@port = origin.port
|
22
|
+
@interests = :w
|
21
23
|
if @options.io
|
22
24
|
@io = case @options.io
|
23
25
|
when Hash
|
@@ -25,24 +27,20 @@ module HTTPX
|
|
25
27
|
else
|
26
28
|
@options.io
|
27
29
|
end
|
30
|
+
raise Error, "Given IO objects do not match the request authority" unless @io
|
31
|
+
|
28
32
|
_, _, _, @ip = @io.addr
|
29
33
|
@addresses ||= [@ip]
|
30
34
|
@ip_index = @addresses.size - 1
|
31
|
-
|
32
|
-
|
33
|
-
@state = :connected
|
34
|
-
end
|
35
|
+
@keep_open = true
|
36
|
+
@state = :connected
|
35
37
|
else
|
36
|
-
@
|
37
|
-
@ip = @addresses[@ip_index]
|
38
|
+
@addresses = addresses.map { |addr| addr.is_a?(IPAddr) ? addr : IPAddr.new(addr) }
|
38
39
|
end
|
40
|
+
@ip_index = @addresses.size - 1
|
39
41
|
@io ||= build_socket
|
40
42
|
end
|
41
43
|
|
42
|
-
def interests
|
43
|
-
:w
|
44
|
-
end
|
45
|
-
|
46
44
|
def to_io
|
47
45
|
@io.to_io
|
48
46
|
end
|
@@ -54,32 +52,40 @@ module HTTPX
|
|
54
52
|
def connect
|
55
53
|
return unless closed?
|
56
54
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
@io = build_socket
|
61
|
-
end
|
62
|
-
@io.connect_nonblock(Socket.sockaddr_in(@port, @ip.to_s))
|
63
|
-
rescue Errno::EISCONN
|
55
|
+
if @io.closed?
|
56
|
+
transition(:idle)
|
57
|
+
@io = build_socket
|
64
58
|
end
|
65
|
-
|
59
|
+
try_connect
|
66
60
|
rescue Errno::EHOSTUNREACH => e
|
67
61
|
raise e if @ip_index <= 0
|
68
62
|
|
69
63
|
@ip_index -= 1
|
70
64
|
retry
|
71
65
|
rescue Errno::ETIMEDOUT => e
|
72
|
-
raise ConnectTimeoutError, e.message if @ip_index <= 0
|
66
|
+
raise ConnectTimeoutError.new(@options.timeout.connect_timeout, e.message) if @ip_index <= 0
|
73
67
|
|
74
68
|
@ip_index -= 1
|
75
69
|
retry
|
76
|
-
rescue Errno::EINPROGRESS,
|
77
|
-
Errno::EALREADY,
|
78
|
-
::IO::WaitReadable
|
79
70
|
end
|
80
71
|
|
81
72
|
if RUBY_VERSION < "2.3"
|
82
73
|
# :nocov:
|
74
|
+
def try_connect
|
75
|
+
@io.connect_nonblock(Socket.sockaddr_in(@port, @ip.to_s))
|
76
|
+
rescue ::IO::WaitWritable, Errno::EALREADY
|
77
|
+
@interests = :w
|
78
|
+
rescue ::IO::WaitReadable
|
79
|
+
@interests = :r
|
80
|
+
rescue Errno::EISCONN
|
81
|
+
transition(:connected)
|
82
|
+
@interests = :w
|
83
|
+
else
|
84
|
+
transition(:connected)
|
85
|
+
@interests = :w
|
86
|
+
end
|
87
|
+
private :try_connect
|
88
|
+
|
83
89
|
def read(size, buffer)
|
84
90
|
@io.read_nonblock(size, buffer)
|
85
91
|
log { "READ: #{buffer.bytesize} bytes..." }
|
@@ -103,6 +109,22 @@ module HTTPX
|
|
103
109
|
end
|
104
110
|
# :nocov:
|
105
111
|
else
|
112
|
+
def try_connect
|
113
|
+
case @io.connect_nonblock(Socket.sockaddr_in(@port, @ip.to_s), exception: false)
|
114
|
+
when :wait_readable
|
115
|
+
@interests = :r
|
116
|
+
return
|
117
|
+
when :wait_writable
|
118
|
+
@interests = :w
|
119
|
+
return
|
120
|
+
end
|
121
|
+
transition(:connected)
|
122
|
+
@interests = :w
|
123
|
+
rescue Errno::EALREADY
|
124
|
+
@interests = :w
|
125
|
+
end
|
126
|
+
private :try_connect
|
127
|
+
|
106
128
|
def read(size, buffer)
|
107
129
|
ret = @io.read_nonblock(size, buffer, exception: false)
|
108
130
|
if ret == :wait_readable
|
@@ -147,14 +169,14 @@ module HTTPX
|
|
147
169
|
|
148
170
|
# :nocov:
|
149
171
|
def inspect
|
150
|
-
|
151
|
-
"#<TCP(fd: #{id}): #{@ip}:#{@port} (state: #{@state})>"
|
172
|
+
"#<#{self.class}: #{@ip}:#{@port} (state: #{@state})>"
|
152
173
|
end
|
153
174
|
# :nocov:
|
154
175
|
|
155
176
|
private
|
156
177
|
|
157
178
|
def build_socket
|
179
|
+
@ip = @addresses[@ip_index]
|
158
180
|
Socket.new(@ip.family, :STREAM, 0)
|
159
181
|
end
|
160
182
|
|
@@ -177,9 +199,9 @@ module HTTPX
|
|
177
199
|
def log_transition_state(nextstate)
|
178
200
|
case nextstate
|
179
201
|
when :connected
|
180
|
-
"Connected to #{
|
202
|
+
"Connected to #{host} (##{@io.fileno})"
|
181
203
|
else
|
182
|
-
"#{
|
204
|
+
"#{host} #{@state} -> #{nextstate}"
|
183
205
|
end
|
184
206
|
end
|
185
207
|
end
|