httpx 1.8.4 → 1.9.1

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.
Files changed (97) hide show
  1. checksums.yaml +4 -4
  2. data/doc/release_notes/1_8_1.md +1 -1
  3. data/doc/release_notes/1_8_2.md +4 -4
  4. data/doc/release_notes/1_8_3.md +3 -5
  5. data/doc/release_notes/1_8_4.md +1 -1
  6. data/doc/release_notes/1_9_0.md +75 -0
  7. data/doc/release_notes/1_9_1.md +32 -0
  8. data/lib/httpx/adapters/faraday.rb +1 -1
  9. data/lib/httpx/adapters/webmock.rb +15 -2
  10. data/lib/httpx/altsvc.rb +29 -15
  11. data/lib/httpx/chainable.rb +4 -1
  12. data/lib/httpx/connection/http1.rb +34 -35
  13. data/lib/httpx/connection/http2.rb +146 -33
  14. data/lib/httpx/connection.rb +282 -162
  15. data/lib/httpx/headers.rb +2 -2
  16. data/lib/httpx/io/tcp.rb +42 -21
  17. data/lib/httpx/options.rb +86 -35
  18. data/lib/httpx/parser/http1.rb +3 -6
  19. data/lib/httpx/plugins/auth/digest.rb +1 -2
  20. data/lib/httpx/plugins/auth.rb +11 -2
  21. data/lib/httpx/plugins/aws_sdk_authentication.rb +7 -3
  22. data/lib/httpx/plugins/aws_sigv4.rb +1 -1
  23. data/lib/httpx/plugins/basic_auth.rb +2 -0
  24. data/lib/httpx/plugins/cache.rb +1 -1
  25. data/lib/httpx/plugins/callbacks.rb +8 -6
  26. data/lib/httpx/plugins/circuit_breaker.rb +1 -0
  27. data/lib/httpx/plugins/content_digest.rb +3 -5
  28. data/lib/httpx/plugins/digest_auth.rb +2 -0
  29. data/lib/httpx/plugins/expect.rb +10 -1
  30. data/lib/httpx/plugins/fiber_concurrency.rb +59 -16
  31. data/lib/httpx/plugins/follow_redirects.rb +1 -1
  32. data/lib/httpx/plugins/grpc.rb +21 -0
  33. data/lib/httpx/plugins/h2c.rb +12 -11
  34. data/lib/httpx/plugins/hedging.rb +284 -0
  35. data/lib/httpx/plugins/ntlm_auth.rb +5 -3
  36. data/lib/httpx/plugins/ntlm_v2_auth.rb +5 -3
  37. data/lib/httpx/plugins/oauth.rb +2 -2
  38. data/lib/httpx/plugins/proxy/http.rb +67 -26
  39. data/lib/httpx/plugins/proxy/socks5.rb +4 -4
  40. data/lib/httpx/plugins/proxy/ssh.rb +30 -11
  41. data/lib/httpx/plugins/proxy.rb +68 -54
  42. data/lib/httpx/plugins/push_promise.rb +4 -2
  43. data/lib/httpx/plugins/query.rb +1 -0
  44. data/lib/httpx/plugins/retries.rb +2 -2
  45. data/lib/httpx/plugins/server_sent_events.rb +1 -0
  46. data/lib/httpx/plugins/ssrf_filter.rb +1 -1
  47. data/lib/httpx/plugins/stream.rb +12 -10
  48. data/lib/httpx/plugins/stream_bidi.rb +4 -0
  49. data/lib/httpx/plugins/tracing.rb +99 -11
  50. data/lib/httpx/plugins/upgrade/h2.rb +3 -3
  51. data/lib/httpx/plugins/upgrade.rb +2 -0
  52. data/lib/httpx/plugins/webdav.rb +8 -0
  53. data/lib/httpx/request/body.rb +2 -1
  54. data/lib/httpx/request.rb +6 -6
  55. data/lib/httpx/resolver/https.rb +3 -2
  56. data/lib/httpx/resolver/native.rb +19 -9
  57. data/lib/httpx/resolver/resolver.rb +2 -2
  58. data/lib/httpx/resolver/system.rb +4 -0
  59. data/lib/httpx/resolver.rb +10 -6
  60. data/lib/httpx/response.rb +19 -7
  61. data/lib/httpx/selector.rb +111 -10
  62. data/lib/httpx/session.rb +36 -10
  63. data/lib/httpx/transcoder/json.rb +1 -1
  64. data/lib/httpx/version.rb +1 -1
  65. data/lib/httpx.rb +1 -0
  66. data/sig/altsvc.rbs +3 -3
  67. data/sig/callbacks.rbs +1 -0
  68. data/sig/chainable.rbs +3 -1
  69. data/sig/connection/http1.rbs +4 -2
  70. data/sig/connection/http2.rbs +23 -17
  71. data/sig/connection.rbs +29 -7
  72. data/sig/headers.rbs +1 -1
  73. data/sig/httpx.rbs +2 -0
  74. data/sig/io/tcp.rbs +5 -0
  75. data/sig/options.rbs +43 -12
  76. data/sig/parser/http1.rbs +1 -1
  77. data/sig/plugins/auth/digest.rbs +0 -1
  78. data/sig/plugins/auth.rbs +12 -5
  79. data/sig/plugins/expect.rbs +6 -0
  80. data/sig/plugins/fiber_concurrency.rbs +10 -1
  81. data/sig/plugins/hedging.rbs +44 -0
  82. data/sig/plugins/proxy/http.rbs +9 -2
  83. data/sig/plugins/proxy.rbs +3 -2
  84. data/sig/plugins/retries.rbs +2 -2
  85. data/sig/plugins/stream_bidi.rbs +0 -2
  86. data/sig/plugins/tracing.rbs +22 -5
  87. data/sig/request/body.rbs +1 -1
  88. data/sig/resolver/entry.rbs +2 -2
  89. data/sig/resolver/https.rbs +2 -0
  90. data/sig/resolver/native.rbs +3 -0
  91. data/sig/resolver/resolver.rbs +1 -1
  92. data/sig/resolver/system.rbs +2 -0
  93. data/sig/resolver.rbs +1 -1
  94. data/sig/response.rbs +1 -2
  95. data/sig/selector.rbs +17 -3
  96. data/sig/session.rbs +8 -6
  97. metadata +7 -1
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "io/wait"
3
+ require "io/wait" if RUBY_VERSION < "3.2.0"
4
4
 
5
5
  module HTTPX
6
6
  #
@@ -21,11 +21,17 @@ module HTTPX
21
21
  class Selector
22
22
  extend Forwardable
23
23
 
24
+ HAS_FIBER_SCHEDULER = Fiber.respond_to?(:scheduler)
25
+
24
26
  READABLE = %i[rw r].freeze
25
27
  WRITABLE = %i[rw w].freeze
26
28
 
29
+ # max number of consecutive ticks allowed to neither wait on IO nor call a ready selectable.
30
+ MAX_BUSY_ITERATIONS = 1000
31
+
27
32
  private_constant :READABLE
28
33
  private_constant :WRITABLE
34
+ private_constant :MAX_BUSY_ITERATIONS
29
35
 
30
36
  def_delegator :@timers, :after
31
37
 
@@ -35,6 +41,8 @@ module HTTPX
35
41
  @timers = Timers.new
36
42
  @selectables = []
37
43
  @is_timer_interval = false
44
+ @busy_iterations = 0
45
+ @last_select_registered = nil
38
46
  end
39
47
 
40
48
  def empty?
@@ -51,11 +59,16 @@ module HTTPX
51
59
  timeout = next_timeout
52
60
  if timeout && timeout.negative?
53
61
  @timers.fire
62
+ busy_loop_check(timeout)
54
63
  throw(:jump_tick)
55
64
  end
56
65
 
57
66
  begin
67
+ selected = false
68
+
58
69
  select(timeout) do |c|
70
+ selected = true
71
+
59
72
  c.log(level: 2) { "[#{c.state}] selected from selector##{object_id}#{" after #{timeout} secs" unless timeout.nil?}..." }
60
73
 
61
74
  c.call
@@ -64,17 +77,32 @@ module HTTPX
64
77
  @timers.fire
65
78
  rescue TimeoutError => e
66
79
  @timers.fire(e)
80
+
81
+ @busy_iterations = 0
82
+ else
83
+ # a tick is healthy if it either called a ready selectable, or actually blocked waiting for one.
84
+ # without a timeout, #select only blocks when something registered interests; with one,
85
+ # it always sleeps or selects, but a zero timeout just polls.
86
+ waited = timeout.nil? ? @last_select_registered.to_i.positive? : timeout.positive?
87
+
88
+ if selected || waited
89
+ @busy_iterations = 0
90
+ else
91
+ busy_loop_check(timeout)
92
+ end
67
93
  end
68
94
  end
69
95
  end
70
96
 
71
- def terminate
97
+ def terminate(selectables = nil)
72
98
  # array may change during iteration
73
- selectables = @selectables.reject(&:inflight?)
99
+ selectables ||= @selectables.reject(&:inflight?)
74
100
 
75
101
  selectables.delete_if do |sel|
76
102
  sel.terminate
77
- sel.state == :closed
103
+ # TODO: this check is racy: connections check in to the pool on termination, and may check out and
104
+ # change state immediately after. find a more idempotent way of doing this.
105
+ sel.current_selector != self
78
106
  end
79
107
 
80
108
  until selectables.empty?
@@ -133,6 +161,8 @@ module HTTPX
133
161
  private
134
162
 
135
163
  def select(interval, &block)
164
+ @last_select_registered = nil
165
+
136
166
  # do not cause an infinite loop here.
137
167
  #
138
168
  # this may happen if timeout calculation actually triggered an error which causes
@@ -153,10 +183,12 @@ module HTTPX
153
183
  # @type var w: (selectable | Array[selectable])?
154
184
  r, w = nil
155
185
 
186
+ registered = 0
187
+
156
188
  @selectables.delete_if do |io|
157
189
  interests = io.interests
158
190
 
159
- is_closed = io.state == :closed
191
+ is_closed = io.closed_for_select?
160
192
 
161
193
  if is_closed
162
194
  # the process by which io was closed may have already triggered the on_close callback,
@@ -166,6 +198,8 @@ module HTTPX
166
198
  end
167
199
 
168
200
  if interests
201
+ registered += 1
202
+
169
203
  io.log(level: 2) do
170
204
  "[#{io.state}] registering in selector##{object_id} for select (#{interests})#{" for #{interval} seconds" unless interval.nil?}"
171
205
  end
@@ -182,6 +216,8 @@ module HTTPX
182
216
  is_closed
183
217
  end
184
218
 
219
+ @last_select_registered = registered
220
+
185
221
  case r
186
222
  when Array
187
223
  w = Array(w) unless w.nil?
@@ -192,7 +228,14 @@ module HTTPX
192
228
  when Array
193
229
  select_many(r, w, interval, &block)
194
230
  when nil
195
- return unless interval && @selectables.any?
231
+ unless interval && @selectables.any?
232
+ # @fiber-switch-guard
233
+ # may mean that another fiber is moving a selectable forward (i.e. closing its
234
+ # socket), so let the scheduler resume it.
235
+ sleep(0) if HAS_FIBER_SCHEDULER && Fiber.scheduler
236
+
237
+ return
238
+ end
196
239
 
197
240
  # no selectables
198
241
  # TODO: replace with sleep?
@@ -221,18 +264,19 @@ module HTTPX
221
264
  begin
222
265
  readers, writers = ::IO.select(r, w, nil, interval)
223
266
  rescue IOError => e
224
- (Array(r) + Array(w)).each do |sel|
225
- # TODO: is there a way to cheaply find the IO associated with the error?
267
+ selectables_with_closed_ios(r, w).each do |sel|
226
268
  sel.on_io_error(e)
227
269
  end
270
+
271
+ return
228
272
  rescue StandardError => e
229
- (Array(r) + Array(w)).each do |sel|
273
+ selectables_with_closed_ios(r, w).each do |sel|
230
274
  sel.on_error(e)
231
275
  end
232
276
 
233
277
  return
234
278
  rescue Exception => e # rubocop:disable Lint/RescueException
235
- (Array(r) + Array(w)).each do |sel|
279
+ Set[*Array(r), *Array(w)].each do |sel|
236
280
  sel.force_close(true)
237
281
  end
238
282
 
@@ -258,6 +302,16 @@ module HTTPX
258
302
  end
259
303
  end
260
304
 
305
+ # returns the selectables whose IOs were closed.
306
+ def selectables_with_closed_ios(r, w)
307
+ selectables = Set[*Array(r), *Array(w)]
308
+
309
+ closed = selectables.select { |sel| sel.to_io.closed? }
310
+
311
+ # When none of them was closed, the error can't be attributed to any of them, so all are returned.
312
+ closed.empty? ? selectables : closed
313
+ end
314
+
261
315
  def select_one(io, interests, interval)
262
316
  begin
263
317
  result =
@@ -306,6 +360,53 @@ module HTTPX
306
360
  connection_interval
307
361
  end
308
362
 
363
+ def busy_loop_check(timeout)
364
+ @busy_iterations += 1
365
+
366
+ return if @busy_iterations < MAX_BUSY_ITERATIONS
367
+
368
+ # this selector is reused by subsequent requests in the same thread/fiber.
369
+ @busy_iterations = 0
370
+
371
+ raise Error, busy_loop_error_message(timeout)
372
+ end
373
+
374
+ def busy_loop_error_message(timeout)
375
+ selectables_state = @selectables.map do |sel|
376
+ state = +"#{sel.class}:#{sel.object_id}[state:#{sel.state},inflight?:#{sel.inflight?}"
377
+
378
+ case sel
379
+ when Connection
380
+ state << ",origin:#{sel.origin},pending:#{sel.pending.size}," \
381
+ "io-state:#{sel.io&.state.inspect},io-interests:#{sel.io&.interests.inspect}," \
382
+ "in-session:#{!sel.current_session.nil?}"
383
+ when Resolver::Resolver
384
+ num_connections = 0
385
+ sel.each_connection { num_connections += 1 }
386
+ state << ",connections:#{num_connections}"
387
+ end
388
+
389
+ state << "]"
390
+ end.join(",")
391
+
392
+ timers_state = @timers.instance_variable_get(:@intervals).map do |interval|
393
+ "#{interval.interval}s(callbacks:#{interval.instance_variable_get(:@callbacks).size})"
394
+ end.join(",")
395
+
396
+ "selector corrupted, aborted after looping #{MAX_BUSY_ITERATIONS} times " \
397
+ "without waiting on IO nor calling a ready selectable, " \
398
+ "please report this https://gitlab.com/os85/httpx/-/work_items " \
399
+ "along with debug logs\n(" \
400
+ "next-timeout:#{timeout.inspect}," \
401
+ "is-timer-interval:#{@is_timer_interval}," \
402
+ "timers:[#{timers_state}]," \
403
+ "next-interval-at:#{@timers.instance_variable_get(:@next_interval_at).inspect}," \
404
+ "last-select-registered:#{@last_select_registered.inspect}," \
405
+ "num-selectables:#{@selectables.size}," \
406
+ "selectables:[#{selectables_state}]" \
407
+ ")"
408
+ end
409
+
309
410
  if RUBY_ENGINE == "jruby"
310
411
  def rw_wait(io, interval)
311
412
  io.to_io.wait(interval, :read_write)
data/lib/httpx/session.rb CHANGED
@@ -46,7 +46,7 @@ module HTTPX
46
46
  ensure
47
47
  unless prev_wrapped
48
48
  if @persistent
49
- deactivate(current_selector)
49
+ deactivate(current_selector, $ERROR_INFO)
50
50
  else
51
51
  close(current_selector)
52
52
  end
@@ -143,7 +143,7 @@ module HTTPX
143
143
  # do not check-in connections only created for Happy Eyeballs
144
144
  return if cloned
145
145
 
146
- return if @closing && connection.state == :closed && !connection.used?
146
+ return unless can_checkin?(connection)
147
147
 
148
148
  connection.log(level: 2) { "check-in connection##{connection.object_id}(#{connection.state}) in pool##{@pool.object_id}" }
149
149
  @pool.checkin_connection(connection)
@@ -211,18 +211,33 @@ module HTTPX
211
211
 
212
212
  private
213
213
 
214
- def selector_close(selector)
214
+ def can_checkin?(connection)
215
+ !@closing || connection.state != :closed || connection.used?
216
+ end
217
+
218
+ def selector_close(selector, ...)
215
219
  begin
216
220
  @closing = true
217
- selector.terminate
221
+ selector.terminate(...)
218
222
  ensure
219
223
  @closing = false
220
224
  end
221
225
  end
222
226
 
223
227
  # tries deactivating connections in the +selector+, deregistering the ones that have been deactivated.
224
- def deactivate(selector)
225
- selector.each_connection.to_a.each(&:deactivate)
228
+ def deactivate(selector, error = nil)
229
+ selector.each_connection.to_a.each do |connection|
230
+ if (pending_count = connection.pending_count).positive?
231
+ warn "connection deactivated with pending requests, " \
232
+ "please report this https://gitlab.com/os85/httpx/-/work_items " \
233
+ "along with debug logs\n(" \
234
+ "state:#{connection.state},pending:#{pending_count}," \
235
+ "connection-pending:#{connection.pending.size}," \
236
+ "deactivate-on-error:#{error&.detailed_message}," \
237
+ ")"
238
+ end
239
+ connection.deactivate
240
+ end
226
241
  end
227
242
 
228
243
  # callback executed when an HTTP/2 promise frame has been received.
@@ -242,13 +257,18 @@ module HTTPX
242
257
  response
243
258
  end
244
259
 
245
- # sends the +request+ to the corresponding HTTPX::Connection
246
- def send_request(request, selector, options = request.options)
260
+ # sends the +request+ to a suitable HTTPX::Connection, which gets yielded if a block is passed.
261
+ def send_request(request, selector, options = request.options, &blk)
247
262
  error = begin
248
263
  catch(:resolve_error) do
249
264
  log(level: 2) { "finding connection for request##{request.object_id}..." }
250
265
  connection = find_connection(request.uri, selector, options)
251
- connection.send(request)
266
+ yield(connection) if blk
267
+ do_request(
268
+ request,
269
+ connection,
270
+ selector
271
+ )
252
272
  end
253
273
  rescue StandardError => e
254
274
  e
@@ -262,6 +282,10 @@ module HTTPX
262
282
  request.emit_response(response)
263
283
  end
264
284
 
285
+ def do_request(request, connection, _)
286
+ connection.send(request)
287
+ end
288
+
265
289
  # returns a set of HTTPX::Request objects built from the given +args+ and +options+.
266
290
  def build_requests(*args, params)
267
291
  requests = if args.size == 1
@@ -269,6 +293,7 @@ module HTTPX
269
293
  reqs.map do |verb, uri, ps = EMPTY_HASH|
270
294
  request_params = params
271
295
  request_params = request_params.merge(ps) unless ps.empty?
296
+ request_params = request_params.dup unless request_params.empty? && reqs.size == 1
272
297
  build_request(verb, uri, request_params)
273
298
  end
274
299
  else
@@ -277,6 +302,7 @@ module HTTPX
277
302
  uris.enum_for(:each).map do |uri, ps = EMPTY_HASH|
278
303
  request_params = params
279
304
  request_params = request_params.merge(ps) unless ps.empty?
305
+ request_params = request_params.dup unless request_params.empty? && uris.size == 1
280
306
  build_request(verb, uri, request_params)
281
307
  end
282
308
  else
@@ -304,7 +330,7 @@ module HTTPX
304
330
  ensure
305
331
  unless @wrapped
306
332
  if @persistent
307
- deactivate(selector)
333
+ deactivate(selector, $ERROR_INFO)
308
334
  else
309
335
  close(selector)
310
336
  end
@@ -56,7 +56,7 @@ module HTTPX::Transcoder
56
56
  def json_load(...); MultiJson.load(...); end
57
57
  def json_dump(...); MultiJson.dump(...); end
58
58
  elsif defined?(Oj)
59
- def json_load(response, ...); Oj.load(response.to_s, ...); end
59
+ def json_load(response, options = {}); Oj.load(response.to_s, { mode: :strict }.merge(options)); end
60
60
  def json_dump(obj, options = {}); Oj.dump(obj, { mode: :compat }.merge(options)); end
61
61
  elsif defined?(Yajl)
62
62
  def json_load(response, ...); Yajl::Parser.new(...).parse(response.to_s); end
data/lib/httpx/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module HTTPX
4
- VERSION = "1.8.4"
4
+ VERSION = "1.9.1"
5
5
  end
data/lib/httpx.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "set"
3
4
  require "httpx/version"
4
5
 
5
6
  # Top-Level Namespace
data/sig/altsvc.rbs CHANGED
@@ -31,11 +31,11 @@ module HTTPX
31
31
 
32
32
  def self?.emit: (Request request, response response) { (http_uri alt_origin, String origin, altsvc_params alt_params) -> void } -> void
33
33
 
34
- def self?.parse: (String altsvc) { (http_uri alt_origin, altsvc_params alt_params) -> void } -> void
35
- | (String altsvc) -> Enumerable[[http_uri, altsvc_params]]
34
+ def self?.parse: (String altsvc, ?host: String?) { (http_uri alt_origin, altsvc_params alt_params) -> void } -> void
35
+ | (String altsvc, ?host: String?) -> Enumerable[[http_uri, altsvc_params]]
36
36
 
37
37
  def self?.parse_altsvc_scheme: (String alt_proto) -> String?
38
38
 
39
- def self.parse_altsvc_origin: (string alt_proto, String alt_origin) -> http_uri?
39
+ def self.parse_altsvc_origin: (string alt_proto, String alt_origin, ?host: String?) -> http_uri?
40
40
  end
41
41
  end
data/sig/callbacks.rbs CHANGED
@@ -4,6 +4,7 @@ module HTTPX
4
4
  end
5
5
 
6
6
  module Callbacks
7
+ @callbacks: Hash[Symbol, Array[_Callable]]?
7
8
  def on: (Symbol) { (*untyped) -> void } -> ^(*untyped) -> void
8
9
  def once: (Symbol) { (*untyped) -> void } -> ^(*untyped) -> void
9
10
  def emit: (Symbol, *untyped) -> void
data/sig/chainable.rbs CHANGED
@@ -2,7 +2,8 @@ module HTTPX
2
2
  module Chainable
3
3
  def request: (Request, **untyped) -> response
4
4
  | (*Request, **untyped) -> Array[response]
5
- | (verb, uri | [uri], **untyped) -> response
5
+ | (verb, uri, **untyped) -> response
6
+ | (verb, [uri], **untyped) -> response
6
7
  | (Array[[verb, uri] | [verb, uri, request_params]], **untyped) -> Array[response]
7
8
  | (verb, _Each[uri | [uri, request_params]], **untyped) -> Array[response]
8
9
 
@@ -47,6 +48,7 @@ module HTTPX
47
48
  | (:xml, ?options) -> Plugins::sessionXML
48
49
  | (:query, ?options) -> Plugins::sessionQuery
49
50
  | (:tracing, ?options) -> Plugins::sessionTracing
51
+ | (:hedging, ?options) -> Plugins::sessionHedging
50
52
  | (Symbol | Module, ?options) { (Class) -> void } -> Session
51
53
  | (Symbol | Module, ?options) -> Session
52
54
 
@@ -36,7 +36,7 @@ module HTTPX
36
36
 
37
37
  def <<: (string) -> void
38
38
 
39
- def send: (Request) -> void
39
+ def send: (Request request, ?bool head) -> bool
40
40
 
41
41
  def consume: () -> void
42
42
 
@@ -60,9 +60,11 @@ module HTTPX
60
60
 
61
61
  def timeout: () -> interval?
62
62
 
63
+ def no_more_requests?: () -> bool
64
+
63
65
  private
64
66
 
65
- def initialize: (Buffer buffer, Options options) -> untyped
67
+ def initialize: (Buffer buffer, Array[Request] pending, Options options) -> untyped
66
68
 
67
69
  def manage_connection: (Request request, Response response) -> void
68
70
 
@@ -5,7 +5,7 @@ module HTTPX
5
5
 
6
6
  MAX_CONCURRENT_REQUESTS: Integer
7
7
 
8
- attr_reader streams: Hash[Request, ::HTTP2::Stream]
8
+ attr_reader streams: Hash[Request, HTTP2::Stream]
9
9
 
10
10
  attr_reader pending: Array[Request]
11
11
 
@@ -14,12 +14,13 @@ module HTTPX
14
14
  @settings: Hash[Symbol, Integer | bool]
15
15
  @max_concurrent_requests: Integer
16
16
  @max_requests: Integer
17
- @drains: Hash[Request, String]
17
+ @drains: Hash[HTTP2::Stream, String]
18
18
  @pings: Array[String]
19
19
  @streams_to_close_after_receive: Array[[HTTP2::Stream, Request, HTTPX::Error]]
20
20
  @buffer: Buffer
21
21
  @handshake_completed: bool
22
22
  @wait_for_handshake: bool
23
+ @last_error: GoawayError?
23
24
 
24
25
  def interests: () -> io_interests?
25
26
 
@@ -47,45 +48,49 @@ module HTTPX
47
48
 
48
49
  def reset_requests: () -> void
49
50
 
51
+ def no_more_requests?: () -> bool
52
+
50
53
  private
51
54
 
52
- def initialize: (Buffer buffer, Options options) -> untyped
55
+ def initialize: (Buffer buffer, Array[Request] pending, Options options) -> untyped
56
+
57
+ def waiting_for_peer?: () -> bool
53
58
 
54
- def can_buffer_more_requests?: () -> bool
59
+ def can_buffer_pending_requests?: () -> bool
55
60
 
56
61
  def send_pending: () -> void
57
62
 
58
63
  def set_protocol_headers: (Request) -> _Each[[String, String]]
59
64
 
60
- def handle: (Request request, ::HTTP2::Stream stream) -> void
65
+ def handle: (Request request, HTTP2::Stream stream) -> void
61
66
 
62
67
  def init_connection: () -> void
63
68
 
64
- def handle_stream: (::HTTP2::Stream stream, Request request) -> void
69
+ def handle_stream: (HTTP2::Stream stream, Request request) -> void
65
70
 
66
71
  def join_headline: (Request request) -> String
67
72
 
68
- def join_headers: (::HTTP2::Stream stream, Request request) -> void
73
+ def join_headers: (HTTP2::Stream stream, Request request) -> void
69
74
 
70
- def join_trailers: (::HTTP2::Stream stream, Request request) -> void
75
+ def join_trailers: (HTTP2::Stream stream, Request request) -> void
71
76
 
72
- def join_body: (::HTTP2::Stream stream, Request request) -> void
77
+ def join_body: (HTTP2::Stream stream, Request request) -> void
73
78
 
74
- def send_chunk: (Request request, ::HTTP2::Stream stream, String chunk, String? next_chunk) -> void
79
+ def send_chunk: (Request request, HTTP2::Stream stream, String chunk, String? next_chunk) -> void
75
80
 
76
81
  def end_stream?: (Request request, String? next_chunk) -> void
77
82
 
78
- def on_stream_headers: (::HTTP2::Stream stream, Request request, Array[[String, String]] headers) -> void
83
+ def on_stream_headers: (HTTP2::Stream stream, Request request, Array[[String, String]] headers) -> void
79
84
 
80
- def on_stream_trailers: (::HTTP2::Stream stream, Request request, Response response, Array[[String, String]] headers) -> void
85
+ def on_stream_trailers: (HTTP2::Stream stream, Request request, Response response, Array[[String, String]] headers) -> void
81
86
 
82
- def on_stream_data: (::HTTP2::Stream stream, Request request, String data) -> void
87
+ def on_stream_data: (HTTP2::Stream stream, Request request, String data) -> void
83
88
 
84
- def on_stream_refuse: (::HTTP2::Stream stream, Request request, StandardError error) -> void
89
+ def on_stream_refuse: (HTTP2::Stream stream, Request request, StandardError error) -> void
85
90
 
86
- def on_stream_half_close: (::HTTP2::Stream stream, Request request) -> void
91
+ def on_stream_half_close: (HTTP2::Stream stream, Request request) -> void
87
92
 
88
- def on_stream_close: (::HTTP2::Stream stream, Request request, (Symbol | StandardError)? error) -> void
93
+ def on_stream_close: (HTTP2::Stream stream, Request request, (Symbol | StandardError)? error) -> void
89
94
 
90
95
  def on_frame: (string bytes) -> void
91
96
 
@@ -101,7 +106,7 @@ module HTTPX
101
106
 
102
107
  def on_altsvc: (String origin, ::HTTP2::frame frame) -> void
103
108
 
104
- def on_promise: (::HTTP2::Stream stream) -> void
109
+ def on_promise: (HTTP2::Stream stream) -> void
105
110
 
106
111
  def on_origin: (String) -> void
107
112
 
@@ -119,6 +124,7 @@ module HTTPX
119
124
  UNRECOVERABLE_ERRORS: Array[Symbol]
120
125
 
121
126
  @code: Symbol
127
+ @last_stream_id: Integer
122
128
 
123
129
  def initialize: (Symbol code, Integer last_stream_id) -> void
124
130
 
data/sig/connection.rbs CHANGED
@@ -37,7 +37,6 @@ module HTTPX
37
37
 
38
38
 
39
39
  @window_size: Integer
40
- @inflight: Integer
41
40
  @max_concurrent_requests: Integer?
42
41
  @keep_alive_timeout: interval?
43
42
  @timeout: interval?
@@ -47,6 +46,7 @@ module HTTPX
47
46
  @response_received_at: Float
48
47
  @exhausted: bool
49
48
  @cloned: bool
49
+ @reset_timeout_on_call: bool
50
50
  @previously_exhausted_with_error: bool
51
51
  @coalesced_connection: instance?
52
52
  @altsvc_connection: instance?
@@ -78,6 +78,8 @@ module HTTPX
78
78
 
79
79
  def merge: (Connection connection) -> void
80
80
 
81
+ def pending_count: () -> Integer
82
+
81
83
  def purge_pending: () { (Request request) -> void } -> void
82
84
 
83
85
  def connecting?: () -> bool
@@ -88,6 +90,8 @@ module HTTPX
88
90
 
89
91
  def inflight?: () -> boolish
90
92
 
93
+ def closed_for_select?: () -> bool
94
+
91
95
  def interests: () -> io_interests?
92
96
 
93
97
  def to_io: () -> IO
@@ -136,6 +140,12 @@ module HTTPX
136
140
 
137
141
  def initialize_type: (http_uri uri, Options options) -> io_type
138
142
 
143
+ def connect_attempt_time_left: () -> interval?
144
+
145
+ def connect_next: (StandardError error) -> void
146
+
147
+ def try_connect: () -> void
148
+
139
149
  def connect: () -> void
140
150
 
141
151
  def exhausted?: () -> boolish
@@ -146,12 +156,12 @@ module HTTPX
146
156
 
147
157
  def parser: () -> (Object & _Parser)
148
158
 
149
- def send_request_to_parser: (Request request) -> void
150
-
151
- def enqueue_pending_requests_from_parser: (HTTP1 | HTTP2 parser) -> void
159
+ def send_request_to_parser: (Request request, ?bool head) -> bool
152
160
 
153
161
  def build_parser: (?String protocol) -> (Object & _Parser)
154
162
 
163
+ def on_parser_error: (Request request, Exception | Symbol error) -> void
164
+
155
165
  def set_parser_callbacks: (HTTP1 | HTTP2 parser) -> void
156
166
 
157
167
  def transition: (Symbol nextstate) -> void
@@ -166,20 +176,26 @@ module HTTPX
166
176
 
167
177
  def pong: () -> void
168
178
 
169
- def no_more_requests_loop_check: () -> void
179
+ def no_more_selector_check: () -> void
170
180
 
171
- def no_more_requests?: () -> bool
181
+ def clear_pending_requests: () -> void
182
+
183
+ def no_more_requests?: () -> boolish
172
184
 
173
185
  def handle_error: (StandardError error, ?Request? request) -> void
174
186
 
175
187
  def force_purge: () -> void
176
188
 
189
+ def reset_ping_timer: () -> void
190
+
177
191
  def close_sibling: () -> void
178
192
 
179
193
  def purge_after_closed: () -> void
180
194
 
181
195
  def set_request_timeouts: (Request request) -> void
182
196
 
197
+ def set_connection_timeouts: (Request request) -> void
198
+
183
199
  def set_request_read_timeout: (Request request) -> void
184
200
 
185
201
  def set_request_write_timeout: (Request request) -> void
@@ -188,12 +204,18 @@ module HTTPX
188
204
 
189
205
  def set_request_total_request_timeout: (Request request) -> void
190
206
 
191
- def write_timeout_callback: (Request request, Numeric timeout) -> void
207
+ def write_timeout_callback: (Request request, interval timeout) -> void
192
208
 
193
209
  def read_timeout_callback: (Request request, interval timeout, ?singleton(RequestTimeoutError) error_type) -> void
194
210
 
195
211
  def set_request_timeout: (Symbol label, Request request, interval timeout, Symbol start_event, Symbol | Array[Symbol] finish_events) { () -> void } -> void
196
212
 
213
+ def set_connecting_request_timeout: (Request request) -> void
214
+
215
+ def set_connecting_total_request_timeout: (Request request) -> void
216
+
217
+ def set_connection_timeout: (Symbol label, Request request, interval timeout, Symbol start_event, Symbol | Array[Symbol] finish_events) { () -> void } -> void
218
+
197
219
  def parser_type: (String protocol) -> (singleton(HTTP1) | singleton(HTTP2))
198
220
  end
199
221
  end
data/sig/headers.rbs CHANGED
@@ -17,7 +17,7 @@ module HTTPX
17
17
  def each: (?_Each[[String, String]]? extra_headers) { (String k, String v) -> void } -> void
18
18
  | (?_Each[[String, String]]? extra_headers) -> Enumerable[[String, String]]
19
19
 
20
- def get: (String field) -> Array[_ToS]
20
+ def get: (String downcased_key) -> Array[_ToS]
21
21
  def key?: (String downcased_key) -> bool
22
22
 
23
23
  def merge: (_Each[[String, headers_value]] other) -> Headers
data/sig/httpx.rbs CHANGED
@@ -18,6 +18,8 @@ module HTTPX
18
18
 
19
19
  type ip_family = Integer #Socket::AF_INET6 | Socket::AF_INET
20
20
 
21
+ type resolver = Resolver::Multi | Resolver::Resolver
22
+
21
23
  module Plugins
22
24
  self.@plugins: Hash[Symbol, Module]
23
25
  self.@plugins_mutex: Thread::Mutex