httpx 0.18.7 → 0.19.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +5 -1
- data/doc/release_notes/0_19_0.md +39 -0
- data/doc/release_notes/0_19_1.md +5 -0
- data/doc/release_notes/0_19_2.md +7 -0
- data/doc/release_notes/0_19_3.md +6 -0
- data/lib/httpx/adapters/faraday.rb +7 -3
- data/lib/httpx/connection.rb +14 -10
- data/lib/httpx/extensions.rb +16 -0
- data/lib/httpx/headers.rb +0 -2
- data/lib/httpx/io/tcp.rb +24 -5
- data/lib/httpx/options.rb +44 -11
- data/lib/httpx/plugins/cookies.rb +5 -7
- data/lib/httpx/plugins/proxy.rb +2 -5
- data/lib/httpx/plugins/retries.rb +2 -2
- data/lib/httpx/pool.rb +40 -20
- data/lib/httpx/resolver/https.rb +32 -42
- data/lib/httpx/resolver/multi.rb +79 -0
- data/lib/httpx/resolver/native.rb +24 -39
- data/lib/httpx/resolver/resolver.rb +95 -0
- data/lib/httpx/resolver/system.rb +175 -19
- data/lib/httpx/resolver.rb +37 -11
- data/lib/httpx/response.rb +4 -2
- data/lib/httpx/session_extensions.rb +9 -2
- data/lib/httpx/timers.rb +1 -1
- data/lib/httpx/transcoder/chunker.rb +0 -1
- data/lib/httpx/version.rb +1 -1
- data/lib/httpx.rb +2 -0
- data/sig/errors.rbs +8 -0
- data/sig/headers.rbs +0 -2
- data/sig/httpx.rbs +4 -0
- data/sig/options.rbs +10 -7
- data/sig/parser/http1.rbs +14 -5
- data/sig/pool.rbs +17 -9
- data/sig/registry.rbs +3 -0
- data/sig/request.rbs +11 -0
- data/sig/resolver/https.rbs +15 -27
- data/sig/resolver/multi.rbs +7 -0
- data/sig/resolver/native.rbs +3 -12
- data/sig/resolver/resolver.rbs +36 -0
- data/sig/resolver/system.rbs +3 -9
- data/sig/resolver.rbs +12 -10
- data/sig/response.rbs +15 -5
- data/sig/selector.rbs +3 -3
- data/sig/timers.rbs +5 -2
- data/sig/transcoder/chunker.rbs +16 -5
- data/sig/transcoder/json.rbs +5 -0
- data/sig/transcoder.rbs +3 -1
- metadata +14 -4
- data/lib/httpx/resolver/resolver_mixin.rb +0 -75
- data/sig/resolver/resolver_mixin.rbs +0 -26
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 431fcabfda42f5d6010d903a15c6a83357123c9eef3528a769755c8639f1ec61
|
4
|
+
data.tar.gz: 52512337b7b2081a4ab123f7261dee14adb97da019fc9244b9ddf8e7de53c904
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7777af904a2e5a8f6f34984a69cb022c853483b6634dd631a3fbe92c9005fadb3637a21a214ff1e14ef4729ffa70d68362b703b9ccd25e2904b820fc674dbe6b
|
7
|
+
data.tar.gz: 94d92ad004319ecb3098b5e901921bfaf5d818cbb0e2e87eed8987248d1cc52d0fc70a5dc1dfe1a92faa8eae9e7074c926c0c01563002cb8067af449ae79fd51
|
data/README.md
CHANGED
@@ -140,11 +140,15 @@ In order to use HTTP/2 under JRuby, [check this link](https://gitlab.com/honeyry
|
|
140
140
|
* Doesn't work with ruby 2.4.0 for Windows (see [#36](https://gitlab.com/honeyryderchuck/httpx/issues/36)).
|
141
141
|
* Using `total_timeout` along with the `:persistent` plugin [does not work as you might expect](https://gitlab.com/honeyryderchuck/httpx/-/wikis/Timeouts#total_timeout).
|
142
142
|
|
143
|
+
## Versioning Policy
|
144
|
+
|
145
|
+
Although 0.x software, `httpx` is considered API-stable and production-ready, i.e. current API or options may be subject to deprecation and emit log warnings, but can only effectively be removed in a major version change.
|
146
|
+
|
143
147
|
## Contributing
|
144
148
|
|
145
149
|
* Discuss your contribution in an issue
|
146
150
|
* Fork it
|
147
151
|
* Make your changes, add some tests
|
148
|
-
* Ensure all tests pass (`bundle exec rake test`)
|
152
|
+
* Ensure all tests pass (`docker-compose -f docker-compose.yml -f docker-compose-ruby-{RUBY_VERSION}.yml run httpx bundle exec rake test`)
|
149
153
|
* Open a Merge Request (that's Pull Request in Github-ish)
|
150
154
|
* Wait for feedback
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# 0.19.0
|
2
|
+
|
3
|
+
## Features
|
4
|
+
|
5
|
+
### Happy Eyeballs v2
|
6
|
+
|
7
|
+
When the system supports dual-stack networking, `httpx` implements the Happy Eyeballs v2 algorithm (RFC 8305) to resolve hostnames to both IPv6 and IPv4 addresses while privileging IPv6 connectivity. This is implemented by `httpx` both for the `:native` as well as the `:https` (DoH) resolver (which do not perform address sorting, thereby being "DNS-based load-balancing" friendly), and "outsourced" to `getaddrinfo` when using the `:system` resolver.
|
8
|
+
|
9
|
+
IPv6 connectivity will also be privileged for `/etc/hosts` local DNS (i.e. `localhost` connections will connec to `::1`).
|
10
|
+
|
11
|
+
A new option, `:ip_families`, will also be available (`[Socket::AF_INET6, Socket::AF_INET]` in dual-stack systems). If you'd like to i.e. force IPv4 connectivity, you can do use it (`client = HTTPX.with(ip_families: [Socket::AF_INET])`).
|
12
|
+
|
13
|
+
## Improvements
|
14
|
+
|
15
|
+
### DNS: :system resolver uses getaddrinfo (instead of the resolver lib)
|
16
|
+
|
17
|
+
The `:system` resolver switched to using the `getaddinfo` system function to perform DNS requests. Not only is this call **not** blocking the session event loop anymore (unlike pre-0.19.0 `:system` resolver), it adds a lot of functionality that the stdlib `resolv` library just doesn't support at the moment (such as SRV records).
|
18
|
+
|
19
|
+
### HTTP/2 proxy support
|
20
|
+
|
21
|
+
The `:proxy` plugin handles "prior-knowledge" HTTP/2 proxies.
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
HTTPX.plugin(:proxy, fallback_protocol: "h2").with_proxy(uri: "http://http2-proxy:3128").get(...
|
25
|
+
```
|
26
|
+
|
27
|
+
Connection coalescing has also been enabled for proxied connections (also `CONNECT`-tunneled connections).
|
28
|
+
|
29
|
+
### curl-to-httpx
|
30
|
+
|
31
|
+
widget in [project website](https://honeyryderchuck.gitlab.io/httpx/) to turn curl commands into the equivalent `httpx` code.
|
32
|
+
|
33
|
+
## Bugfixes
|
34
|
+
|
35
|
+
* faraday adapter now supports passing session options.
|
36
|
+
* proxy: several fixes which enabled env-var (`HTTP(S)_PROXY`) defined proxy support.
|
37
|
+
* proxy: fixed graceful recovery from proxy tcp connect errors.
|
38
|
+
* several fixes around CNAMEs timeouts with the native resolver.
|
39
|
+
* https resolver is now closed when wrapping session closes (it was left open).
|
@@ -0,0 +1,7 @@
|
|
1
|
+
# 0.19.2
|
2
|
+
|
3
|
+
## Bugfixes
|
4
|
+
|
5
|
+
* skip resolution delay path for early resolve cases
|
6
|
+
|
7
|
+
when the early resolve path (using IP, /etc/hosts IP, IP from cache) is followed, emit_addresses is called, and in a particular case (dual-stack network but using an IPv4 address), the happy eyeballs resolution delay path was activated when it shouldn't (it's meant to be used only for DNS network requests), and resulted in @pool being called before it was ever set. This simple check ensures that it doesn't happen before it must.
|
@@ -81,6 +81,9 @@ module Faraday
|
|
81
81
|
|
82
82
|
def response=(response)
|
83
83
|
super
|
84
|
+
|
85
|
+
return if response.is_a?(::HTTPX::ErrorResponse)
|
86
|
+
|
84
87
|
response.body.on_data = @response_on_data
|
85
88
|
end
|
86
89
|
end
|
@@ -136,7 +139,7 @@ module Faraday
|
|
136
139
|
|
137
140
|
def on_response(&blk)
|
138
141
|
if blk
|
139
|
-
@on_response =
|
142
|
+
@on_response = ->(response) do
|
140
143
|
blk.call(response)
|
141
144
|
end
|
142
145
|
self
|
@@ -200,9 +203,9 @@ module Faraday
|
|
200
203
|
end
|
201
204
|
end
|
202
205
|
|
203
|
-
def initialize(app)
|
206
|
+
def initialize(app, options = {})
|
204
207
|
super(app)
|
205
|
-
@session = Session.new
|
208
|
+
@session = Session.new(options)
|
206
209
|
end
|
207
210
|
|
208
211
|
def call(env)
|
@@ -210,6 +213,7 @@ module Faraday
|
|
210
213
|
if parallel?(env)
|
211
214
|
handler = env[:parallel_manager].enqueue(env)
|
212
215
|
handler.on_response do |response|
|
216
|
+
response.raise_for_status
|
213
217
|
save_response(env, response.status, response.body.to_s, response.headers, response.reason) do |response_headers|
|
214
218
|
response_headers.merge!(response.headers)
|
215
219
|
end
|
data/lib/httpx/connection.rb
CHANGED
@@ -44,7 +44,7 @@ module HTTPX
|
|
44
44
|
|
45
45
|
def_delegator :@write_buffer, :empty?
|
46
46
|
|
47
|
-
attr_reader :origin, :origins, :state, :pending, :options
|
47
|
+
attr_reader :io, :origin, :origins, :state, :pending, :options
|
48
48
|
|
49
49
|
attr_writer :timers
|
50
50
|
|
@@ -78,7 +78,11 @@ module HTTPX
|
|
78
78
|
# this is a semi-private method, to be used by the resolver
|
79
79
|
# to initiate the io object.
|
80
80
|
def addresses=(addrs)
|
81
|
-
@io
|
81
|
+
if @io
|
82
|
+
@io.add_addresses(addrs)
|
83
|
+
else
|
84
|
+
@io = IO.registry(@type).new(@origin, addrs, @options)
|
85
|
+
end
|
82
86
|
end
|
83
87
|
|
84
88
|
def addresses
|
@@ -490,14 +494,14 @@ module HTTPX
|
|
490
494
|
|
491
495
|
def transition(nextstate)
|
492
496
|
handle_transition(nextstate)
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
497
|
+
rescue Errno::ECONNREFUSED,
|
498
|
+
Errno::EADDRNOTAVAIL,
|
499
|
+
Errno::EHOSTUNREACH,
|
500
|
+
TLSError => e
|
501
|
+
# connect errors, exit gracefully
|
502
|
+
handle_error(e)
|
503
|
+
@state = :closed
|
504
|
+
emit(:close)
|
501
505
|
end
|
502
506
|
|
503
507
|
def handle_transition(nextstate)
|
data/lib/httpx/extensions.rb
CHANGED
@@ -54,6 +54,22 @@ module HTTPX
|
|
54
54
|
Numeric.__send__(:include, NegMethods)
|
55
55
|
end
|
56
56
|
|
57
|
+
module StringExtensions
|
58
|
+
refine String do
|
59
|
+
def delete_suffix!(suffix)
|
60
|
+
suffix = Backports.coerce_to_str(suffix)
|
61
|
+
chomp! if frozen?
|
62
|
+
len = suffix.length
|
63
|
+
if len > 0 && index(suffix, -len)
|
64
|
+
self[-len..-1] = ''
|
65
|
+
self
|
66
|
+
else
|
67
|
+
nil
|
68
|
+
end
|
69
|
+
end unless String.method_defined?(:delete_suffix!)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
57
73
|
module HashExtensions
|
58
74
|
refine Hash do
|
59
75
|
def compact
|
data/lib/httpx/headers.rb
CHANGED
data/lib/httpx/io/tcp.rb
CHANGED
@@ -15,6 +15,7 @@ module HTTPX
|
|
15
15
|
|
16
16
|
def initialize(origin, addresses, options)
|
17
17
|
@state = :idle
|
18
|
+
@addresses = []
|
18
19
|
@hostname = origin.host
|
19
20
|
@options = Options.new(options)
|
20
21
|
@fallback_protocol = @options.fallback_protocol
|
@@ -30,15 +31,29 @@ module HTTPX
|
|
30
31
|
raise Error, "Given IO objects do not match the request authority" unless @io
|
31
32
|
|
32
33
|
_, _, _, @ip = @io.addr
|
33
|
-
@addresses
|
34
|
-
@ip_index = @addresses.size - 1
|
34
|
+
@addresses << @ip
|
35
35
|
@keep_open = true
|
36
36
|
@state = :connected
|
37
37
|
else
|
38
|
-
|
38
|
+
add_addresses(addresses)
|
39
39
|
end
|
40
40
|
@ip_index = @addresses.size - 1
|
41
|
-
@io ||= build_socket
|
41
|
+
# @io ||= build_socket
|
42
|
+
end
|
43
|
+
|
44
|
+
def add_addresses(addrs)
|
45
|
+
return if addrs.empty?
|
46
|
+
|
47
|
+
addrs = addrs.map { |addr| addr.is_a?(IPAddr) ? addr : IPAddr.new(addr) }
|
48
|
+
|
49
|
+
ip_index = @ip_index || (@addresses.size - 1)
|
50
|
+
if addrs.first.ipv6?
|
51
|
+
# should be the next in line
|
52
|
+
@addresses = [*@addresses[0, ip_index], *addrs, *@addresses[ip_index..-1]]
|
53
|
+
else
|
54
|
+
@addresses.unshift(*addrs)
|
55
|
+
@ip_index += addrs.size if @ip_index
|
56
|
+
end
|
42
57
|
end
|
43
58
|
|
44
59
|
def to_io
|
@@ -52,7 +67,7 @@ module HTTPX
|
|
52
67
|
def connect
|
53
68
|
return unless closed?
|
54
69
|
|
55
|
-
if @io.closed?
|
70
|
+
if !@io || @io.closed?
|
56
71
|
transition(:idle)
|
57
72
|
@io = build_socket
|
58
73
|
end
|
@@ -62,12 +77,16 @@ module HTTPX
|
|
62
77
|
Errno::EHOSTUNREACH => e
|
63
78
|
raise e if @ip_index <= 0
|
64
79
|
|
80
|
+
log { "failed connecting to #{@ip} (#{e.message}), trying next..." }
|
65
81
|
@ip_index -= 1
|
82
|
+
@io = build_socket
|
66
83
|
retry
|
67
84
|
rescue Errno::ETIMEDOUT => e
|
68
85
|
raise ConnectTimeoutError.new(@options.timeout[:connect_timeout], e.message) if @ip_index <= 0
|
69
86
|
|
87
|
+
log { "failed connecting to #{@ip} (#{e.message}), trying next..." }
|
70
88
|
@ip_index -= 1
|
89
|
+
@io = build_socket
|
71
90
|
retry
|
72
91
|
end
|
73
92
|
|
data/lib/httpx/options.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "socket"
|
4
|
+
|
3
5
|
module HTTPX
|
4
6
|
class Options
|
5
7
|
WINDOW_SIZE = 1 << 14 # 16K
|
@@ -9,6 +11,18 @@ module HTTPX
|
|
9
11
|
KEEP_ALIVE_TIMEOUT = 20
|
10
12
|
SETTINGS_TIMEOUT = 10
|
11
13
|
|
14
|
+
# https://github.com/ruby/resolv/blob/095f1c003f6073730500f02acbdbc55f83d70987/lib/resolv.rb#L408
|
15
|
+
ip_address_families = begin
|
16
|
+
list = Socket.ip_address_list
|
17
|
+
if list.any? { |a| a.ipv6? && !a.ipv6_loopback? && !a.ipv6_linklocal? }
|
18
|
+
[Socket::AF_INET6, Socket::AF_INET]
|
19
|
+
else
|
20
|
+
[Socket::AF_INET]
|
21
|
+
end
|
22
|
+
rescue NotImplementedError
|
23
|
+
[Socket::AF_INET]
|
24
|
+
end
|
25
|
+
|
12
26
|
DEFAULT_OPTIONS = {
|
13
27
|
:debug => ENV.key?("HTTPX_DEBUG") ? $stderr : nil,
|
14
28
|
:debug_level => (ENV["HTTPX_DEBUG"] || 1).to_i,
|
@@ -37,6 +51,7 @@ module HTTPX
|
|
37
51
|
:persistent => false,
|
38
52
|
:resolver_class => (ENV["HTTPX_RESOLVER"] || :native).to_sym,
|
39
53
|
:resolver_options => { cache: true },
|
54
|
+
:ip_families => ip_address_families,
|
40
55
|
}.freeze
|
41
56
|
|
42
57
|
begin
|
@@ -110,20 +125,18 @@ module HTTPX
|
|
110
125
|
end
|
111
126
|
|
112
127
|
def initialize(options = {})
|
113
|
-
|
114
|
-
defaults.each do |k, v|
|
115
|
-
next if v.nil?
|
116
|
-
|
117
|
-
begin
|
118
|
-
value = __send__(:"option_#{k}", v)
|
119
|
-
instance_variable_set(:"@#{k}", value)
|
120
|
-
rescue NoMethodError
|
121
|
-
raise Error, "unknown option: #{k}"
|
122
|
-
end
|
123
|
-
end
|
128
|
+
__initialize__(options)
|
124
129
|
freeze
|
125
130
|
end
|
126
131
|
|
132
|
+
def freeze
|
133
|
+
super
|
134
|
+
@origin.freeze
|
135
|
+
@timeout.freeze
|
136
|
+
@headers.freeze
|
137
|
+
@addresses.freeze
|
138
|
+
end
|
139
|
+
|
127
140
|
def option_origin(value)
|
128
141
|
URI(value)
|
129
142
|
end
|
@@ -174,6 +187,10 @@ module HTTPX
|
|
174
187
|
Array(value)
|
175
188
|
end
|
176
189
|
|
190
|
+
def option_ip_families(value)
|
191
|
+
Array(value)
|
192
|
+
end
|
193
|
+
|
177
194
|
%i[
|
178
195
|
params form json body ssl http2_settings
|
179
196
|
request_class response_class headers_class request_body_class
|
@@ -249,5 +266,21 @@ module HTTPX
|
|
249
266
|
end
|
250
267
|
end
|
251
268
|
end
|
269
|
+
|
270
|
+
private
|
271
|
+
|
272
|
+
def __initialize__(options = {})
|
273
|
+
defaults = DEFAULT_OPTIONS.merge(options)
|
274
|
+
defaults.each do |k, v|
|
275
|
+
next if v.nil?
|
276
|
+
|
277
|
+
begin
|
278
|
+
value = __send__(:"option_#{k}", v)
|
279
|
+
instance_variable_set(:"@#{k}", value)
|
280
|
+
rescue NoMethodError
|
281
|
+
raise Error, "unknown option: #{k}"
|
282
|
+
end
|
283
|
+
end
|
284
|
+
end
|
252
285
|
end
|
253
286
|
end
|
@@ -18,12 +18,6 @@ module HTTPX
|
|
18
18
|
require "httpx/plugins/cookies/set_cookie_parser"
|
19
19
|
end
|
20
20
|
|
21
|
-
module OptionsMethods
|
22
|
-
def option_cookies(value)
|
23
|
-
value.is_a?(Jar) ? value : Jar.new(value)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
21
|
module InstanceMethods
|
28
22
|
extend Forwardable
|
29
23
|
|
@@ -77,7 +71,7 @@ module HTTPX
|
|
77
71
|
end
|
78
72
|
|
79
73
|
module OptionsMethods
|
80
|
-
def
|
74
|
+
def __initialize__(*)
|
81
75
|
super
|
82
76
|
|
83
77
|
return unless @headers.key?("cookie")
|
@@ -89,6 +83,10 @@ module HTTPX
|
|
89
83
|
end
|
90
84
|
end
|
91
85
|
end
|
86
|
+
|
87
|
+
def option_cookies(value)
|
88
|
+
value.is_a?(Jar) ? value : Jar.new(value)
|
89
|
+
end
|
92
90
|
end
|
93
91
|
end
|
94
92
|
register_plugin :cookies, Cookies
|
data/lib/httpx/plugins/proxy.rb
CHANGED
@@ -1,9 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "resolv"
|
4
|
-
require "ipaddr"
|
5
|
-
require "forwardable"
|
6
|
-
|
7
3
|
module HTTPX
|
8
4
|
class HTTPProxyError < Error; end
|
9
5
|
|
@@ -117,6 +113,7 @@ module HTTPX
|
|
117
113
|
|
118
114
|
def fetch_response(request, connections, options)
|
119
115
|
response = super
|
116
|
+
|
120
117
|
if response.is_a?(ErrorResponse) &&
|
121
118
|
__proxy_error?(response) && !@_proxy_uris.empty?
|
122
119
|
@_proxy_uris.shift
|
@@ -251,7 +248,7 @@ module HTTPX
|
|
251
248
|
case nextstate
|
252
249
|
when :closing
|
253
250
|
# this is a hack so that we can use the super method
|
254
|
-
# and it'll
|
251
|
+
# and it'll think that the current state is open
|
255
252
|
@state = :open if @state == :connecting
|
256
253
|
end
|
257
254
|
super
|
@@ -41,7 +41,7 @@ module HTTPX
|
|
41
41
|
def option_retry_after(value)
|
42
42
|
# return early if callable
|
43
43
|
unless value.respond_to?(:call)
|
44
|
-
value =
|
44
|
+
value = Float(value)
|
45
45
|
raise TypeError, ":retry_after must be positive" unless value.positive?
|
46
46
|
end
|
47
47
|
|
@@ -96,8 +96,8 @@ module HTTPX
|
|
96
96
|
# rubocop:enable Style/MultilineTernaryOperator
|
97
97
|
)
|
98
98
|
response.close if response.respond_to?(:close)
|
99
|
-
request.retries -= 1
|
100
99
|
log { "failed to get response, #{request.retries} tries to go..." }
|
100
|
+
request.retries -= 1
|
101
101
|
request.transition(:idle)
|
102
102
|
|
103
103
|
retry_after = options.retry_after
|
data/lib/httpx/pool.rb
CHANGED
@@ -14,7 +14,6 @@ module HTTPX
|
|
14
14
|
|
15
15
|
def initialize
|
16
16
|
@resolvers = {}
|
17
|
-
@_resolver_ios = {}
|
18
17
|
@timers = Timers.new
|
19
18
|
@selector = Selector.new
|
20
19
|
@connections = []
|
@@ -56,9 +55,20 @@ module HTTPX
|
|
56
55
|
connections = connections.reject(&:inflight?)
|
57
56
|
connections.each(&:close)
|
58
57
|
next_tick until connections.none? { |c| c.state != :idle && @connections.include?(c) }
|
58
|
+
|
59
|
+
# close resolvers
|
60
|
+
outstanding_connections = @connections
|
61
|
+
resolver_connections = @resolvers.each_value.flat_map(&:connections).compact
|
62
|
+
outstanding_connections -= resolver_connections
|
63
|
+
|
64
|
+
return unless outstanding_connections.empty?
|
65
|
+
|
59
66
|
@resolvers.each_value do |resolver|
|
60
67
|
resolver.close unless resolver.closed?
|
61
|
-
end
|
68
|
+
end
|
69
|
+
# for https resolver
|
70
|
+
resolver_connections.each(&:close)
|
71
|
+
next_tick until resolver_connections.none? { |c| c.state != :idle && @connections.include?(c) }
|
62
72
|
end
|
63
73
|
|
64
74
|
def init_connection(connection, _options)
|
@@ -107,11 +117,12 @@ module HTTPX
|
|
107
117
|
return
|
108
118
|
end
|
109
119
|
|
110
|
-
|
111
|
-
|
112
|
-
|
120
|
+
find_resolver_for(connection) do |resolver|
|
121
|
+
resolver << connection
|
122
|
+
next if resolver.empty?
|
113
123
|
|
114
|
-
|
124
|
+
select_connection(resolver)
|
125
|
+
end
|
115
126
|
end
|
116
127
|
|
117
128
|
def on_resolver_connection(connection)
|
@@ -138,12 +149,11 @@ module HTTPX
|
|
138
149
|
|
139
150
|
def on_resolver_close(resolver)
|
140
151
|
resolver_type = resolver.class
|
141
|
-
return
|
152
|
+
return if resolver.closed?
|
142
153
|
|
143
154
|
@resolvers.delete(resolver_type)
|
144
155
|
|
145
156
|
deselect_connection(resolver)
|
146
|
-
@_resolver_ios.delete(resolver)
|
147
157
|
resolver.close unless resolver.closed?
|
148
158
|
end
|
149
159
|
|
@@ -174,12 +184,10 @@ module HTTPX
|
|
174
184
|
end
|
175
185
|
|
176
186
|
def coalesce_connections(conn1, conn2)
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
register_connection(conn2)
|
182
|
-
end
|
187
|
+
return register_connection(conn2) unless conn1.coalescable?(conn2)
|
188
|
+
|
189
|
+
conn1.merge(conn2)
|
190
|
+
@connections.delete(conn2)
|
183
191
|
end
|
184
192
|
|
185
193
|
def next_timeout
|
@@ -196,13 +204,25 @@ module HTTPX
|
|
196
204
|
resolver_type = Resolver.registry(resolver_type) if resolver_type.is_a?(Symbol)
|
197
205
|
|
198
206
|
@resolvers[resolver_type] ||= begin
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
207
|
+
resolver_manager = if resolver_type.multi?
|
208
|
+
Resolver::Multi.new(resolver_type, connection_options)
|
209
|
+
else
|
210
|
+
resolver_type.new(connection_options)
|
211
|
+
end
|
212
|
+
resolver_manager.on(:resolve, &method(:on_resolver_connection))
|
213
|
+
resolver_manager.on(:error, &method(:on_resolver_error))
|
214
|
+
resolver_manager.on(:close, &method(:on_resolver_close))
|
215
|
+
resolver_manager
|
216
|
+
end
|
217
|
+
|
218
|
+
manager = @resolvers[resolver_type]
|
219
|
+
|
220
|
+
(manager.is_a?(Resolver::Multi) && manager.early_resolve(connection)) || manager.resolvers.each do |resolver|
|
221
|
+
resolver.pool = self
|
222
|
+
yield resolver
|
205
223
|
end
|
224
|
+
|
225
|
+
manager
|
206
226
|
end
|
207
227
|
end
|
208
228
|
end
|