httpx 1.6.2 → 1.7.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.
- checksums.yaml +4 -4
- data/doc/release_notes/0_11_0.md +3 -3
- data/doc/release_notes/1_6_3.md +47 -0
- data/doc/release_notes/1_7_0.md +149 -0
- data/lib/httpx/adapters/datadog.rb +1 -1
- data/lib/httpx/adapters/faraday.rb +1 -1
- data/lib/httpx/adapters/sentry.rb +1 -1
- data/lib/httpx/altsvc.rb +3 -1
- data/lib/httpx/connection/http1.rb +14 -15
- data/lib/httpx/connection/http2.rb +16 -15
- data/lib/httpx/connection.rb +118 -110
- data/lib/httpx/domain_name.rb +1 -1
- data/lib/httpx/extensions.rb +0 -14
- data/lib/httpx/headers.rb +2 -2
- data/lib/httpx/io/ssl.rb +1 -1
- data/lib/httpx/loggable.rb +14 -2
- data/lib/httpx/options.rb +60 -17
- data/lib/httpx/plugins/auth/digest.rb +44 -4
- data/lib/httpx/plugins/auth.rb +87 -4
- data/lib/httpx/plugins/aws_sdk_authentication.rb +0 -1
- data/lib/httpx/plugins/callbacks.rb +15 -1
- data/lib/httpx/plugins/cookies/cookie.rb +1 -0
- data/lib/httpx/plugins/digest_auth.rb +4 -5
- data/lib/httpx/plugins/fiber_concurrency.rb +16 -1
- data/lib/httpx/plugins/grpc/grpc_encoding.rb +1 -1
- data/lib/httpx/plugins/grpc.rb +2 -2
- data/lib/httpx/plugins/internal_telemetry.rb +1 -1
- data/lib/httpx/plugins/ntlm_auth.rb +5 -3
- data/lib/httpx/plugins/oauth.rb +162 -56
- data/lib/httpx/plugins/proxy/http.rb +37 -9
- data/lib/httpx/plugins/rate_limiter.rb +2 -2
- data/lib/httpx/plugins/response_cache/file_store.rb +1 -0
- data/lib/httpx/plugins/response_cache.rb +16 -9
- data/lib/httpx/plugins/retries.rb +55 -16
- data/lib/httpx/plugins/ssrf_filter.rb +1 -1
- data/lib/httpx/plugins/stream.rb +59 -8
- data/lib/httpx/plugins/stream_bidi.rb +87 -22
- data/lib/httpx/pool.rb +65 -21
- data/lib/httpx/request.rb +13 -14
- data/lib/httpx/resolver/https.rb +100 -34
- data/lib/httpx/resolver/multi.rb +12 -27
- data/lib/httpx/resolver/native.rb +68 -38
- data/lib/httpx/resolver/resolver.rb +46 -29
- data/lib/httpx/resolver/system.rb +63 -39
- data/lib/httpx/resolver.rb +97 -29
- data/lib/httpx/response/body.rb +2 -0
- data/lib/httpx/response.rb +22 -6
- data/lib/httpx/selector.rb +44 -20
- data/lib/httpx/session.rb +23 -33
- data/lib/httpx/transcoder/body.rb +1 -1
- data/lib/httpx/transcoder/deflate.rb +13 -8
- data/lib/httpx/transcoder/json.rb +1 -1
- data/lib/httpx/transcoder/multipart/decoder.rb +4 -4
- data/lib/httpx/transcoder/multipart/encoder.rb +1 -1
- data/lib/httpx/transcoder/multipart.rb +16 -8
- data/lib/httpx/transcoder/utils/body_reader.rb +1 -2
- data/lib/httpx/transcoder/utils/deflater.rb +1 -2
- data/lib/httpx/transcoder.rb +4 -6
- data/lib/httpx/version.rb +1 -1
- data/sig/altsvc.rbs +3 -0
- data/sig/chainable.rbs +3 -3
- data/sig/connection.rbs +13 -6
- data/sig/loggable.rbs +5 -1
- data/sig/options.rbs +6 -2
- data/sig/plugins/auth/digest.rbs +6 -0
- data/sig/plugins/auth.rbs +28 -4
- data/sig/plugins/basic_auth.rbs +3 -3
- data/sig/plugins/callbacks.rbs +3 -0
- data/sig/plugins/digest_auth.rbs +2 -4
- data/sig/plugins/fiber_concurrency.rbs +6 -0
- data/sig/plugins/ntlm_auth.rbs +2 -2
- data/sig/plugins/oauth.rbs +46 -15
- data/sig/plugins/rate_limiter.rbs +1 -1
- data/sig/plugins/response_cache/file_store.rbs +2 -0
- data/sig/plugins/response_cache.rbs +4 -0
- data/sig/plugins/retries.rbs +8 -2
- data/sig/plugins/stream.rbs +13 -3
- data/sig/plugins/stream_bidi.rbs +5 -7
- data/sig/pool.rbs +1 -1
- data/sig/resolver/https.rbs +7 -0
- data/sig/resolver/multi.rbs +2 -9
- data/sig/resolver/native.rbs +1 -1
- data/sig/resolver/resolver.rbs +9 -8
- data/sig/resolver/system.rbs +4 -2
- data/sig/resolver.rbs +12 -3
- data/sig/response.rbs +3 -0
- data/sig/selector.rbs +2 -0
- data/sig/session.rbs +8 -8
- data/sig/transcoder/multipart.rbs +4 -2
- data/sig/transcoder.rbs +5 -1
- metadata +5 -1
|
@@ -9,6 +9,7 @@ module HTTPX
|
|
|
9
9
|
#
|
|
10
10
|
class Resolver::Native < Resolver::Resolver
|
|
11
11
|
extend Forwardable
|
|
12
|
+
|
|
12
13
|
using URIExtensions
|
|
13
14
|
|
|
14
15
|
DEFAULTS = {
|
|
@@ -49,8 +50,19 @@ module HTTPX
|
|
|
49
50
|
transition(:closed)
|
|
50
51
|
end
|
|
51
52
|
|
|
53
|
+
def force_close(*)
|
|
54
|
+
@timer.cancel if @timer
|
|
55
|
+
@timer = @name = nil
|
|
56
|
+
@queries.clear
|
|
57
|
+
@timeouts.clear
|
|
58
|
+
close
|
|
59
|
+
super
|
|
60
|
+
ensure
|
|
61
|
+
terminate
|
|
62
|
+
end
|
|
63
|
+
|
|
52
64
|
def terminate
|
|
53
|
-
|
|
65
|
+
disconnect
|
|
54
66
|
end
|
|
55
67
|
|
|
56
68
|
def closed?
|
|
@@ -84,7 +96,7 @@ module HTTPX
|
|
|
84
96
|
if @nameserver.nil?
|
|
85
97
|
ex = ResolveError.new("No available nameserver")
|
|
86
98
|
ex.set_backtrace(caller)
|
|
87
|
-
connection.
|
|
99
|
+
connection.force_close
|
|
88
100
|
throw(:resolve_error, ex)
|
|
89
101
|
else
|
|
90
102
|
@connections << connection
|
|
@@ -93,15 +105,34 @@ module HTTPX
|
|
|
93
105
|
end
|
|
94
106
|
|
|
95
107
|
def timeout
|
|
96
|
-
return
|
|
108
|
+
return unless @name
|
|
97
109
|
|
|
98
110
|
@start_timeout = Utils.now
|
|
99
|
-
|
|
100
|
-
@timeouts
|
|
111
|
+
|
|
112
|
+
timeouts = @timeouts[@name]
|
|
113
|
+
|
|
114
|
+
return if timeouts.empty?
|
|
115
|
+
|
|
116
|
+
log(level: 2) { "resolver #{FAMILY_TYPES[@record_type]}: next timeout #{timeouts.first} secs... (#{timeouts.size - 1} left)" }
|
|
117
|
+
|
|
118
|
+
timeouts.first
|
|
101
119
|
end
|
|
102
120
|
|
|
103
121
|
def handle_socket_timeout(interval); end
|
|
104
122
|
|
|
123
|
+
def handle_error(error)
|
|
124
|
+
if error.respond_to?(:connection) &&
|
|
125
|
+
error.respond_to?(:host)
|
|
126
|
+
reset_hostname(error.host, connection: error.connection)
|
|
127
|
+
else
|
|
128
|
+
@queries.each do |host, connection|
|
|
129
|
+
reset_hostname(host, connection: connection)
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
super
|
|
134
|
+
end
|
|
135
|
+
|
|
105
136
|
private
|
|
106
137
|
|
|
107
138
|
def calculate_interests
|
|
@@ -118,7 +149,6 @@ module HTTPX
|
|
|
118
149
|
|
|
119
150
|
break unless calculate_interests == :w
|
|
120
151
|
|
|
121
|
-
# do_retry
|
|
122
152
|
dwrite
|
|
123
153
|
|
|
124
154
|
break unless calculate_interests == :r
|
|
@@ -133,7 +163,7 @@ module HTTPX
|
|
|
133
163
|
retry
|
|
134
164
|
else
|
|
135
165
|
handle_error(e)
|
|
136
|
-
|
|
166
|
+
disconnect
|
|
137
167
|
end
|
|
138
168
|
rescue NativeResolveError => e
|
|
139
169
|
handle_error(e)
|
|
@@ -154,7 +184,7 @@ module HTTPX
|
|
|
154
184
|
@timer = @current_selector.after(timeout) do
|
|
155
185
|
next unless @connections.include?(connection)
|
|
156
186
|
|
|
157
|
-
@timer = nil
|
|
187
|
+
@timer = @name = nil
|
|
158
188
|
|
|
159
189
|
do_retry(h, connection, timeout)
|
|
160
190
|
end
|
|
@@ -178,8 +208,6 @@ module HTTPX
|
|
|
178
208
|
@timeouts.clear
|
|
179
209
|
resolve(connection, h)
|
|
180
210
|
else
|
|
181
|
-
|
|
182
|
-
@timeouts.delete(h)
|
|
183
211
|
reset_hostname(h, reset_candidates: false)
|
|
184
212
|
|
|
185
213
|
unless @queries.empty?
|
|
@@ -271,16 +299,14 @@ module HTTPX
|
|
|
271
299
|
end
|
|
272
300
|
|
|
273
301
|
def parse(buffer)
|
|
274
|
-
@timer.cancel
|
|
275
|
-
|
|
276
|
-
@timer = nil
|
|
277
|
-
|
|
278
302
|
code, result = Resolver.decode_dns_answer(buffer)
|
|
279
303
|
|
|
280
304
|
case code
|
|
281
305
|
when :ok
|
|
306
|
+
reset_query
|
|
282
307
|
parse_addresses(result)
|
|
283
308
|
when :no_domain_found
|
|
309
|
+
reset_query
|
|
284
310
|
# Indicates no such domain was found.
|
|
285
311
|
hostname, connection = @queries.first
|
|
286
312
|
reset_hostname(hostname, reset_candidates: false)
|
|
@@ -297,6 +323,7 @@ module HTTPX
|
|
|
297
323
|
close_or_resolve
|
|
298
324
|
end
|
|
299
325
|
when :message_truncated
|
|
326
|
+
reset_query
|
|
300
327
|
# TODO: what to do if it's already tcp??
|
|
301
328
|
return if @socket_type == :tcp
|
|
302
329
|
|
|
@@ -305,13 +332,29 @@ module HTTPX
|
|
|
305
332
|
hostname, _ = @queries.first
|
|
306
333
|
reset_hostname(hostname)
|
|
307
334
|
transition(:closed)
|
|
335
|
+
when :retriable_error
|
|
336
|
+
if @name && @timer
|
|
337
|
+
log { "resolver #{FAMILY_TYPES[@record_type]}: failed, but will retry..." }
|
|
338
|
+
return
|
|
339
|
+
end
|
|
340
|
+
# retry now!
|
|
341
|
+
# connection = @queries[@name].shift
|
|
342
|
+
# @timer.fire
|
|
343
|
+
reset_query
|
|
344
|
+
hostname, connection = @queries.first
|
|
345
|
+
reset_hostname(hostname)
|
|
346
|
+
@connections.delete(connection)
|
|
347
|
+
ex = NativeResolveError.new(connection, connection.peer.host, "unknown DNS error (error code #{result})")
|
|
348
|
+
raise ex
|
|
308
349
|
when :dns_error
|
|
350
|
+
reset_query
|
|
309
351
|
hostname, connection = @queries.first
|
|
310
352
|
reset_hostname(hostname)
|
|
311
353
|
@connections.delete(connection)
|
|
312
354
|
ex = NativeResolveError.new(connection, connection.peer.host, "unknown DNS error (error code #{result})")
|
|
313
355
|
raise ex
|
|
314
356
|
when :decode_error
|
|
357
|
+
reset_query
|
|
315
358
|
hostname, connection = @queries.first
|
|
316
359
|
reset_hostname(hostname)
|
|
317
360
|
@connections.delete(connection)
|
|
@@ -431,13 +474,14 @@ module HTTPX
|
|
|
431
474
|
def generate_candidates(name)
|
|
432
475
|
return [name] if name.end_with?(".")
|
|
433
476
|
|
|
434
|
-
candidates = []
|
|
435
477
|
name_parts = name.scan(/[^.]+/)
|
|
436
|
-
candidates =
|
|
437
|
-
candidates.concat(@search.map { |domain| [*name_parts, *domain].join(".") })
|
|
478
|
+
candidates = @search.map { |domain| [*name_parts, *domain].join(".") }
|
|
438
479
|
fname = "#{name}."
|
|
439
|
-
|
|
440
|
-
|
|
480
|
+
if @ndots <= name_parts.size - 1
|
|
481
|
+
candidates.unshift(fname)
|
|
482
|
+
else
|
|
483
|
+
candidates << fname
|
|
484
|
+
end
|
|
441
485
|
candidates
|
|
442
486
|
end
|
|
443
487
|
|
|
@@ -498,27 +542,13 @@ module HTTPX
|
|
|
498
542
|
ConnectTimeoutError => e
|
|
499
543
|
# these errors may happen during TCP handshake
|
|
500
544
|
# treat them as resolve errors.
|
|
501
|
-
|
|
502
|
-
emit(:close, self)
|
|
545
|
+
on_error(e)
|
|
503
546
|
end
|
|
504
547
|
|
|
505
|
-
def
|
|
506
|
-
|
|
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
|
|
548
|
+
def reset_query
|
|
549
|
+
@timer.cancel
|
|
517
550
|
|
|
518
|
-
|
|
519
|
-
emit_resolve_error(connection, connection.peer.host, error)
|
|
520
|
-
end
|
|
521
|
-
end
|
|
551
|
+
@timer = @name = nil
|
|
522
552
|
end
|
|
523
553
|
|
|
524
554
|
def reset_hostname(hostname, connection: @queries.delete(hostname), reset_candidates: true)
|
|
@@ -538,7 +568,7 @@ module HTTPX
|
|
|
538
568
|
@connections.shift until @connections.empty? || @connections.first.state != :closed
|
|
539
569
|
|
|
540
570
|
if (@connections - @queries.values).empty?
|
|
541
|
-
|
|
571
|
+
disconnect
|
|
542
572
|
else
|
|
543
573
|
resolve
|
|
544
574
|
end
|
|
@@ -7,7 +7,6 @@ module HTTPX
|
|
|
7
7
|
# from the Selectable API.
|
|
8
8
|
#
|
|
9
9
|
class Resolver::Resolver
|
|
10
|
-
include Callbacks
|
|
11
10
|
include Loggable
|
|
12
11
|
|
|
13
12
|
using ArrayExtensions::Intersect
|
|
@@ -39,8 +38,6 @@ module HTTPX
|
|
|
39
38
|
@record_type = RECORD_TYPES[family]
|
|
40
39
|
@options = options
|
|
41
40
|
@connections = []
|
|
42
|
-
|
|
43
|
-
set_resolver_callbacks
|
|
44
41
|
end
|
|
45
42
|
|
|
46
43
|
def each_connection(&block)
|
|
@@ -55,6 +52,12 @@ module HTTPX
|
|
|
55
52
|
|
|
56
53
|
alias_method :terminate, :close
|
|
57
54
|
|
|
55
|
+
def force_close(*args)
|
|
56
|
+
while (connection = @connections.shift)
|
|
57
|
+
connection.force_close(*args)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
58
61
|
def closed?
|
|
59
62
|
true
|
|
60
63
|
end
|
|
@@ -72,7 +75,7 @@ module HTTPX
|
|
|
72
75
|
|
|
73
76
|
# double emission check, but allow early resolution to work
|
|
74
77
|
conn_addrs = connection.addresses
|
|
75
|
-
return if !early_resolve && conn_addrs &&
|
|
78
|
+
return if !early_resolve && conn_addrs && !conn_addrs.empty? && !addresses.intersect?(conn_addrs)
|
|
76
79
|
|
|
77
80
|
log do
|
|
78
81
|
"resolver #{FAMILY_TYPES[RECORD_TYPES[family]]}: " \
|
|
@@ -104,26 +107,24 @@ module HTTPX
|
|
|
104
107
|
end
|
|
105
108
|
end
|
|
106
109
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
connection.
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
emit(:resolve, connection)
|
|
116
|
-
rescue StandardError => e
|
|
117
|
-
if early_resolve
|
|
118
|
-
connection.force_reset
|
|
119
|
-
throw(:resolve_error, e)
|
|
120
|
-
else
|
|
121
|
-
emit(:error, connection, e)
|
|
110
|
+
def handle_error(error)
|
|
111
|
+
if error.respond_to?(:connection) &&
|
|
112
|
+
error.respond_to?(:host)
|
|
113
|
+
@connections.delete(error.connection)
|
|
114
|
+
emit_resolve_error(error.connection, error.host, error)
|
|
115
|
+
else
|
|
116
|
+
while (connection = @connections.shift)
|
|
117
|
+
emit_resolve_error(connection, connection.peer.host, error)
|
|
122
118
|
end
|
|
123
119
|
end
|
|
124
120
|
end
|
|
125
121
|
|
|
126
|
-
def
|
|
122
|
+
def on_error(error)
|
|
123
|
+
handle_error(error)
|
|
124
|
+
disconnect
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def early_resolve(connection, hostname: connection.peer.host) # rubocop:disable Naming/PredicateMethod
|
|
127
128
|
addresses = @resolver_options[:cache] && (connection.addresses || HTTPX::Resolver.nolookup_resolve(hostname))
|
|
128
129
|
|
|
129
130
|
return false unless addresses
|
|
@@ -137,6 +138,25 @@ module HTTPX
|
|
|
137
138
|
true
|
|
138
139
|
end
|
|
139
140
|
|
|
141
|
+
private
|
|
142
|
+
|
|
143
|
+
def emit_resolved_connection(connection, addresses, early_resolve)
|
|
144
|
+
begin
|
|
145
|
+
connection.addresses = addresses
|
|
146
|
+
|
|
147
|
+
return if connection.state == :closed
|
|
148
|
+
|
|
149
|
+
resolve_connection(connection)
|
|
150
|
+
rescue StandardError => e
|
|
151
|
+
if early_resolve
|
|
152
|
+
connection.force_close
|
|
153
|
+
throw(:resolve_error, e)
|
|
154
|
+
else
|
|
155
|
+
emit_connection_error(connection, e)
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
140
160
|
def emit_resolve_error(connection, hostname = connection.peer.host, ex = nil)
|
|
141
161
|
emit_connection_error(connection, resolve_error(hostname, ex))
|
|
142
162
|
end
|
|
@@ -150,12 +170,6 @@ module HTTPX
|
|
|
150
170
|
error
|
|
151
171
|
end
|
|
152
172
|
|
|
153
|
-
def set_resolver_callbacks
|
|
154
|
-
on(:resolve, &method(:resolve_connection))
|
|
155
|
-
on(:error, &method(:emit_connection_error))
|
|
156
|
-
on(:close, &method(:close_resolver))
|
|
157
|
-
end
|
|
158
|
-
|
|
159
173
|
def resolve_connection(connection)
|
|
160
174
|
@current_session.__send__(:on_resolver_connection, connection, @current_selector)
|
|
161
175
|
end
|
|
@@ -163,11 +177,14 @@ module HTTPX
|
|
|
163
177
|
def emit_connection_error(connection, error)
|
|
164
178
|
return connection.handle_connect_error(error) if connection.connecting?
|
|
165
179
|
|
|
166
|
-
connection.
|
|
180
|
+
connection.on_error(error)
|
|
167
181
|
end
|
|
168
182
|
|
|
169
|
-
def
|
|
170
|
-
|
|
183
|
+
def disconnect
|
|
184
|
+
return if closed?
|
|
185
|
+
|
|
186
|
+
close
|
|
187
|
+
@current_session.deselect_resolver(self, @current_selector)
|
|
171
188
|
end
|
|
172
189
|
end
|
|
173
190
|
end
|
|
@@ -56,13 +56,21 @@ module HTTPX
|
|
|
56
56
|
end
|
|
57
57
|
|
|
58
58
|
def empty?
|
|
59
|
-
|
|
59
|
+
@connections.empty?
|
|
60
60
|
end
|
|
61
61
|
|
|
62
62
|
def close
|
|
63
63
|
transition(:closed)
|
|
64
64
|
end
|
|
65
65
|
|
|
66
|
+
def force_close(*)
|
|
67
|
+
close
|
|
68
|
+
@queries.clear
|
|
69
|
+
@timeouts.clear
|
|
70
|
+
@ips.clear
|
|
71
|
+
super
|
|
72
|
+
end
|
|
73
|
+
|
|
66
74
|
def closed?
|
|
67
75
|
@state == :closed
|
|
68
76
|
end
|
|
@@ -86,36 +94,42 @@ module HTTPX
|
|
|
86
94
|
end
|
|
87
95
|
|
|
88
96
|
def timeout
|
|
89
|
-
return unless @queries.empty?
|
|
90
|
-
|
|
91
97
|
_, connection = @queries.first
|
|
92
98
|
|
|
93
99
|
return unless connection
|
|
94
100
|
|
|
95
|
-
@timeouts[connection.peer.host]
|
|
101
|
+
timeouts = @timeouts[connection.peer.host]
|
|
102
|
+
|
|
103
|
+
return if timeouts.empty?
|
|
104
|
+
|
|
105
|
+
log(level: 2) { "resolver #{FAMILY_TYPES[@record_type]}: next timeout #{timeouts.first} secs... (#{timeouts.size - 1} left)" }
|
|
106
|
+
|
|
107
|
+
timeouts.first
|
|
96
108
|
end
|
|
97
109
|
|
|
98
|
-
def
|
|
110
|
+
def lazy_resolve(connection)
|
|
99
111
|
@connections << connection
|
|
100
112
|
resolve
|
|
101
|
-
end
|
|
102
113
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
114
|
+
return if empty?
|
|
115
|
+
|
|
116
|
+
@current_session.select_resolver(self, @current_selector)
|
|
106
117
|
end
|
|
107
118
|
|
|
119
|
+
def early_resolve(connection, **); end
|
|
120
|
+
|
|
108
121
|
def handle_socket_timeout(interval)
|
|
109
122
|
error = HTTPX::ResolveTimeoutError.new(interval, "timed out while waiting on select")
|
|
110
123
|
error.set_backtrace(caller)
|
|
111
|
-
@queries.each do |
|
|
112
|
-
@connections.delete(connection)
|
|
113
|
-
emit_resolve_error(connection, host, error)
|
|
124
|
+
@queries.each do |_, connection| # rubocop:disable Style/HashEachMethods
|
|
125
|
+
emit_resolve_error(connection, connection.peer.host, error) if @connections.delete(connection)
|
|
114
126
|
end
|
|
115
127
|
|
|
116
128
|
while (connection = @connections.shift)
|
|
117
129
|
emit_resolve_error(connection, connection.peer.host, error)
|
|
118
130
|
end
|
|
131
|
+
|
|
132
|
+
close_or_resolve
|
|
119
133
|
end
|
|
120
134
|
|
|
121
135
|
private
|
|
@@ -140,34 +154,38 @@ module HTTPX
|
|
|
140
154
|
def consume
|
|
141
155
|
return if @connections.empty?
|
|
142
156
|
|
|
143
|
-
|
|
144
|
-
event = @pipe_read.getbyte
|
|
157
|
+
event = @pipe_read.read_nonblock(1, exception: false)
|
|
145
158
|
|
|
146
|
-
|
|
147
|
-
when DONE
|
|
148
|
-
*pair, addrs = @pipe_mutex.synchronize { @ips.pop }
|
|
149
|
-
if pair
|
|
150
|
-
@queries.delete(pair)
|
|
151
|
-
family, connection = pair
|
|
152
|
-
@connections.delete(connection)
|
|
159
|
+
return if event == :wait_readable
|
|
153
160
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
161
|
+
raise ResolveError, "socket pipe closed unexpectedly" if event.nil?
|
|
162
|
+
|
|
163
|
+
case event.unpack1("C")
|
|
164
|
+
when DONE
|
|
165
|
+
*pair, addrs = @pipe_mutex.synchronize { @ips.pop }
|
|
166
|
+
if pair
|
|
167
|
+
@queries.delete(pair)
|
|
168
|
+
family, connection = pair
|
|
169
|
+
@connections.delete(connection)
|
|
170
|
+
|
|
171
|
+
catch(:coalesced) { emit_addresses(connection, family, addrs) }
|
|
172
|
+
end
|
|
173
|
+
when ERROR
|
|
174
|
+
*pair, error = @pipe_mutex.synchronize { @ips.pop }
|
|
175
|
+
if pair && error
|
|
176
|
+
@queries.delete(pair)
|
|
177
|
+
_, connection = pair
|
|
178
|
+
@connections.delete(connection)
|
|
179
|
+
|
|
180
|
+
emit_resolve_error(connection, connection.peer.host, error)
|
|
165
181
|
end
|
|
166
182
|
end
|
|
167
183
|
|
|
168
|
-
return
|
|
184
|
+
return disconnect if @connections.empty?
|
|
169
185
|
|
|
170
186
|
resolve
|
|
187
|
+
rescue StandardError => e
|
|
188
|
+
on_error(e)
|
|
171
189
|
end
|
|
172
190
|
|
|
173
191
|
def resolve(connection = nil, hostname = nil)
|
|
@@ -240,16 +258,22 @@ module HTTPX
|
|
|
240
258
|
end
|
|
241
259
|
end
|
|
242
260
|
end
|
|
261
|
+
Thread.pass
|
|
243
262
|
end
|
|
244
263
|
|
|
245
|
-
def
|
|
246
|
-
|
|
247
|
-
|
|
264
|
+
def close_or_resolve
|
|
265
|
+
# drop already closed connections
|
|
266
|
+
@connections.shift until @connections.empty? || @connections.first.state != :closed
|
|
248
267
|
|
|
249
|
-
|
|
250
|
-
|
|
268
|
+
if (@connections - @queries.map(&:last)).empty?
|
|
269
|
+
disconnect
|
|
270
|
+
else
|
|
271
|
+
resolve
|
|
272
|
+
end
|
|
251
273
|
end
|
|
252
274
|
|
|
253
|
-
def
|
|
275
|
+
def __addrinfo_resolve(host, scheme)
|
|
276
|
+
Addrinfo.getaddrinfo(host, scheme, Socket::AF_UNSPEC, Socket::SOCK_STREAM)
|
|
277
|
+
end
|
|
254
278
|
end
|
|
255
279
|
end
|