httpx 1.7.4 → 1.7.6
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_5.md +10 -0
- data/doc/release_notes/1_7_6.md +24 -0
- data/lib/httpx/adapters/datadog.rb +15 -6
- data/lib/httpx/altsvc.rb +4 -2
- data/lib/httpx/connection/http1.rb +20 -17
- data/lib/httpx/connection/http2.rb +10 -3
- data/lib/httpx/connection.rb +78 -41
- data/lib/httpx/io/ssl.rb +20 -8
- data/lib/httpx/io/tcp.rb +18 -12
- data/lib/httpx/io/unix.rb +13 -9
- data/lib/httpx/options.rb +23 -7
- data/lib/httpx/parser/http1.rb +14 -4
- data/lib/httpx/plugins/auth.rb +23 -9
- data/lib/httpx/plugins/expect.rb +3 -0
- data/lib/httpx/plugins/retries.rb +1 -1
- data/lib/httpx/plugins/tracing.rb +4 -4
- data/lib/httpx/pool.rb +7 -9
- data/lib/httpx/request.rb +15 -3
- data/lib/httpx/resolver/native.rb +1 -1
- data/lib/httpx/response.rb +5 -1
- data/lib/httpx/selector.rb +15 -12
- data/lib/httpx/session.rb +24 -39
- data/lib/httpx/timers.rb +4 -0
- data/lib/httpx/version.rb +1 -1
- data/sig/altsvc.rbs +2 -0
- data/sig/connection/http1.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/options.rbs +8 -3
- data/sig/parser/http1.rbs +1 -1
- data/sig/plugins/auth.rbs +5 -2
- data/sig/plugins/expect.rbs +4 -0
- data/sig/plugins/fiber_concurrency.rbs +2 -2
- data/sig/plugins/retries.rbs +1 -1
- data/sig/pool.rbs +1 -1
- data/sig/request.rbs +3 -0
- data/sig/selector.rbs +3 -2
- data/sig/timers.rbs +2 -0
- metadata +5 -1
data/lib/httpx/io/unix.rb
CHANGED
|
@@ -14,16 +14,20 @@ module HTTPX
|
|
|
14
14
|
@state = :idle
|
|
15
15
|
@options = options
|
|
16
16
|
@fallback_protocol = @options.fallback_protocol
|
|
17
|
-
if @options.io
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
17
|
+
if (io = @options.io)
|
|
18
|
+
io =
|
|
19
|
+
case io
|
|
20
|
+
when Hash
|
|
21
|
+
io[origin.authority]
|
|
22
|
+
else
|
|
23
|
+
io
|
|
24
|
+
end
|
|
25
|
+
raise Error, "Given IO objects do not match the request authority" unless io
|
|
26
|
+
|
|
27
|
+
# @type var io: UNIXSocket
|
|
25
28
|
|
|
26
|
-
@path =
|
|
29
|
+
_, @path = io.addr
|
|
30
|
+
@io = io
|
|
27
31
|
@keep_open = true
|
|
28
32
|
@state = :connected
|
|
29
33
|
elsif path
|
data/lib/httpx/options.rb
CHANGED
|
@@ -202,16 +202,19 @@ module HTTPX
|
|
|
202
202
|
|
|
203
203
|
REQUEST_BODY_IVARS = %i[@headers].freeze
|
|
204
204
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
205
|
+
# checks whether +other+ matches the same connection-level options
|
|
206
|
+
def connection_options_match?(other, ignore_ivars = nil)
|
|
207
|
+
return true if self == other
|
|
208
208
|
|
|
209
|
-
# checks whether +other+ is equal by comparing the session options
|
|
210
|
-
def options_equals?(other, ignore_ivars = REQUEST_BODY_IVARS)
|
|
211
209
|
# headers and other request options do not play a role, as they are
|
|
212
210
|
# relevant only for the request.
|
|
213
|
-
ivars = instance_variables
|
|
214
|
-
|
|
211
|
+
ivars = instance_variables
|
|
212
|
+
ivars.reject! { |iv| REQUEST_BODY_IVARS.include?(iv) }
|
|
213
|
+
ivars.reject! { |iv| ignore_ivars.include?(iv) } if ignore_ivars
|
|
214
|
+
|
|
215
|
+
other_ivars = other.instance_variables
|
|
216
|
+
other_ivars.reject! { |iv| REQUEST_BODY_IVARS.include?(iv) }
|
|
217
|
+
other_ivars.reject! { |iv| ignore_ivars.include?(iv) } if ignore_ivars
|
|
215
218
|
|
|
216
219
|
return false if ivars.size != other_ivars.size
|
|
217
220
|
|
|
@@ -222,6 +225,19 @@ module HTTPX
|
|
|
222
225
|
end
|
|
223
226
|
end
|
|
224
227
|
|
|
228
|
+
RESOLVER_IVARS = %i[
|
|
229
|
+
@resolver_class @resolver_cache @resolver_options
|
|
230
|
+
@resolver_native_class @resolver_system_class @resolver_https_class
|
|
231
|
+
].freeze
|
|
232
|
+
|
|
233
|
+
# checks whether +other+ matches the same resolver-level options
|
|
234
|
+
def resolver_options_match?(other)
|
|
235
|
+
self == other ||
|
|
236
|
+
RESOLVER_IVARS.all? do |ivar|
|
|
237
|
+
instance_variable_get(ivar) == other.instance_variable_get(ivar)
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
|
|
225
241
|
# returns a HTTPX::Options instance resulting of the merging of +other+ with self.
|
|
226
242
|
# it may return self if +other+ is self or equal to self.
|
|
227
243
|
def merge(other)
|
data/lib/httpx/parser/http1.rb
CHANGED
|
@@ -14,6 +14,8 @@ module HTTPX
|
|
|
14
14
|
@state = :idle
|
|
15
15
|
@buffer = "".b
|
|
16
16
|
@headers = {}
|
|
17
|
+
@content_length = nil
|
|
18
|
+
@_has_trailers = @upgrade = false
|
|
17
19
|
end
|
|
18
20
|
|
|
19
21
|
def <<(chunk)
|
|
@@ -25,7 +27,8 @@ module HTTPX
|
|
|
25
27
|
@state = :idle
|
|
26
28
|
@headers = {}
|
|
27
29
|
@content_length = nil
|
|
28
|
-
@_has_trailers =
|
|
30
|
+
@_has_trailers = @upgrade = false
|
|
31
|
+
@buffer = @buffer.to_s
|
|
29
32
|
@buffer.clear
|
|
30
33
|
end
|
|
31
34
|
|
|
@@ -34,7 +37,7 @@ module HTTPX
|
|
|
34
37
|
end
|
|
35
38
|
|
|
36
39
|
def upgrade_data
|
|
37
|
-
@buffer
|
|
40
|
+
@buffer.to_s
|
|
38
41
|
end
|
|
39
42
|
|
|
40
43
|
private
|
|
@@ -55,6 +58,7 @@ module HTTPX
|
|
|
55
58
|
end
|
|
56
59
|
|
|
57
60
|
def parse_headline
|
|
61
|
+
#: @type ivar @buffer: String
|
|
58
62
|
idx = @buffer.index("\n")
|
|
59
63
|
return unless idx
|
|
60
64
|
|
|
@@ -75,6 +79,8 @@ module HTTPX
|
|
|
75
79
|
headers = @headers
|
|
76
80
|
buffer = @buffer
|
|
77
81
|
|
|
82
|
+
#: @type var buffer: String
|
|
83
|
+
|
|
78
84
|
while (idx = buffer.index("\n"))
|
|
79
85
|
# @type var line: String
|
|
80
86
|
line = buffer.byteslice(0..idx)
|
|
@@ -118,17 +124,20 @@ module HTTPX
|
|
|
118
124
|
|
|
119
125
|
def parse_data
|
|
120
126
|
if @buffer.respond_to?(:each)
|
|
127
|
+
# @type ivar @buffer: Transcoder::Chunker::Decoder
|
|
121
128
|
@buffer.each do |chunk|
|
|
122
129
|
@observer.on_data(chunk)
|
|
123
130
|
end
|
|
124
131
|
elsif @content_length
|
|
125
|
-
# @type
|
|
132
|
+
# @type ivar @buffer: String
|
|
126
133
|
data = @buffer.byteslice(0, @content_length)
|
|
134
|
+
# @type var data: String
|
|
127
135
|
@buffer = @buffer.byteslice(@content_length..-1) || "".b
|
|
128
136
|
@content_length -= data.bytesize
|
|
129
137
|
@observer.on_data(data)
|
|
130
138
|
data.clear
|
|
131
139
|
else
|
|
140
|
+
# @type ivar @buffer: String
|
|
132
141
|
@observer.on_data(@buffer)
|
|
133
142
|
@buffer.clear
|
|
134
143
|
end
|
|
@@ -152,7 +161,7 @@ module HTTPX
|
|
|
152
161
|
tr_encoding.split(/ *, */).each do |encoding|
|
|
153
162
|
case encoding
|
|
154
163
|
when "chunked"
|
|
155
|
-
@buffer = Transcoder::Chunker::Decoder.new(@buffer, @_has_trailers)
|
|
164
|
+
@buffer = Transcoder::Chunker::Decoder.new(@buffer.to_s, @_has_trailers)
|
|
156
165
|
end
|
|
157
166
|
end
|
|
158
167
|
end
|
|
@@ -165,6 +174,7 @@ module HTTPX
|
|
|
165
174
|
if @content_length
|
|
166
175
|
@content_length <= 0
|
|
167
176
|
elsif @buffer.respond_to?(:finished?)
|
|
177
|
+
# @type ivar @buffer: Transcoder::Chunker::Decoder
|
|
168
178
|
@buffer.finished?
|
|
169
179
|
else
|
|
170
180
|
false
|
data/lib/httpx/plugins/auth.rb
CHANGED
|
@@ -44,6 +44,7 @@ module HTTPX
|
|
|
44
44
|
super
|
|
45
45
|
|
|
46
46
|
@auth_header_value = nil
|
|
47
|
+
@auth_header_value_mtx = Thread::Mutex.new
|
|
47
48
|
@skip_auth_header_value = false
|
|
48
49
|
end
|
|
49
50
|
|
|
@@ -63,7 +64,9 @@ module HTTPX
|
|
|
63
64
|
end
|
|
64
65
|
|
|
65
66
|
def reset_auth_header_value!
|
|
66
|
-
@
|
|
67
|
+
@auth_header_value_mtx.synchronize do
|
|
68
|
+
@auth_header_value = nil
|
|
69
|
+
end
|
|
67
70
|
end
|
|
68
71
|
|
|
69
72
|
private
|
|
@@ -71,9 +74,11 @@ module HTTPX
|
|
|
71
74
|
def send_request(request, *)
|
|
72
75
|
return super if @skip_auth_header_value || request.authorized?
|
|
73
76
|
|
|
74
|
-
|
|
77
|
+
auth_header_value = @auth_header_value_mtx.synchronize do
|
|
78
|
+
@auth_header_value ||= generate_auth_token
|
|
79
|
+
end
|
|
75
80
|
|
|
76
|
-
request.authorize(
|
|
81
|
+
request.authorize(auth_header_value) if auth_header_value
|
|
77
82
|
|
|
78
83
|
super
|
|
79
84
|
end
|
|
@@ -92,9 +97,11 @@ module HTTPX
|
|
|
92
97
|
end
|
|
93
98
|
|
|
94
99
|
module RequestMethods
|
|
100
|
+
attr_reader :auth_token_value
|
|
101
|
+
|
|
95
102
|
def initialize(*)
|
|
96
103
|
super
|
|
97
|
-
@auth_token_value = nil
|
|
104
|
+
@auth_token_value = @auth_header_value = nil
|
|
98
105
|
end
|
|
99
106
|
|
|
100
107
|
def authorized?
|
|
@@ -102,19 +109,20 @@ module HTTPX
|
|
|
102
109
|
end
|
|
103
110
|
|
|
104
111
|
def unauthorize!
|
|
105
|
-
return unless (auth_value = @
|
|
112
|
+
return unless (auth_value = @auth_header_value)
|
|
106
113
|
|
|
107
114
|
@headers.get("authorization").delete(auth_value)
|
|
108
115
|
|
|
109
|
-
@auth_token_value = nil
|
|
116
|
+
@auth_token_value = @auth_header_value = nil
|
|
110
117
|
end
|
|
111
118
|
|
|
112
119
|
def authorize(auth_value)
|
|
120
|
+
@auth_header_value = auth_value
|
|
113
121
|
if (auth_type = @options.auth_header_type)
|
|
114
|
-
|
|
122
|
+
@auth_header_value = "#{auth_type} #{@auth_header_value}"
|
|
115
123
|
end
|
|
116
124
|
|
|
117
|
-
@headers.add("authorization",
|
|
125
|
+
@headers.add("authorization", @auth_header_value)
|
|
118
126
|
|
|
119
127
|
@auth_token_value = auth_value
|
|
120
128
|
end
|
|
@@ -138,8 +146,14 @@ module HTTPX
|
|
|
138
146
|
return unless auth_error?(response, request.options) ||
|
|
139
147
|
(@options.generate_auth_value_on_retry && @options.generate_auth_value_on_retry.call(response))
|
|
140
148
|
|
|
149
|
+
# regenerate token before retry, but only if it's the first request from batch failing.
|
|
150
|
+
# otherwise, it means that the first request already passed here, so this request should
|
|
151
|
+
# use whatever was generated for it.
|
|
152
|
+
@auth_header_value_mtx.synchronize do
|
|
153
|
+
@auth_header_value = generate_auth_token if request.auth_token_value == @auth_header_value
|
|
154
|
+
end
|
|
155
|
+
|
|
141
156
|
request.unauthorize!
|
|
142
|
-
@auth_header_value = generate_auth_token
|
|
143
157
|
end
|
|
144
158
|
|
|
145
159
|
def auth_error?(response, options)
|
data/lib/httpx/plugins/expect.rb
CHANGED
|
@@ -148,7 +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))
|
|
151
|
+
if (retry_after = when_to_retry(request, response, options)) && retry_after.positive?
|
|
152
152
|
# apply jitter
|
|
153
153
|
if (jitter = request.options.retry_jitter)
|
|
154
154
|
retry_after = jitter.call(retry_after)
|
|
@@ -89,7 +89,7 @@ module HTTPX::Plugins
|
|
|
89
89
|
on(:headers) do
|
|
90
90
|
# the usual request init time (when not including the connection handshake)
|
|
91
91
|
# should be the time the request is buffered the first time.
|
|
92
|
-
@init_time ||= ::Time.now
|
|
92
|
+
@init_time ||= ::Time.now.utc
|
|
93
93
|
|
|
94
94
|
tracer.start(self)
|
|
95
95
|
end
|
|
@@ -102,7 +102,7 @@ module HTTPX::Plugins
|
|
|
102
102
|
# Example is the :ssrf_filter plugin, which raises an error on
|
|
103
103
|
# initialize if the host is an IP which matches against the known set.
|
|
104
104
|
# in such cases, we'll just set here right here.
|
|
105
|
-
@init_time ||= ::Time.now
|
|
105
|
+
@init_time ||= ::Time.now.utc
|
|
106
106
|
|
|
107
107
|
super
|
|
108
108
|
end
|
|
@@ -113,7 +113,7 @@ module HTTPX::Plugins
|
|
|
113
113
|
def initialize(*)
|
|
114
114
|
super
|
|
115
115
|
|
|
116
|
-
@init_time = ::Time.now
|
|
116
|
+
@init_time = ::Time.now.utc
|
|
117
117
|
end
|
|
118
118
|
|
|
119
119
|
def send(request)
|
|
@@ -129,7 +129,7 @@ module HTTPX::Plugins
|
|
|
129
129
|
|
|
130
130
|
# time of initial request(s) is accounted from the moment
|
|
131
131
|
# the connection is back to :idle, and ready to connect again.
|
|
132
|
-
@init_time = ::Time.now
|
|
132
|
+
@init_time = ::Time.now.utc
|
|
133
133
|
end
|
|
134
134
|
end
|
|
135
135
|
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,9 @@ 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
|
+
|
|
45
48
|
attr_writer :persistent
|
|
46
49
|
|
|
47
50
|
attr_reader :active_timeouts
|
|
@@ -91,7 +94,7 @@ module HTTPX
|
|
|
91
94
|
raise UnsupportedSchemeError, "#{@uri}: #{@uri.scheme}: unsupported URI scheme" unless ALLOWED_URI_SCHEMES.include?(@uri.scheme)
|
|
92
95
|
|
|
93
96
|
@state = :idle
|
|
94
|
-
@response = @drainer = @peer_address = @informational_status = nil
|
|
97
|
+
@connection = @response = @drainer = @peer_address = @informational_status = nil
|
|
95
98
|
@ping = false
|
|
96
99
|
@persistent = @options.persistent
|
|
97
100
|
@active_timeouts = []
|
|
@@ -274,8 +277,7 @@ module HTTPX
|
|
|
274
277
|
when :idle
|
|
275
278
|
@body.rewind
|
|
276
279
|
@ping = false
|
|
277
|
-
@response = nil
|
|
278
|
-
@drainer = nil
|
|
280
|
+
@response = @drainer = nil
|
|
279
281
|
@active_timeouts.clear
|
|
280
282
|
when :headers
|
|
281
283
|
return unless @state == :idle
|
|
@@ -321,6 +323,16 @@ module HTTPX
|
|
|
321
323
|
callbacks(event).delete(clb)
|
|
322
324
|
end
|
|
323
325
|
end
|
|
326
|
+
|
|
327
|
+
def handle_error(error)
|
|
328
|
+
if (connection = @connection)
|
|
329
|
+
connection.on_error(error, self)
|
|
330
|
+
else
|
|
331
|
+
response = ErrorResponse.new(self, error)
|
|
332
|
+
self.response = response
|
|
333
|
+
emit(:response, response)
|
|
334
|
+
end
|
|
335
|
+
end
|
|
324
336
|
end
|
|
325
337
|
end
|
|
326
338
|
|
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
|
@@ -29,7 +29,7 @@ module HTTPX
|
|
|
29
29
|
|
|
30
30
|
def_delegator :@timers, :after
|
|
31
31
|
|
|
32
|
-
def_delegator :@selectables, :
|
|
32
|
+
def_delegator :@selectables, :each
|
|
33
33
|
|
|
34
34
|
def initialize
|
|
35
35
|
@timers = Timers.new
|
|
@@ -37,8 +37,8 @@ module HTTPX
|
|
|
37
37
|
@is_timer_interval = false
|
|
38
38
|
end
|
|
39
39
|
|
|
40
|
-
def
|
|
41
|
-
@selectables.
|
|
40
|
+
def empty?
|
|
41
|
+
@selectables.empty? && @timers.empty?
|
|
42
42
|
end
|
|
43
43
|
|
|
44
44
|
def next_tick
|
|
@@ -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
|
|
@@ -148,16 +149,18 @@ module HTTPX
|
|
|
148
149
|
|
|
149
150
|
next(is_closed) if is_closed
|
|
150
151
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
152
|
+
if interests
|
|
153
|
+
io.log(level: 2) do
|
|
154
|
+
"[#{io.state}] registering in selector##{object_id} for select (#{interests})#{" for #{interval} seconds" unless interval.nil?}"
|
|
155
|
+
end
|
|
154
156
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
157
|
+
if READABLE.include?(interests)
|
|
158
|
+
r = r.nil? ? io : (Array(r) << io)
|
|
159
|
+
end
|
|
158
160
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
+
if WRITABLE.include?(interests)
|
|
162
|
+
w = w.nil? ? io : (Array(w) << io)
|
|
163
|
+
end
|
|
161
164
|
end
|
|
162
165
|
|
|
163
166
|
is_closed
|
data/lib/httpx/session.rb
CHANGED
|
@@ -325,53 +325,34 @@ module HTTPX
|
|
|
325
325
|
|
|
326
326
|
# returns the array of HTTPX::Response objects corresponding to the array of HTTPX::Request +requests+.
|
|
327
327
|
def receive_requests(requests, selector)
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
return responses unless request
|
|
335
|
-
|
|
336
|
-
catch(:coalesced) { selector.next_tick } until (response = fetch_response(request, selector, request.options))
|
|
337
|
-
request.complete!(response)
|
|
338
|
-
|
|
339
|
-
responses << response
|
|
340
|
-
requests.shift
|
|
328
|
+
waiting = 0
|
|
329
|
+
responses = requests.map do |request|
|
|
330
|
+
fetch_response(request, selector, request.options).tap do |response|
|
|
331
|
+
waiting += 1 if response.nil?
|
|
332
|
+
end
|
|
333
|
+
end
|
|
341
334
|
|
|
342
|
-
|
|
335
|
+
until waiting.zero? || selector.empty?
|
|
336
|
+
# loop on selector until at least one response has been received.
|
|
337
|
+
catch(:coalesced) { selector.next_tick }
|
|
343
338
|
|
|
344
|
-
|
|
339
|
+
responses.each_with_index do |response, idx|
|
|
340
|
+
next unless response.nil?
|
|
345
341
|
|
|
346
|
-
|
|
347
|
-
# handshake error, and the error responses have already been emitted, but there was no
|
|
348
|
-
# opportunity to traverse the requests, hence we're returning only a fraction of the errors
|
|
349
|
-
# we were supposed to. This effectively fetches the existing responses and return them.
|
|
350
|
-
exit_from_loop = true
|
|
342
|
+
request = requests[idx]
|
|
351
343
|
|
|
352
|
-
|
|
344
|
+
response = fetch_response(request, selector, request.options)
|
|
353
345
|
|
|
354
|
-
|
|
355
|
-
response = fetch_response(req, selector, request.options)
|
|
346
|
+
next unless response
|
|
356
347
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
requests_to_remove << req
|
|
361
|
-
else
|
|
362
|
-
# fetch_response may resend requests. when that happens, we need to go back to the initial
|
|
363
|
-
# loop and process the selector. we still do a pass-through on the remainder of requests, so
|
|
364
|
-
# that every request that need to be resent, is resent.
|
|
365
|
-
exit_from_loop = false
|
|
366
|
-
|
|
367
|
-
raise Error, "something went wrong, responses not found and requests not resent" if selector.empty?
|
|
368
|
-
end
|
|
348
|
+
request.complete!(response)
|
|
349
|
+
responses[idx] = response
|
|
350
|
+
waiting -= 1
|
|
369
351
|
end
|
|
352
|
+
end
|
|
370
353
|
|
|
371
|
-
|
|
354
|
+
raise Error, "something went wrong, responses not found and requests not resent" unless waiting.zero?
|
|
372
355
|
|
|
373
|
-
requests -= requests_to_remove
|
|
374
|
-
end
|
|
375
356
|
responses
|
|
376
357
|
end
|
|
377
358
|
|
|
@@ -392,7 +373,11 @@ module HTTPX
|
|
|
392
373
|
resolver = find_resolver_for(connection, selector)
|
|
393
374
|
|
|
394
375
|
pin(connection, selector)
|
|
395
|
-
early_resolve(resolver, connection)
|
|
376
|
+
if early_resolve(resolver, connection)
|
|
377
|
+
@pool.checkin_resolver(resolver)
|
|
378
|
+
else
|
|
379
|
+
resolver.lazy_resolve(connection)
|
|
380
|
+
end
|
|
396
381
|
end
|
|
397
382
|
|
|
398
383
|
def early_resolve(resolver, connection)
|
data/lib/httpx/timers.rb
CHANGED
data/lib/httpx/version.rb
CHANGED
data/sig/altsvc.rbs
CHANGED
data/sig/connection/http1.rbs
CHANGED
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
|
|
data/sig/io/ssl.rbs
CHANGED
data/sig/io/tcp.rbs
CHANGED
|
@@ -46,7 +46,7 @@ module HTTPX
|
|
|
46
46
|
|
|
47
47
|
public
|
|
48
48
|
|
|
49
|
-
def read: (Integer size,
|
|
49
|
+
def read: (Integer size, Buffer | String buffer) -> (0 | nil | untyped)
|
|
50
50
|
|
|
51
51
|
def write: (Buffer buffer) -> Integer?
|
|
52
52
|
|
|
@@ -67,6 +67,6 @@ module HTTPX
|
|
|
67
67
|
|
|
68
68
|
def do_transition: (Symbol nextstate) -> void
|
|
69
69
|
|
|
70
|
-
def log_transition_state: (Symbol nextstate) ->
|
|
70
|
+
def log_transition_state: (Symbol nextstate) -> String
|
|
71
71
|
end
|
|
72
72
|
end
|