httpx 1.7.5 → 1.7.7
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_7_4.md +1 -1
- data/doc/release_notes/1_7_6.md +24 -0
- data/doc/release_notes/1_7_7.md +17 -0
- data/lib/httpx/adapters/datadog.rb +14 -1
- data/lib/httpx/adapters/faraday.rb +0 -10
- data/lib/httpx/adapters/webmock.rb +1 -1
- data/lib/httpx/altsvc.rb +4 -2
- data/lib/httpx/connection/http1.rb +52 -43
- data/lib/httpx/connection/http2.rb +23 -16
- data/lib/httpx/connection.rb +80 -43
- data/lib/httpx/io/ssl.rb +24 -12
- data/lib/httpx/io/tcp.rb +18 -12
- data/lib/httpx/io/unix.rb +13 -9
- data/lib/httpx/loggable.rb +1 -1
- data/lib/httpx/options.rb +23 -7
- data/lib/httpx/parser/http1.rb +14 -5
- data/lib/httpx/plugins/auth/digest.rb +6 -0
- data/lib/httpx/plugins/auth.rb +23 -9
- data/lib/httpx/plugins/circuit_breaker/circuit.rb +1 -0
- data/lib/httpx/plugins/cookies/cookie.rb +0 -1
- data/lib/httpx/plugins/digest_auth.rb +3 -1
- data/lib/httpx/plugins/follow_redirects.rb +13 -1
- data/lib/httpx/plugins/h2c.rb +2 -12
- data/lib/httpx/plugins/proxy/http.rb +1 -1
- data/lib/httpx/plugins/proxy.rb +1 -1
- data/lib/httpx/plugins/response_cache.rb +11 -4
- data/lib/httpx/plugins/retries.rb +6 -6
- data/lib/httpx/plugins/ssrf_filter.rb +1 -1
- data/lib/httpx/plugins/tracing.rb +1 -6
- data/lib/httpx/plugins/upgrade/h2.rb +1 -11
- data/lib/httpx/plugins/upgrade.rb +17 -17
- data/lib/httpx/pool.rb +7 -9
- data/lib/httpx/request.rb +28 -3
- data/lib/httpx/resolver/native.rb +1 -1
- data/lib/httpx/response.rb +5 -1
- data/lib/httpx/selector.rb +18 -10
- data/lib/httpx/session.rb +32 -24
- data/lib/httpx/version.rb +1 -1
- data/sig/altsvc.rbs +2 -0
- data/sig/connection/http1.rbs +4 -2
- data/sig/connection/http2.rbs +1 -1
- data/sig/connection.rbs +9 -2
- data/sig/io/ssl.rbs +1 -0
- data/sig/io/tcp.rbs +2 -2
- data/sig/loggable.rbs +1 -1
- data/sig/options.rbs +8 -3
- data/sig/parser/http1.rbs +1 -1
- data/sig/plugins/auth/basic.rbs +1 -1
- data/sig/plugins/auth/digest.rbs +1 -1
- data/sig/plugins/auth/ntlm.rbs +2 -0
- data/sig/plugins/auth.rbs +5 -2
- data/sig/plugins/follow_redirects.rbs +1 -1
- data/sig/plugins/proxy.rbs +1 -0
- data/sig/plugins/response_cache.rbs +2 -0
- data/sig/plugins/retries.rbs +1 -1
- data/sig/plugins/tracing.rbs +1 -1
- data/sig/pool.rbs +1 -1
- data/sig/request.rbs +6 -0
- data/sig/session.rbs +0 -2
- metadata +5 -1
|
@@ -17,6 +17,7 @@ module HTTPX
|
|
|
17
17
|
@break_in = break_in
|
|
18
18
|
@circuit_breaker_half_open_drip_rate = circuit_breaker_half_open_drip_rate
|
|
19
19
|
@attempts = 0
|
|
20
|
+
@opened_at = @attempted_at = @response = nil
|
|
20
21
|
|
|
21
22
|
total_real_attempts = @max_attempts * @circuit_breaker_half_open_drip_rate
|
|
22
23
|
@drip_factor = (@max_attempts / total_real_attempts).round
|
|
@@ -155,7 +155,6 @@ module HTTPX
|
|
|
155
155
|
# Tests if it is OK to send this cookie to a given `uri`. A
|
|
156
156
|
# RuntimeError is raised if the cookie's domain is unknown.
|
|
157
157
|
def valid_for_uri?(uri)
|
|
158
|
-
uri = URI(uri)
|
|
159
158
|
# RFC 6265 5.4
|
|
160
159
|
|
|
161
160
|
return false if @secure && uri.scheme != "https"
|
|
@@ -51,7 +51,9 @@ module HTTPX
|
|
|
51
51
|
|
|
52
52
|
if probe_response.status == 401 && digest.can_authenticate?(probe_response.headers["www-authenticate"])
|
|
53
53
|
request.transition(:idle)
|
|
54
|
-
|
|
54
|
+
if (auth_header = digest.authenticate(request, probe_response.headers["www-authenticate"]))
|
|
55
|
+
request.authorize(auth_header)
|
|
56
|
+
end
|
|
55
57
|
super(request)
|
|
56
58
|
else
|
|
57
59
|
probe_response
|
|
@@ -157,7 +157,7 @@ module HTTPX
|
|
|
157
157
|
response.finish!
|
|
158
158
|
retry_request.response = response
|
|
159
159
|
# request has terminated abruptly meanwhile
|
|
160
|
-
retry_request.
|
|
160
|
+
retry_request.emit_response(response)
|
|
161
161
|
else
|
|
162
162
|
log { "redirecting (elapsed time: #{Utils.elapsed_time(retry_start)})!!" }
|
|
163
163
|
send_request(retry_request, selector, options)
|
|
@@ -201,6 +201,17 @@ module HTTPX
|
|
|
201
201
|
# returns the top-most original HTTPX::Request from the redirect chain
|
|
202
202
|
attr_accessor :root_request
|
|
203
203
|
|
|
204
|
+
def initialize(*)
|
|
205
|
+
super
|
|
206
|
+
@redirect_request = nil
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def on_response_arrived=(cb)
|
|
210
|
+
@redirect_request.on_response_arrived = cb if @redirect_request
|
|
211
|
+
|
|
212
|
+
super
|
|
213
|
+
end
|
|
214
|
+
|
|
204
215
|
# returns the follow-up redirect request, or itself
|
|
205
216
|
def redirect_request
|
|
206
217
|
@redirect_request || self
|
|
@@ -210,6 +221,7 @@ module HTTPX
|
|
|
210
221
|
def redirect_request=(req)
|
|
211
222
|
@redirect_request = req
|
|
212
223
|
req.root_request = @root_request || self
|
|
224
|
+
req.on_response_arrived = @on_response_arrived
|
|
213
225
|
@response = nil
|
|
214
226
|
end
|
|
215
227
|
|
data/lib/httpx/plugins/h2c.rb
CHANGED
|
@@ -68,23 +68,13 @@ module HTTPX
|
|
|
68
68
|
end
|
|
69
69
|
|
|
70
70
|
def upgrade_to_h2c(request, response)
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
if prev_parser
|
|
74
|
-
prev_parser.reset
|
|
75
|
-
@inflight -= prev_parser.requests.size
|
|
76
|
-
end
|
|
71
|
+
enqueue_pending_requests_from_parser(@parser)
|
|
77
72
|
|
|
78
73
|
@parser = request.options.h2c_class.new(@write_buffer, @options)
|
|
79
74
|
set_parser_callbacks(@parser)
|
|
80
|
-
@inflight += 1
|
|
75
|
+
@inflight += 1 # request is being completed below
|
|
81
76
|
@parser.upgrade(request, response)
|
|
82
77
|
@upgrade_protocol = "h2c"
|
|
83
|
-
|
|
84
|
-
prev_parser.pending.each do |req|
|
|
85
|
-
req.transition(:idle)
|
|
86
|
-
send(req)
|
|
87
|
-
end
|
|
88
78
|
end
|
|
89
79
|
|
|
90
80
|
private
|
data/lib/httpx/plugins/proxy.rb
CHANGED
|
@@ -140,7 +140,7 @@ module HTTPX
|
|
|
140
140
|
cached_response = cached_response.dup
|
|
141
141
|
cached_response.mark_as_cached!
|
|
142
142
|
request.response = cached_response
|
|
143
|
-
request.
|
|
143
|
+
request.emit_response(cached_response)
|
|
144
144
|
return
|
|
145
145
|
end
|
|
146
146
|
|
|
@@ -220,11 +220,12 @@ module HTTPX
|
|
|
220
220
|
end
|
|
221
221
|
|
|
222
222
|
module ResponseMethods
|
|
223
|
-
attr_writer :original_request
|
|
223
|
+
attr_writer :original_request, :revalidated_at
|
|
224
224
|
|
|
225
225
|
def initialize(*)
|
|
226
226
|
super
|
|
227
227
|
@cached = false
|
|
228
|
+
@revalidated_at = nil
|
|
228
229
|
end
|
|
229
230
|
|
|
230
231
|
# a copy of the request this response was originally cached from
|
|
@@ -254,6 +255,8 @@ module HTTPX
|
|
|
254
255
|
@body = cached_response.body.dup
|
|
255
256
|
|
|
256
257
|
@body.rewind
|
|
258
|
+
|
|
259
|
+
cached_response.revalidated_at = date
|
|
257
260
|
end
|
|
258
261
|
|
|
259
262
|
# A response is fresh if its age has not yet exceeded its freshness lifetime.
|
|
@@ -314,9 +317,13 @@ module HTTPX
|
|
|
314
317
|
# returns the value of the "age" header as an Integer (time since epoch).
|
|
315
318
|
# if no "age" of header exists, it returns the number of seconds since {#date}.
|
|
316
319
|
def age
|
|
317
|
-
|
|
320
|
+
if (revalidated_at = @revalidated_at)
|
|
321
|
+
(Time.now - revalidated_at).to_i
|
|
322
|
+
else
|
|
323
|
+
return @headers["age"].to_i if @headers.key?("age")
|
|
318
324
|
|
|
319
|
-
|
|
325
|
+
(Time.now - date).to_i
|
|
326
|
+
end
|
|
320
327
|
end
|
|
321
328
|
|
|
322
329
|
# returns the value of the "date" header as a Time object
|
|
@@ -148,11 +148,7 @@ module HTTPX
|
|
|
148
148
|
log { "failed to get response, #{request.retries} tries to go..." }
|
|
149
149
|
prepare_to_retry(request, response)
|
|
150
150
|
|
|
151
|
-
if (retry_after = when_to_retry(request, response, options))
|
|
152
|
-
# apply jitter
|
|
153
|
-
if (jitter = request.options.retry_jitter)
|
|
154
|
-
retry_after = jitter.call(retry_after)
|
|
155
|
-
end
|
|
151
|
+
if (retry_after = when_to_retry(request, response, options)) && retry_after.positive?
|
|
156
152
|
|
|
157
153
|
retry_start = Utils.now
|
|
158
154
|
log { "retrying after #{retry_after} secs..." }
|
|
@@ -160,7 +156,7 @@ module HTTPX
|
|
|
160
156
|
if (response = request.response)
|
|
161
157
|
response.finish!
|
|
162
158
|
# request has terminated abruptly meanwhile
|
|
163
|
-
request.
|
|
159
|
+
request.emit_response(response)
|
|
164
160
|
else
|
|
165
161
|
log { "retrying (elapsed time: #{Utils.elapsed_time(retry_start)})!!" }
|
|
166
162
|
send_request(request, selector, options)
|
|
@@ -205,6 +201,10 @@ module HTTPX
|
|
|
205
201
|
def when_to_retry(request, response, options)
|
|
206
202
|
retry_after = options.retry_after
|
|
207
203
|
retry_after = retry_after.call(request, response) if retry_after.respond_to?(:call)
|
|
204
|
+
# apply jitter
|
|
205
|
+
if (jitter = request.options.retry_jitter)
|
|
206
|
+
retry_after = jitter.call(retry_after)
|
|
207
|
+
end
|
|
208
208
|
retry_after
|
|
209
209
|
end
|
|
210
210
|
|
|
@@ -107,7 +107,7 @@ module HTTPX
|
|
|
107
107
|
error.set_backtrace(caller)
|
|
108
108
|
response = ErrorResponse.new(request, error)
|
|
109
109
|
request.response = response
|
|
110
|
-
request.
|
|
110
|
+
request.emit_response(response)
|
|
111
111
|
response
|
|
112
112
|
end
|
|
113
113
|
allowed_requests = requests.select { |req| responses[requests.index(req)].nil? }
|
|
@@ -33,12 +33,7 @@ module HTTPX
|
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
def upgrade_to_h2
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
if prev_parser
|
|
39
|
-
prev_parser.reset
|
|
40
|
-
@inflight -= prev_parser.requests.size
|
|
41
|
-
end
|
|
36
|
+
enqueue_pending_requests_from_parser(@parser)
|
|
42
37
|
|
|
43
38
|
@parser = @options.http2_class.new(@write_buffer, @options)
|
|
44
39
|
set_parser_callbacks(@parser)
|
|
@@ -51,11 +46,6 @@ module HTTPX
|
|
|
51
46
|
# while the parser is already here.
|
|
52
47
|
purge_after_closed
|
|
53
48
|
transition(:idle)
|
|
54
|
-
|
|
55
|
-
prev_parser.requests.each do |req|
|
|
56
|
-
req.transition(:idle)
|
|
57
|
-
send(req)
|
|
58
|
-
end
|
|
59
49
|
end
|
|
60
50
|
end
|
|
61
51
|
end
|
|
@@ -33,32 +33,32 @@ module HTTPX
|
|
|
33
33
|
def fetch_response(request, selector, options)
|
|
34
34
|
response = super
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
return response unless response.is_a?(Response)
|
|
36
|
+
return unless response
|
|
38
37
|
|
|
39
|
-
|
|
38
|
+
return response unless response.is_a?(Response)
|
|
40
39
|
|
|
41
|
-
|
|
40
|
+
return response unless response.headers.key?("upgrade")
|
|
42
41
|
|
|
43
|
-
|
|
42
|
+
upgrade_protocol = response.headers["upgrade"].split(/ *, */).first
|
|
44
43
|
|
|
45
|
-
|
|
44
|
+
return response unless upgrade_protocol && options.upgrade_handlers.key?(upgrade_protocol)
|
|
46
45
|
|
|
47
|
-
|
|
46
|
+
protocol_handler = options.upgrade_handlers[upgrade_protocol]
|
|
48
47
|
|
|
49
|
-
|
|
50
|
-
connection = find_connection(request.uri, selector, options)
|
|
48
|
+
return response unless protocol_handler
|
|
51
49
|
|
|
52
|
-
|
|
53
|
-
|
|
50
|
+
log { "upgrading to #{upgrade_protocol}..." }
|
|
51
|
+
connection = find_connection(request.uri, selector, options)
|
|
54
52
|
|
|
55
|
-
|
|
53
|
+
# do not upgrade already upgraded connections
|
|
54
|
+
return if connection.upgrade_protocol == upgrade_protocol
|
|
56
55
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
56
|
+
protocol_handler.call(connection, request, response)
|
|
57
|
+
|
|
58
|
+
# keep in the loop if the server is switching, unless
|
|
59
|
+
# the connection has been hijacked, in which case you want
|
|
60
|
+
# to terminante immediately
|
|
61
|
+
return fetch_response(request, selector, options) if response.status == 101 && !connection.hijacked
|
|
62
62
|
|
|
63
63
|
response
|
|
64
64
|
end
|
data/lib/httpx/pool.rb
CHANGED
|
@@ -122,12 +122,6 @@ module HTTPX
|
|
|
122
122
|
|
|
123
123
|
@max_connections_cond.signal
|
|
124
124
|
@origin_conds[connection.origin.to_s].signal
|
|
125
|
-
|
|
126
|
-
# Observed situations where a session handling multiple requests in a loop
|
|
127
|
-
# across multiple threads checks the same connection in and out, while another
|
|
128
|
-
# thread which is waiting on the same connection never gets the chance to pick
|
|
129
|
-
# it up, because ruby's thread scheduler never switched on to it in the process.
|
|
130
|
-
Thread.pass
|
|
131
125
|
end
|
|
132
126
|
end
|
|
133
127
|
|
|
@@ -153,16 +147,20 @@ module HTTPX
|
|
|
153
147
|
resolvers = @resolvers[resolver_type]
|
|
154
148
|
|
|
155
149
|
idx = resolvers.find_index do |res|
|
|
156
|
-
res.options
|
|
150
|
+
res.options.resolver_options_match?(options)
|
|
157
151
|
end
|
|
158
152
|
resolvers.delete_at(idx) if idx
|
|
159
153
|
end || checkout_new_resolver(resolver_type, options)
|
|
160
154
|
end
|
|
161
155
|
|
|
162
156
|
def checkin_resolver(resolver)
|
|
163
|
-
|
|
157
|
+
if resolver.is_a?(Resolver::Multi)
|
|
158
|
+
resolver_class = resolver.resolvers.first.class
|
|
159
|
+
else
|
|
160
|
+
resolver_class = resolver.class
|
|
164
161
|
|
|
165
|
-
|
|
162
|
+
resolver = resolver.multi
|
|
163
|
+
end
|
|
166
164
|
|
|
167
165
|
# a multi requires all sub-resolvers being closed in order to be
|
|
168
166
|
# correctly checked back in.
|
data/lib/httpx/request.rb
CHANGED
|
@@ -42,6 +42,12 @@ module HTTPX
|
|
|
42
42
|
# The IP address from the peer server.
|
|
43
43
|
attr_accessor :peer_address
|
|
44
44
|
|
|
45
|
+
# the connection the request is currently being sent to (none if before or after transaction)
|
|
46
|
+
attr_writer :connection
|
|
47
|
+
|
|
48
|
+
# callback triggered when a response (which may not be the final response) was assigned to the request.
|
|
49
|
+
attr_writer :on_response_arrived
|
|
50
|
+
|
|
45
51
|
attr_writer :persistent
|
|
46
52
|
|
|
47
53
|
attr_reader :active_timeouts
|
|
@@ -91,7 +97,9 @@ module HTTPX
|
|
|
91
97
|
raise UnsupportedSchemeError, "#{@uri}: #{@uri.scheme}: unsupported URI scheme" unless ALLOWED_URI_SCHEMES.include?(@uri.scheme)
|
|
92
98
|
|
|
93
99
|
@state = :idle
|
|
94
|
-
@
|
|
100
|
+
@connection = @response =
|
|
101
|
+
@drainer = @peer_address =
|
|
102
|
+
@informational_status = @on_response_arrived = nil
|
|
95
103
|
@ping = false
|
|
96
104
|
@persistent = @options.persistent
|
|
97
105
|
@active_timeouts = []
|
|
@@ -274,8 +282,7 @@ module HTTPX
|
|
|
274
282
|
when :idle
|
|
275
283
|
@body.rewind
|
|
276
284
|
@ping = false
|
|
277
|
-
@response = nil
|
|
278
|
-
@drainer = nil
|
|
285
|
+
@response = @drainer = nil
|
|
279
286
|
@active_timeouts.clear
|
|
280
287
|
when :headers
|
|
281
288
|
return unless @state == :idle
|
|
@@ -321,6 +328,24 @@ module HTTPX
|
|
|
321
328
|
callbacks(event).delete(clb)
|
|
322
329
|
end
|
|
323
330
|
end
|
|
331
|
+
|
|
332
|
+
def handle_error(error)
|
|
333
|
+
if (connection = @connection)
|
|
334
|
+
connection.on_error(error, self)
|
|
335
|
+
else
|
|
336
|
+
response = ErrorResponse.new(self, error)
|
|
337
|
+
self.response = response
|
|
338
|
+
emit_response(response)
|
|
339
|
+
end
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
def emit_response(response)
|
|
343
|
+
emit(:response, response)
|
|
344
|
+
|
|
345
|
+
return unless @on_response_arrived
|
|
346
|
+
|
|
347
|
+
@on_response_arrived.call
|
|
348
|
+
end
|
|
324
349
|
end
|
|
325
350
|
end
|
|
326
351
|
|
data/lib/httpx/response.rb
CHANGED
|
@@ -112,6 +112,7 @@ module HTTPX
|
|
|
112
112
|
def finish!
|
|
113
113
|
@finished = true
|
|
114
114
|
@headers.freeze
|
|
115
|
+
@request.connection = nil
|
|
115
116
|
end
|
|
116
117
|
|
|
117
118
|
# returns whether the response contains body payload.
|
|
@@ -282,6 +283,7 @@ module HTTPX
|
|
|
282
283
|
@error = error
|
|
283
284
|
@options = request.options
|
|
284
285
|
log_exception(@error)
|
|
286
|
+
finish!
|
|
285
287
|
end
|
|
286
288
|
|
|
287
289
|
# returns the exception full message.
|
|
@@ -299,7 +301,9 @@ module HTTPX
|
|
|
299
301
|
true
|
|
300
302
|
end
|
|
301
303
|
|
|
302
|
-
def finish
|
|
304
|
+
def finish!
|
|
305
|
+
@request.connection = nil
|
|
306
|
+
end
|
|
303
307
|
|
|
304
308
|
# raises the wrapped exception.
|
|
305
309
|
def raise_for_status
|
data/lib/httpx/selector.rb
CHANGED
|
@@ -81,7 +81,8 @@ module HTTPX
|
|
|
81
81
|
|
|
82
82
|
def find_resolver(options)
|
|
83
83
|
res = @selectables.find do |c|
|
|
84
|
-
c.is_a?(Resolver::Resolver) &&
|
|
84
|
+
c.is_a?(Resolver::Resolver) &&
|
|
85
|
+
options.resolver_options_match?(c.options)
|
|
85
86
|
end
|
|
86
87
|
|
|
87
88
|
res.multi if res
|
|
@@ -146,18 +147,25 @@ module HTTPX
|
|
|
146
147
|
|
|
147
148
|
is_closed = io.state == :closed
|
|
148
149
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
150
|
+
if is_closed
|
|
151
|
+
# the process by which io was closed may have already triggered the on_close callback,
|
|
152
|
+
# which already deregistered the io. this check prevents it from deleting the wrong io,
|
|
153
|
+
# because of https://bugs.ruby-lang.org/issues/22021 .
|
|
154
|
+
next(@selectables.include?(io))
|
|
153
155
|
end
|
|
154
156
|
|
|
155
|
-
if
|
|
156
|
-
|
|
157
|
-
|
|
157
|
+
if interests
|
|
158
|
+
io.log(level: 2) do
|
|
159
|
+
"[#{io.state}] registering in selector##{object_id} for select (#{interests})#{" for #{interval} seconds" unless interval.nil?}"
|
|
160
|
+
end
|
|
158
161
|
|
|
159
|
-
|
|
160
|
-
|
|
162
|
+
if READABLE.include?(interests)
|
|
163
|
+
r = r.nil? ? io : (Array(r) << io)
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
if WRITABLE.include?(interests)
|
|
167
|
+
w = w.nil? ? io : (Array(w) << io)
|
|
168
|
+
end
|
|
161
169
|
end
|
|
162
170
|
|
|
163
171
|
is_closed
|
data/lib/httpx/session.rb
CHANGED
|
@@ -192,11 +192,8 @@ module HTTPX
|
|
|
192
192
|
when :idle
|
|
193
193
|
do_init_connection(connection, selector)
|
|
194
194
|
when :open
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
else
|
|
198
|
-
pin(connection, selector)
|
|
199
|
-
end
|
|
195
|
+
# external io
|
|
196
|
+
select_connection(connection, selector)
|
|
200
197
|
when :closing, :closed
|
|
201
198
|
connection.idling
|
|
202
199
|
if connection.addresses?
|
|
@@ -262,7 +259,7 @@ module HTTPX
|
|
|
262
259
|
|
|
263
260
|
response = ErrorResponse.new(request, error)
|
|
264
261
|
request.response = response
|
|
265
|
-
request.
|
|
262
|
+
request.emit_response(response)
|
|
266
263
|
end
|
|
267
264
|
|
|
268
265
|
# returns a set of HTTPX::Request objects built from the given +args+ and +options+.
|
|
@@ -303,7 +300,6 @@ module HTTPX
|
|
|
303
300
|
def send_requests(*requests)
|
|
304
301
|
selector = get_current_selector { Selector.new }
|
|
305
302
|
begin
|
|
306
|
-
_send_requests(requests, selector)
|
|
307
303
|
receive_requests(requests, selector)
|
|
308
304
|
ensure
|
|
309
305
|
unless @wrapped
|
|
@@ -316,42 +312,50 @@ module HTTPX
|
|
|
316
312
|
end
|
|
317
313
|
end
|
|
318
314
|
|
|
319
|
-
# sends an array of HTTPX::Request objects
|
|
320
|
-
def _send_requests(requests, selector)
|
|
321
|
-
requests.each do |request|
|
|
322
|
-
send_request(request, selector)
|
|
323
|
-
end
|
|
324
|
-
end
|
|
325
|
-
|
|
326
315
|
# returns the array of HTTPX::Response objects corresponding to the array of HTTPX::Request +requests+.
|
|
327
316
|
def receive_requests(requests, selector)
|
|
328
|
-
|
|
329
|
-
|
|
317
|
+
pending_idxs = [] #: Array[Integer]
|
|
318
|
+
pending = 0
|
|
319
|
+
|
|
320
|
+
waiting = false
|
|
321
|
+
|
|
322
|
+
responses = requests.each_with_index.map do |request, idx|
|
|
323
|
+
send_request(request, selector)
|
|
324
|
+
|
|
330
325
|
fetch_response(request, selector, request.options).tap do |response|
|
|
331
|
-
|
|
326
|
+
if response.nil?
|
|
327
|
+
pending += 1
|
|
328
|
+
request.on_response_arrived = lambda do
|
|
329
|
+
pending_idxs << idx if waiting
|
|
330
|
+
end
|
|
331
|
+
end
|
|
332
332
|
end
|
|
333
333
|
end
|
|
334
334
|
|
|
335
|
-
until
|
|
335
|
+
until pending.zero? || selector.empty?
|
|
336
336
|
# loop on selector until at least one response has been received.
|
|
337
|
+
waiting = true
|
|
337
338
|
catch(:coalesced) { selector.next_tick }
|
|
339
|
+
waiting = false
|
|
338
340
|
|
|
339
|
-
|
|
340
|
-
next unless response.nil?
|
|
341
|
-
|
|
341
|
+
while (idx = pending_idxs.shift)
|
|
342
342
|
request = requests[idx]
|
|
343
343
|
|
|
344
344
|
response = fetch_response(request, selector, request.options)
|
|
345
345
|
|
|
346
|
+
# stop on first pending response. this avoids traversing pending idxs all the way
|
|
347
|
+
# (which is more expensive in the beginning, when the array is larger and N) while
|
|
348
|
+
# making the next loop cheaper (because we're dropping).
|
|
346
349
|
next unless response
|
|
347
350
|
|
|
348
351
|
request.complete!(response)
|
|
349
352
|
responses[idx] = response
|
|
350
|
-
|
|
353
|
+
request.on_response_arrived = nil
|
|
354
|
+
pending -= 1
|
|
351
355
|
end
|
|
352
356
|
end
|
|
353
357
|
|
|
354
|
-
raise Error, "something went wrong, responses not found and requests not resent" unless
|
|
358
|
+
raise Error, "something went wrong, responses not found and requests not resent" unless pending.zero?
|
|
355
359
|
|
|
356
360
|
responses
|
|
357
361
|
end
|
|
@@ -373,7 +377,11 @@ module HTTPX
|
|
|
373
377
|
resolver = find_resolver_for(connection, selector)
|
|
374
378
|
|
|
375
379
|
pin(connection, selector)
|
|
376
|
-
early_resolve(resolver, connection)
|
|
380
|
+
if early_resolve(resolver, connection)
|
|
381
|
+
@pool.checkin_resolver(resolver)
|
|
382
|
+
else
|
|
383
|
+
resolver.lazy_resolve(connection)
|
|
384
|
+
end
|
|
377
385
|
end
|
|
378
386
|
|
|
379
387
|
def early_resolve(resolver, connection)
|
data/lib/httpx/version.rb
CHANGED
data/sig/altsvc.rbs
CHANGED
data/sig/connection/http1.rbs
CHANGED
|
@@ -52,7 +52,7 @@ module HTTPX
|
|
|
52
52
|
|
|
53
53
|
def on_complete: () -> void
|
|
54
54
|
|
|
55
|
-
def dispatch: () -> void
|
|
55
|
+
def dispatch: (Request request) -> void
|
|
56
56
|
|
|
57
57
|
def ping: () -> void
|
|
58
58
|
|
|
@@ -74,11 +74,13 @@ module HTTPX
|
|
|
74
74
|
|
|
75
75
|
def handle: (Request request) -> void
|
|
76
76
|
|
|
77
|
+
def join_headline: (Request request) -> String
|
|
78
|
+
|
|
77
79
|
def join_headers: (Request request) -> void
|
|
78
80
|
|
|
79
81
|
def join_trailers: (Request request) -> void
|
|
80
82
|
|
|
81
|
-
def join_headers2: (_Each[[String, String]] headers) -> void
|
|
83
|
+
def join_headers2: (Request request, _Each[[String, String]] headers) -> void
|
|
82
84
|
|
|
83
85
|
def join_body: (Request request) -> void
|
|
84
86
|
|
data/sig/connection/http2.rbs
CHANGED
|
@@ -76,7 +76,7 @@ module HTTPX
|
|
|
76
76
|
|
|
77
77
|
def on_stream_headers: (::HTTP2::Stream stream, Request request, Array[[String, String]] headers) -> void
|
|
78
78
|
|
|
79
|
-
def on_stream_trailers: (::HTTP2::Stream stream, Response response, Array[[String, String]] headers) -> void
|
|
79
|
+
def on_stream_trailers: (::HTTP2::Stream stream, Request request, Response response, Array[[String, String]] headers) -> void
|
|
80
80
|
|
|
81
81
|
def on_stream_data: (::HTTP2::Stream stream, Request request, String data) -> void
|
|
82
82
|
|
data/sig/connection.rbs
CHANGED
|
@@ -50,6 +50,7 @@ module HTTPX
|
|
|
50
50
|
@altsvc_connection: instance?
|
|
51
51
|
@sibling: instance?
|
|
52
52
|
@main_sibling: bool
|
|
53
|
+
@no_more_requests_counter: Integer
|
|
53
54
|
|
|
54
55
|
|
|
55
56
|
def addresses: () -> Array[Resolver::Entry]?
|
|
@@ -156,6 +157,12 @@ module HTTPX
|
|
|
156
157
|
|
|
157
158
|
def build_socket: (?Array[Resolver::Entry]? addrs) -> (TCP | SSL | UNIX)
|
|
158
159
|
|
|
160
|
+
def ping: () -> void
|
|
161
|
+
|
|
162
|
+
def pong: () -> void
|
|
163
|
+
|
|
164
|
+
def no_more_requests_loop_check: () -> void
|
|
165
|
+
|
|
159
166
|
def handle_error: (StandardError error, ?Request? request) -> void
|
|
160
167
|
|
|
161
168
|
def force_purge: () -> void
|
|
@@ -172,9 +179,9 @@ module HTTPX
|
|
|
172
179
|
|
|
173
180
|
def set_request_request_timeout: (Request request) -> void
|
|
174
181
|
|
|
175
|
-
def write_timeout_callback: (Request request, Numeric
|
|
182
|
+
def write_timeout_callback: (Request request, Numeric timeout) -> void
|
|
176
183
|
|
|
177
|
-
def read_timeout_callback: (Request request, Numeric
|
|
184
|
+
def read_timeout_callback: (Request request, Numeric timeout, ?singleton(RequestTimeoutError) error_type) -> void
|
|
178
185
|
|
|
179
186
|
def set_request_timeout: (Symbol label, Request request, Numeric timeout, Symbol start_event, Symbol | Array[Symbol] finish_events) { () -> void } -> void
|
|
180
187
|
|