httpx 1.6.1 → 1.6.3
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/doc/release_notes/1_6_2.md +11 -0
- data/doc/release_notes/1_6_3.md +47 -0
- data/lib/httpx/adapters/datadog.rb +15 -11
- data/lib/httpx/adapters/sentry.rb +1 -1
- data/lib/httpx/connection/http1.rb +9 -9
- data/lib/httpx/connection/http2.rb +14 -15
- data/lib/httpx/connection.rb +119 -102
- data/lib/httpx/extensions.rb +0 -14
- data/lib/httpx/io/ssl.rb +1 -1
- data/lib/httpx/loggable.rb +12 -2
- data/lib/httpx/options.rb +20 -0
- data/lib/httpx/plugins/callbacks.rb +15 -1
- data/lib/httpx/plugins/digest_auth.rb +1 -1
- data/lib/httpx/plugins/proxy/http.rb +37 -9
- data/lib/httpx/plugins/response_cache/file_store.rb +1 -0
- data/lib/httpx/plugins/response_cache.rb +13 -2
- data/lib/httpx/plugins/stream_bidi.rb +15 -6
- data/lib/httpx/pool.rb +53 -19
- data/lib/httpx/request.rb +3 -13
- data/lib/httpx/resolver/https.rb +35 -19
- data/lib/httpx/resolver/multi.rb +9 -32
- data/lib/httpx/resolver/native.rb +46 -38
- data/lib/httpx/resolver/resolver.rb +45 -28
- data/lib/httpx/resolver/system.rb +63 -39
- data/lib/httpx/selector.rb +35 -20
- data/lib/httpx/session.rb +18 -28
- data/lib/httpx/transcoder/deflate.rb +13 -8
- data/lib/httpx/transcoder/utils/body_reader.rb +1 -2
- data/lib/httpx/transcoder/utils/deflater.rb +1 -2
- data/lib/httpx/version.rb +1 -1
- data/sig/connection.rbs +12 -3
- data/sig/loggable.rbs +5 -1
- data/sig/options.rbs +5 -1
- data/sig/plugins/callbacks.rbs +3 -0
- data/sig/plugins/stream_bidi.rbs +3 -5
- data/sig/resolver/https.rbs +2 -0
- data/sig/resolver/multi.rbs +0 -9
- data/sig/resolver/native.rbs +0 -2
- data/sig/resolver/resolver.rbs +9 -8
- data/sig/resolver/system.rbs +4 -2
- data/sig/selector.rbs +2 -0
- data/sig/session.rbs +5 -3
- metadata +5 -1
|
@@ -16,7 +16,7 @@ module HTTPX
|
|
|
16
16
|
# The streams keeps send DATA frames while there's data; when they're ain't,
|
|
17
17
|
# the stream is kept open; it must be explicitly closed by the end user.
|
|
18
18
|
#
|
|
19
|
-
|
|
19
|
+
module HTTP2Methods
|
|
20
20
|
def initialize(*)
|
|
21
21
|
super
|
|
22
22
|
@lock = Thread::Mutex.new
|
|
@@ -117,8 +117,11 @@ module HTTPX
|
|
|
117
117
|
# which allows it to be registered in the selector alongside actual HTTP-based
|
|
118
118
|
# HTTPX::Connection objects.
|
|
119
119
|
class Signal
|
|
120
|
+
attr_reader :error
|
|
121
|
+
|
|
120
122
|
def initialize
|
|
121
123
|
@closed = false
|
|
124
|
+
@error = nil
|
|
122
125
|
@pipe_read, @pipe_write = IO.pipe
|
|
123
126
|
end
|
|
124
127
|
|
|
@@ -159,6 +162,11 @@ module HTTPX
|
|
|
159
162
|
@closed = true
|
|
160
163
|
end
|
|
161
164
|
|
|
165
|
+
def on_error(error)
|
|
166
|
+
@error = error
|
|
167
|
+
terminate
|
|
168
|
+
end
|
|
169
|
+
|
|
162
170
|
# noop (the owner connection will take of it)
|
|
163
171
|
def handle_socket_timeout(interval); end
|
|
164
172
|
end
|
|
@@ -193,6 +201,7 @@ module HTTPX
|
|
|
193
201
|
|
|
194
202
|
def deselect_connection(connection, *)
|
|
195
203
|
super
|
|
204
|
+
|
|
196
205
|
connection.signal = nil
|
|
197
206
|
end
|
|
198
207
|
end
|
|
@@ -294,14 +303,14 @@ module HTTPX
|
|
|
294
303
|
super
|
|
295
304
|
end
|
|
296
305
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
def parser_type(protocol)
|
|
300
|
-
return HTTP2Bidi if protocol == "h2"
|
|
306
|
+
def call
|
|
307
|
+
return super unless (error = @signal.error)
|
|
301
308
|
|
|
302
|
-
|
|
309
|
+
on_error(error)
|
|
303
310
|
end
|
|
304
311
|
|
|
312
|
+
private
|
|
313
|
+
|
|
305
314
|
def set_parser_callbacks(parser)
|
|
306
315
|
super
|
|
307
316
|
parser.on(:flush_buffer) do
|
data/lib/httpx/pool.rb
CHANGED
|
@@ -8,7 +8,6 @@ require "httpx/resolver"
|
|
|
8
8
|
|
|
9
9
|
module HTTPX
|
|
10
10
|
class Pool
|
|
11
|
-
using ArrayExtensions::FilterMap
|
|
12
11
|
using URIExtensions
|
|
13
12
|
|
|
14
13
|
POOL_TIMEOUT = 5
|
|
@@ -51,32 +50,53 @@ module HTTPX
|
|
|
51
50
|
acquire_connection(uri, options) || begin
|
|
52
51
|
if @connections_counter == @max_connections
|
|
53
52
|
# this takes precedence over per-origin
|
|
54
|
-
@max_connections_cond.wait(@connection_mtx, @pool_timeout)
|
|
55
53
|
|
|
56
|
-
|
|
57
|
-
return conn
|
|
58
|
-
end
|
|
54
|
+
expires_at = Utils.now + @pool_timeout
|
|
59
55
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
# this means that all of them are persistent or being used, so raise a timeout error.
|
|
63
|
-
conn = @connections.find { |c| c.state == :closed }
|
|
56
|
+
loop do
|
|
57
|
+
@max_connections_cond.wait(@connection_mtx, @pool_timeout)
|
|
64
58
|
|
|
65
|
-
|
|
66
|
-
|
|
59
|
+
if (conn = acquire_connection(uri, options))
|
|
60
|
+
return conn
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# if one can afford to create a new connection, do it
|
|
64
|
+
break unless @connections_counter == @max_connections
|
|
65
|
+
|
|
66
|
+
# if no matching usable connection was found, the pool will make room and drop a closed connection.
|
|
67
|
+
if (conn = @connections.find { |c| c.state == :closed })
|
|
68
|
+
drop_connection(conn)
|
|
69
|
+
break
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# happens when a condition was signalled, but another thread snatched the available connection before
|
|
73
|
+
# context was passed back here.
|
|
74
|
+
next if Utils.now < expires_at
|
|
67
75
|
|
|
68
|
-
|
|
76
|
+
raise PoolTimeoutError.new(@pool_timeout,
|
|
77
|
+
"Timed out after #{@pool_timeout} seconds while waiting for a connection")
|
|
69
78
|
end
|
|
70
79
|
|
|
71
80
|
end
|
|
72
81
|
|
|
73
82
|
if @origin_counters[uri.origin] == @max_connections_per_origin
|
|
74
83
|
|
|
75
|
-
|
|
84
|
+
expires_at = Utils.now + @pool_timeout
|
|
85
|
+
|
|
86
|
+
loop do
|
|
87
|
+
@origin_conds[uri.origin].wait(@connection_mtx, @pool_timeout)
|
|
88
|
+
|
|
89
|
+
if (conn = acquire_connection(uri, options))
|
|
90
|
+
return conn
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# happens when a condition was signalled, but another thread snatched the available connection before
|
|
94
|
+
# context was passed back here.
|
|
95
|
+
next if Utils.now < expires_at
|
|
76
96
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
97
|
+
raise(PoolTimeoutError.new(@pool_timeout,
|
|
98
|
+
"Timed out after #{@pool_timeout} seconds while waiting for a connection to #{uri.origin}"))
|
|
99
|
+
end
|
|
80
100
|
end
|
|
81
101
|
|
|
82
102
|
@connections_counter += 1
|
|
@@ -91,6 +111,13 @@ module HTTPX
|
|
|
91
111
|
return if connection.options.io
|
|
92
112
|
|
|
93
113
|
@connection_mtx.synchronize do
|
|
114
|
+
if connection.coalesced? || connection.state == :idle
|
|
115
|
+
# when connections coalesce
|
|
116
|
+
drop_connection(connection)
|
|
117
|
+
|
|
118
|
+
return
|
|
119
|
+
end
|
|
120
|
+
|
|
94
121
|
@connections << connection
|
|
95
122
|
|
|
96
123
|
@max_connections_cond.signal
|
|
@@ -128,10 +155,16 @@ module HTTPX
|
|
|
128
155
|
end
|
|
129
156
|
|
|
130
157
|
def checkin_resolver(resolver)
|
|
131
|
-
|
|
132
|
-
|
|
158
|
+
resolver_class = resolver.class
|
|
159
|
+
|
|
160
|
+
resolver = resolver.multi
|
|
133
161
|
|
|
134
|
-
|
|
162
|
+
# a multi requires all sub-resolvers being closed in order to be
|
|
163
|
+
# correctly checked back in.
|
|
164
|
+
return unless resolver.closed?
|
|
165
|
+
|
|
166
|
+
@resolver_mtx.synchronize do
|
|
167
|
+
resolvers = @resolvers[resolver_class]
|
|
135
168
|
|
|
136
169
|
resolvers << resolver unless resolvers.include?(resolver)
|
|
137
170
|
end
|
|
@@ -140,6 +173,7 @@ module HTTPX
|
|
|
140
173
|
# :nocov:
|
|
141
174
|
def inspect
|
|
142
175
|
"#<#{self.class}:#{object_id} " \
|
|
176
|
+
"@max_connections=#{@max_connections} " \
|
|
143
177
|
"@max_connections_per_origin=#{@max_connections_per_origin} " \
|
|
144
178
|
"@pool_timeout=#{@pool_timeout} " \
|
|
145
179
|
"@connections=#{@connections.size}>"
|
data/lib/httpx/request.rb
CHANGED
|
@@ -14,9 +14,6 @@ module HTTPX
|
|
|
14
14
|
|
|
15
15
|
ALLOWED_URI_SCHEMES = %w[https http].freeze
|
|
16
16
|
|
|
17
|
-
# default value used for "user-agent" header, when not overridden.
|
|
18
|
-
USER_AGENT = "httpx.rb/#{VERSION}".freeze # rubocop:disable Style/RedundantFreeze
|
|
19
|
-
|
|
20
17
|
# the upcased string HTTP verb for this request.
|
|
21
18
|
attr_reader :verb
|
|
22
19
|
|
|
@@ -75,16 +72,6 @@ module HTTPX
|
|
|
75
72
|
@headers = options.headers.dup
|
|
76
73
|
merge_headers(params.delete(:headers)) if params.key?(:headers)
|
|
77
74
|
|
|
78
|
-
@headers["user-agent"] ||= USER_AGENT
|
|
79
|
-
@headers["accept"] ||= "*/*"
|
|
80
|
-
|
|
81
|
-
# forego compression in the Range request case
|
|
82
|
-
if @headers.key?("range")
|
|
83
|
-
@headers.delete("accept-encoding")
|
|
84
|
-
else
|
|
85
|
-
@headers["accept-encoding"] ||= options.supported_compression_formats
|
|
86
|
-
end
|
|
87
|
-
|
|
88
75
|
@query_params = params.delete(:params) if params.key?(:params)
|
|
89
76
|
|
|
90
77
|
@body = options.request_body_class.new(@headers, options, **params)
|
|
@@ -166,6 +153,9 @@ module HTTPX
|
|
|
166
153
|
# merges +h+ into the instance of HTTPX::Headers of the request.
|
|
167
154
|
def merge_headers(h)
|
|
168
155
|
@headers = @headers.merge(h)
|
|
156
|
+
return unless @headers.key?("range")
|
|
157
|
+
|
|
158
|
+
@headers.delete("accept-encoding")
|
|
169
159
|
end
|
|
170
160
|
|
|
171
161
|
# the URI scheme of the request +uri+.
|
data/lib/httpx/resolver/https.rb
CHANGED
|
@@ -30,7 +30,8 @@ module HTTPX
|
|
|
30
30
|
use_get: false,
|
|
31
31
|
}.freeze
|
|
32
32
|
|
|
33
|
-
def_delegators :@resolver_connection, :state, :connecting?, :to_io, :call, :close,
|
|
33
|
+
def_delegators :@resolver_connection, :state, :connecting?, :to_io, :call, :close,
|
|
34
|
+
:closed?, :deactivate, :terminate, :inflight?, :handle_socket_timeout
|
|
34
35
|
|
|
35
36
|
def initialize(_, options)
|
|
36
37
|
super
|
|
@@ -52,29 +53,24 @@ module HTTPX
|
|
|
52
53
|
if @uri_addresses.empty?
|
|
53
54
|
ex = ResolveError.new("Can't resolve DNS server #{@uri.host}")
|
|
54
55
|
ex.set_backtrace(caller)
|
|
55
|
-
connection.
|
|
56
|
+
connection.force_close
|
|
56
57
|
throw(:resolve_error, ex)
|
|
57
58
|
end
|
|
58
59
|
|
|
59
60
|
resolve(connection)
|
|
60
61
|
end
|
|
61
62
|
|
|
62
|
-
# This is already indirectly monitored bt the HTTP connection. In order to skip
|
|
63
|
-
# monitoring, this method returns <tt>true</tt>.
|
|
64
|
-
def closed?
|
|
65
|
-
true
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
def empty?
|
|
69
|
-
true
|
|
70
|
-
end
|
|
71
|
-
|
|
72
63
|
def resolver_connection
|
|
73
64
|
# TODO: leaks connection object into the pool
|
|
74
|
-
@resolver_connection ||=
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
65
|
+
@resolver_connection ||=
|
|
66
|
+
@current_session.find_connection(
|
|
67
|
+
@uri,
|
|
68
|
+
@current_selector,
|
|
69
|
+
@options.merge(resolver_class: :system, ssl: { alpn_protocols: %w[h2] })
|
|
70
|
+
).tap do |conn|
|
|
71
|
+
emit_addresses(conn, @family, @uri_addresses) unless conn.addresses
|
|
72
|
+
conn.on(:force_closed, &method(:force_close))
|
|
73
|
+
end
|
|
78
74
|
end
|
|
79
75
|
|
|
80
76
|
private
|
|
@@ -111,7 +107,9 @@ module HTTPX
|
|
|
111
107
|
@connections << connection
|
|
112
108
|
rescue ResolveError, Resolv::DNS::EncodeError => e
|
|
113
109
|
reset_hostname(hostname)
|
|
110
|
+
throw(:resolve_error, e) if connection.pending.empty?
|
|
114
111
|
emit_resolve_error(connection, connection.peer.host, e)
|
|
112
|
+
close_or_resolve
|
|
115
113
|
end
|
|
116
114
|
end
|
|
117
115
|
|
|
@@ -121,6 +119,7 @@ module HTTPX
|
|
|
121
119
|
hostname = @requests.delete(request)
|
|
122
120
|
connection = reset_hostname(hostname)
|
|
123
121
|
emit_resolve_error(connection, connection.peer.host, e)
|
|
122
|
+
close_or_resolve
|
|
124
123
|
else
|
|
125
124
|
# @type var response: HTTPX::Response
|
|
126
125
|
parse(request, response)
|
|
@@ -147,6 +146,7 @@ module HTTPX
|
|
|
147
146
|
|
|
148
147
|
unless @queries.value?(connection)
|
|
149
148
|
emit_resolve_error(connection)
|
|
149
|
+
close_or_resolve
|
|
150
150
|
return
|
|
151
151
|
end
|
|
152
152
|
|
|
@@ -156,10 +156,12 @@ module HTTPX
|
|
|
156
156
|
connection = reset_hostname(host)
|
|
157
157
|
|
|
158
158
|
emit_resolve_error(connection)
|
|
159
|
+
close_or_resolve
|
|
159
160
|
when :decode_error
|
|
160
161
|
host = @requests.delete(request)
|
|
161
162
|
connection = reset_hostname(host)
|
|
162
163
|
emit_resolve_error(connection, connection.peer.host, result)
|
|
164
|
+
close_or_resolve
|
|
163
165
|
end
|
|
164
166
|
end
|
|
165
167
|
|
|
@@ -169,6 +171,7 @@ module HTTPX
|
|
|
169
171
|
host = @requests.delete(request)
|
|
170
172
|
connection = reset_hostname(host)
|
|
171
173
|
emit_resolve_error(connection)
|
|
174
|
+
close_or_resolve
|
|
172
175
|
return
|
|
173
176
|
|
|
174
177
|
else
|
|
@@ -207,9 +210,7 @@ module HTTPX
|
|
|
207
210
|
catch(:coalesced) { emit_addresses(connection, @family, addresses.map { |a| Resolver::Entry.new(a["data"], a["TTL"]) }) }
|
|
208
211
|
end
|
|
209
212
|
end
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
resolve
|
|
213
|
+
close_or_resolve(true)
|
|
213
214
|
end
|
|
214
215
|
|
|
215
216
|
def build_request(hostname)
|
|
@@ -252,5 +253,20 @@ module HTTPX
|
|
|
252
253
|
|
|
253
254
|
connection
|
|
254
255
|
end
|
|
256
|
+
|
|
257
|
+
def close_or_resolve(should_deactivate = false)
|
|
258
|
+
# drop already closed connections
|
|
259
|
+
@connections.shift until @connections.empty? || @connections.first.state != :closed
|
|
260
|
+
|
|
261
|
+
if (@connections - @queries.values).empty?
|
|
262
|
+
if should_deactivate
|
|
263
|
+
deactivate
|
|
264
|
+
else
|
|
265
|
+
disconnect
|
|
266
|
+
end
|
|
267
|
+
else
|
|
268
|
+
resolve
|
|
269
|
+
end
|
|
270
|
+
end
|
|
255
271
|
end
|
|
256
272
|
end
|
data/lib/httpx/resolver/multi.rb
CHANGED
|
@@ -5,9 +5,6 @@ require "resolv"
|
|
|
5
5
|
|
|
6
6
|
module HTTPX
|
|
7
7
|
class Resolver::Multi
|
|
8
|
-
include Callbacks
|
|
9
|
-
using ArrayExtensions::FilterMap
|
|
10
|
-
|
|
11
8
|
attr_reader :resolvers, :options
|
|
12
9
|
|
|
13
10
|
def initialize(resolver_type, options)
|
|
@@ -28,52 +25,32 @@ module HTTPX
|
|
|
28
25
|
|
|
29
26
|
def current_selector=(s)
|
|
30
27
|
@current_selector = s
|
|
31
|
-
@resolvers.each { |r| r.
|
|
28
|
+
@resolvers.each { |r| r.current_selector = s }
|
|
32
29
|
end
|
|
33
30
|
|
|
34
31
|
def current_session=(s)
|
|
35
32
|
@current_session = s
|
|
36
|
-
@resolvers.each { |r| r.
|
|
33
|
+
@resolvers.each { |r| r.current_session = s }
|
|
37
34
|
end
|
|
38
35
|
|
|
39
36
|
def log(*args, **kwargs, &blk)
|
|
40
|
-
@resolvers.each { |r| r.
|
|
37
|
+
@resolvers.each { |r| r.log(*args, **kwargs, &blk) }
|
|
41
38
|
end
|
|
42
39
|
|
|
43
40
|
def closed?
|
|
44
41
|
@resolvers.all?(&:closed?)
|
|
45
42
|
end
|
|
46
43
|
|
|
47
|
-
def empty?
|
|
48
|
-
@resolvers.all?(&:empty?)
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def inflight?
|
|
52
|
-
@resolvers.any(&:inflight?)
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
def timeout
|
|
56
|
-
@resolvers.filter_map(&:timeout).min
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def close
|
|
60
|
-
@resolvers.each(&:close)
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
def connections
|
|
64
|
-
@resolvers.filter_map { |r| r.resolver_connection if r.respond_to?(:resolver_connection) }
|
|
65
|
-
end
|
|
66
|
-
|
|
67
44
|
def early_resolve(connection)
|
|
68
45
|
hostname = connection.peer.host
|
|
69
46
|
addresses = @resolver_options[:cache] && (connection.addresses || HTTPX::Resolver.nolookup_resolve(hostname))
|
|
70
47
|
return false unless addresses
|
|
71
48
|
|
|
72
|
-
ip_families = connection.options.ip_families
|
|
49
|
+
ip_families = connection.options.ip_families
|
|
73
50
|
|
|
74
51
|
resolved = false
|
|
75
52
|
addresses.group_by(&:family).sort { |(f1, _), (f2, _)| f2 <=> f1 }.each do |family, addrs|
|
|
76
|
-
next unless ip_families.include?(family)
|
|
53
|
+
next unless ip_families.nil? || ip_families.include?(family)
|
|
77
54
|
|
|
78
55
|
# try to match the resolver by family. However, there are cases where that's not possible, as when
|
|
79
56
|
# the system does not have IPv6 connectivity, but it does support IPv6 via loopback/link-local.
|
|
@@ -91,14 +68,14 @@ module HTTPX
|
|
|
91
68
|
end
|
|
92
69
|
|
|
93
70
|
def lazy_resolve(connection)
|
|
94
|
-
ip_families = connection.options.ip_families || Resolver.supported_ip_families
|
|
95
|
-
|
|
96
71
|
@resolvers.each do |resolver|
|
|
97
|
-
|
|
72
|
+
conn_to_resolve = @current_session.try_clone_connection(connection, @current_selector, resolver.family)
|
|
73
|
+
resolver << conn_to_resolve
|
|
98
74
|
|
|
99
|
-
resolver << @current_session.try_clone_connection(connection, @current_selector, resolver.family)
|
|
100
75
|
next if resolver.empty?
|
|
101
76
|
|
|
77
|
+
# both the resolver and the connection it's resolving must be pineed to the session
|
|
78
|
+
@current_session.pin(conn_to_resolve, @current_selector)
|
|
102
79
|
@current_session.select_resolver(resolver, @current_selector)
|
|
103
80
|
end
|
|
104
81
|
end
|
|
@@ -49,8 +49,19 @@ module HTTPX
|
|
|
49
49
|
transition(:closed)
|
|
50
50
|
end
|
|
51
51
|
|
|
52
|
+
def force_close(*)
|
|
53
|
+
@timer.cancel if @timer
|
|
54
|
+
@timer = @name = nil
|
|
55
|
+
@queries.clear
|
|
56
|
+
@timeouts.clear
|
|
57
|
+
close
|
|
58
|
+
super
|
|
59
|
+
ensure
|
|
60
|
+
terminate
|
|
61
|
+
end
|
|
62
|
+
|
|
52
63
|
def terminate
|
|
53
|
-
|
|
64
|
+
disconnect
|
|
54
65
|
end
|
|
55
66
|
|
|
56
67
|
def closed?
|
|
@@ -84,7 +95,7 @@ module HTTPX
|
|
|
84
95
|
if @nameserver.nil?
|
|
85
96
|
ex = ResolveError.new("No available nameserver")
|
|
86
97
|
ex.set_backtrace(caller)
|
|
87
|
-
connection.
|
|
98
|
+
connection.force_close
|
|
88
99
|
throw(:resolve_error, ex)
|
|
89
100
|
else
|
|
90
101
|
@connections << connection
|
|
@@ -93,15 +104,34 @@ module HTTPX
|
|
|
93
104
|
end
|
|
94
105
|
|
|
95
106
|
def timeout
|
|
96
|
-
return
|
|
107
|
+
return unless @name
|
|
97
108
|
|
|
98
109
|
@start_timeout = Utils.now
|
|
99
|
-
|
|
100
|
-
@timeouts
|
|
110
|
+
|
|
111
|
+
timeouts = @timeouts[@name]
|
|
112
|
+
|
|
113
|
+
return if timeouts.empty?
|
|
114
|
+
|
|
115
|
+
log(level: 2) { "resolver #{FAMILY_TYPES[@record_type]}: next timeout #{timeouts.first} secs... (#{timeouts.size - 1} left)" }
|
|
116
|
+
|
|
117
|
+
timeouts.first
|
|
101
118
|
end
|
|
102
119
|
|
|
103
120
|
def handle_socket_timeout(interval); end
|
|
104
121
|
|
|
122
|
+
def handle_error(error)
|
|
123
|
+
if error.respond_to?(:connection) &&
|
|
124
|
+
error.respond_to?(:host)
|
|
125
|
+
reset_hostname(error.host, connection: error.connection)
|
|
126
|
+
else
|
|
127
|
+
@queries.each do |host, connection|
|
|
128
|
+
reset_hostname(host, connection: connection)
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
super
|
|
133
|
+
end
|
|
134
|
+
|
|
105
135
|
private
|
|
106
136
|
|
|
107
137
|
def calculate_interests
|
|
@@ -118,7 +148,6 @@ module HTTPX
|
|
|
118
148
|
|
|
119
149
|
break unless calculate_interests == :w
|
|
120
150
|
|
|
121
|
-
# do_retry
|
|
122
151
|
dwrite
|
|
123
152
|
|
|
124
153
|
break unless calculate_interests == :r
|
|
@@ -133,7 +162,7 @@ module HTTPX
|
|
|
133
162
|
retry
|
|
134
163
|
else
|
|
135
164
|
handle_error(e)
|
|
136
|
-
|
|
165
|
+
disconnect
|
|
137
166
|
end
|
|
138
167
|
rescue NativeResolveError => e
|
|
139
168
|
handle_error(e)
|
|
@@ -154,7 +183,7 @@ module HTTPX
|
|
|
154
183
|
@timer = @current_selector.after(timeout) do
|
|
155
184
|
next unless @connections.include?(connection)
|
|
156
185
|
|
|
157
|
-
@timer = nil
|
|
186
|
+
@timer = @name = nil
|
|
158
187
|
|
|
159
188
|
do_retry(h, connection, timeout)
|
|
160
189
|
end
|
|
@@ -178,8 +207,6 @@ module HTTPX
|
|
|
178
207
|
@timeouts.clear
|
|
179
208
|
resolve(connection, h)
|
|
180
209
|
else
|
|
181
|
-
|
|
182
|
-
@timeouts.delete(h)
|
|
183
210
|
reset_hostname(h, reset_candidates: false)
|
|
184
211
|
|
|
185
212
|
unless @queries.empty?
|
|
@@ -273,7 +300,7 @@ module HTTPX
|
|
|
273
300
|
def parse(buffer)
|
|
274
301
|
@timer.cancel
|
|
275
302
|
|
|
276
|
-
@timer = nil
|
|
303
|
+
@timer = @name = nil
|
|
277
304
|
|
|
278
305
|
code, result = Resolver.decode_dns_answer(buffer)
|
|
279
306
|
|
|
@@ -431,13 +458,14 @@ module HTTPX
|
|
|
431
458
|
def generate_candidates(name)
|
|
432
459
|
return [name] if name.end_with?(".")
|
|
433
460
|
|
|
434
|
-
candidates = []
|
|
435
461
|
name_parts = name.scan(/[^.]+/)
|
|
436
|
-
candidates =
|
|
437
|
-
candidates.concat(@search.map { |domain| [*name_parts, *domain].join(".") })
|
|
462
|
+
candidates = @search.map { |domain| [*name_parts, *domain].join(".") }
|
|
438
463
|
fname = "#{name}."
|
|
439
|
-
|
|
440
|
-
|
|
464
|
+
if @ndots <= name_parts.size - 1
|
|
465
|
+
candidates.unshift(fname)
|
|
466
|
+
else
|
|
467
|
+
candidates << fname
|
|
468
|
+
end
|
|
441
469
|
candidates
|
|
442
470
|
end
|
|
443
471
|
|
|
@@ -498,27 +526,7 @@ module HTTPX
|
|
|
498
526
|
ConnectTimeoutError => e
|
|
499
527
|
# these errors may happen during TCP handshake
|
|
500
528
|
# treat them as resolve errors.
|
|
501
|
-
|
|
502
|
-
emit(:close, self)
|
|
503
|
-
end
|
|
504
|
-
|
|
505
|
-
def handle_error(error)
|
|
506
|
-
if error.respond_to?(:connection) &&
|
|
507
|
-
error.respond_to?(:host)
|
|
508
|
-
reset_hostname(error.host, connection: error.connection)
|
|
509
|
-
@connections.delete(error.connection)
|
|
510
|
-
emit_resolve_error(error.connection, error.host, error)
|
|
511
|
-
else
|
|
512
|
-
@queries.each do |host, connection|
|
|
513
|
-
reset_hostname(host, connection: connection)
|
|
514
|
-
@connections.delete(connection)
|
|
515
|
-
emit_resolve_error(connection, host, error)
|
|
516
|
-
end
|
|
517
|
-
|
|
518
|
-
while (connection = @connections.shift)
|
|
519
|
-
emit_resolve_error(connection, connection.peer.host, error)
|
|
520
|
-
end
|
|
521
|
-
end
|
|
529
|
+
on_error(e)
|
|
522
530
|
end
|
|
523
531
|
|
|
524
532
|
def reset_hostname(hostname, connection: @queries.delete(hostname), reset_candidates: true)
|
|
@@ -538,7 +546,7 @@ module HTTPX
|
|
|
538
546
|
@connections.shift until @connections.empty? || @connections.first.state != :closed
|
|
539
547
|
|
|
540
548
|
if (@connections - @queries.values).empty?
|
|
541
|
-
|
|
549
|
+
disconnect
|
|
542
550
|
else
|
|
543
551
|
resolve
|
|
544
552
|
end
|