httpx 1.5.1 → 1.6.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.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/doc/release_notes/1_6_0.md +50 -0
  3. data/lib/httpx/adapters/datadog.rb +23 -13
  4. data/lib/httpx/adapters/faraday.rb +14 -9
  5. data/lib/httpx/adapters/webmock.rb +1 -1
  6. data/lib/httpx/callbacks.rb +1 -1
  7. data/lib/httpx/connection/http1.rb +5 -6
  8. data/lib/httpx/connection/http2.rb +30 -12
  9. data/lib/httpx/connection.rb +17 -24
  10. data/lib/httpx/errors.rb +3 -1
  11. data/lib/httpx/io/ssl.rb +1 -4
  12. data/lib/httpx/io/tcp.rb +25 -16
  13. data/lib/httpx/io/unix.rb +4 -3
  14. data/lib/httpx/loggable.rb +4 -1
  15. data/lib/httpx/options.rb +252 -158
  16. data/lib/httpx/plugins/aws_sdk_authentication.rb +2 -0
  17. data/lib/httpx/plugins/aws_sigv4.rb +2 -0
  18. data/lib/httpx/plugins/callbacks.rb +13 -1
  19. data/lib/httpx/plugins/circuit_breaker.rb +2 -0
  20. data/lib/httpx/plugins/content_digest.rb +2 -0
  21. data/lib/httpx/plugins/cookies.rb +2 -2
  22. data/lib/httpx/plugins/digest_auth.rb +2 -0
  23. data/lib/httpx/plugins/expect.rb +2 -0
  24. data/lib/httpx/plugins/fiber_concurrency.rb +195 -0
  25. data/lib/httpx/plugins/follow_redirects.rb +2 -0
  26. data/lib/httpx/plugins/grpc.rb +2 -0
  27. data/lib/httpx/plugins/h2c.rb +26 -16
  28. data/lib/httpx/plugins/internal_telemetry.rb +0 -49
  29. data/lib/httpx/plugins/ntlm_auth.rb +2 -0
  30. data/lib/httpx/plugins/oauth.rb +2 -0
  31. data/lib/httpx/plugins/persistent.rb +27 -18
  32. data/lib/httpx/plugins/proxy/socks4.rb +1 -1
  33. data/lib/httpx/plugins/proxy/socks5.rb +1 -1
  34. data/lib/httpx/plugins/proxy/ssh.rb +2 -0
  35. data/lib/httpx/plugins/proxy.rb +61 -20
  36. data/lib/httpx/plugins/response_cache/file_store.rb +2 -2
  37. data/lib/httpx/plugins/response_cache.rb +2 -0
  38. data/lib/httpx/plugins/retries.rb +2 -0
  39. data/lib/httpx/plugins/ssrf_filter.rb +2 -2
  40. data/lib/httpx/plugins/stream_bidi.rb +3 -3
  41. data/lib/httpx/plugins/upgrade/h2.rb +11 -1
  42. data/lib/httpx/plugins/upgrade.rb +8 -0
  43. data/lib/httpx/pool.rb +15 -10
  44. data/lib/httpx/request/body.rb +8 -3
  45. data/lib/httpx/request.rb +22 -11
  46. data/lib/httpx/resolver/entry.rb +30 -0
  47. data/lib/httpx/resolver/https.rb +3 -1
  48. data/lib/httpx/resolver/multi.rb +5 -2
  49. data/lib/httpx/resolver/native.rb +15 -6
  50. data/lib/httpx/resolver/resolver.rb +3 -5
  51. data/lib/httpx/resolver/system.rb +1 -1
  52. data/lib/httpx/resolver.rb +34 -21
  53. data/lib/httpx/response/body.rb +1 -1
  54. data/lib/httpx/response/buffer.rb +13 -18
  55. data/lib/httpx/selector.rb +92 -34
  56. data/lib/httpx/session.rb +89 -30
  57. data/lib/httpx/session_extensions.rb +3 -2
  58. data/lib/httpx/transcoder/form.rb +1 -13
  59. data/lib/httpx/transcoder/multipart/mime_type_detector.rb +1 -1
  60. data/lib/httpx/transcoder/multipart.rb +14 -0
  61. data/lib/httpx/transcoder/utils/deflater.rb +1 -1
  62. data/lib/httpx/version.rb +1 -1
  63. data/sig/callbacks.rbs +1 -1
  64. data/sig/chainable.rbs +1 -0
  65. data/sig/connection/http1.rbs +2 -0
  66. data/sig/connection/http2.rbs +4 -0
  67. data/sig/connection.rbs +6 -6
  68. data/sig/errors.rbs +3 -1
  69. data/sig/io/ssl.rbs +1 -1
  70. data/sig/io/tcp.rbs +13 -7
  71. data/sig/io/udp.rbs +7 -2
  72. data/sig/io/unix.rbs +0 -1
  73. data/sig/io.rbs +0 -3
  74. data/sig/options.rbs +63 -10
  75. data/sig/plugins/fiber_concurrency.rbs +51 -0
  76. data/sig/plugins/h2c.rbs +5 -1
  77. data/sig/plugins/persistent.rbs +1 -1
  78. data/sig/plugins/proxy/socks4.rbs +1 -1
  79. data/sig/plugins/proxy/socks5.rbs +1 -1
  80. data/sig/plugins/proxy.rbs +5 -2
  81. data/sig/plugins/ssrf_filter.rbs +1 -1
  82. data/sig/plugins/stream_bidi.rbs +2 -2
  83. data/sig/request.rbs +4 -1
  84. data/sig/resolver/entry.rbs +13 -0
  85. data/sig/resolver/native.rbs +1 -0
  86. data/sig/resolver/resolver.rbs +2 -3
  87. data/sig/resolver/system.rbs +2 -2
  88. data/sig/resolver.rbs +10 -11
  89. data/sig/response.rbs +2 -2
  90. data/sig/selector.rbs +18 -10
  91. data/sig/session.rbs +4 -0
  92. data/sig/transcoder/form.rbs +3 -3
  93. data/sig/transcoder/multipart.rbs +9 -3
  94. metadata +9 -3
@@ -3,6 +3,21 @@
3
3
  require "io/wait"
4
4
 
5
5
  module HTTPX
6
+ #
7
+ # Implements the selector loop, where it registers and monitors "Selectable" objects.
8
+ #
9
+ # A Selectable object is an object which can calculate the **interests** (<tt>:r</tt>, <tt>:w</tt> or <tt>:rw</tt>,
10
+ # respectively "read", "write" or "read-write") it wants to monitor for, and returns (via <tt>to_io</tt> method) an
11
+ # IO object which can be passed to functions such as IO.select . More exhaustively, a Selectable **must** implement
12
+ # the following methods:
13
+ #
14
+ # state :: returns the state as a Symbol, must return <tt>:closed</tt> when disposed of resources.
15
+ # to_io :: returns the IO object.
16
+ # call :: gets called when the IO is ready.
17
+ # interests :: returns the current interests to monitor for, as described above.
18
+ # timeout :: returns nil or an integer, representing how long to wait for interests.
19
+ # handle_socket_timeout(Numeric) :: called when waiting for interest times out.
20
+ #
6
21
  class Selector
7
22
  extend Forwardable
8
23
 
@@ -123,38 +138,75 @@ module HTTPX
123
138
  private
124
139
 
125
140
  def select(interval, &block)
141
+ has_no_selectables = @selectables.empty?
126
142
  # do not cause an infinite loop here.
127
143
  #
128
144
  # this may happen if timeout calculation actually triggered an error which causes
129
145
  # the connections to be reaped (such as the total timeout error) before #select
130
146
  # gets called.
131
- return if interval.nil? && @selectables.empty?
147
+ return if interval.nil? && has_no_selectables
132
148
 
133
- return select_one(interval, &block) if @selectables.size == 1
134
-
135
- select_many(interval, &block)
136
- end
137
-
138
- def select_many(interval, &block)
149
+ # @type var r: (selectable | Array[selectable])?
150
+ # @type var w: (selectable | Array[selectable])?
139
151
  r, w = nil
140
152
 
141
- # first, we group IOs based on interest type. On call to #interests however,
142
- # things might already happen, and new IOs might be registered, so we might
143
- # have to start all over again. We do this until we group all selectables
144
153
  @selectables.delete_if do |io|
145
154
  interests = io.interests
146
155
 
156
+ is_closed = io.state == :closed
157
+
158
+ next(is_closed) if is_closed
159
+
147
160
  io.log(level: 2) { "[#{io.state}] registering for select (#{interests})#{" for #{interval} seconds" unless interval.nil?}" }
148
161
 
149
- (r ||= []) << io if READABLE.include?(interests)
150
- (w ||= []) << io if WRITABLE.include?(interests)
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
151
169
 
152
- io.state == :closed
170
+ is_closed
153
171
  end
154
172
 
155
- # TODO: what to do if there are no selectables?
173
+ case r
174
+ when Array
175
+ w = Array(w) unless w.nil?
176
+
177
+ select_many(r, w, interval, &block)
178
+ when nil
179
+ case w
180
+ when Array
181
+ select_many(r, w, interval, &block)
182
+ when nil
183
+ return unless interval && has_no_selectables
184
+
185
+ # no selectables
186
+ # TODO: replace with sleep?
187
+ select_many(r, w, interval, &block)
188
+ else
189
+ select_one(w, :w, interval, &block)
190
+ end
156
191
 
157
- readers, writers = IO.select(r, w, nil, interval)
192
+ else
193
+ case w
194
+ when Array
195
+ select_many(Array(r), w, interval, &block)
196
+ when nil
197
+ select_one(r, :r, interval, &block)
198
+ else
199
+ if r == w
200
+ select_one(r, :rw, interval, &block)
201
+ else
202
+ select_many(Array(r), Array(w), interval, &block)
203
+ end
204
+ end
205
+ end
206
+ end
207
+
208
+ def select_many(r, w, interval, &block)
209
+ readers, writers = ::IO.select(r, w, nil, interval)
158
210
 
159
211
  if readers.nil? && writers.nil? && interval
160
212
  [*r, *w].each { |io| io.handle_socket_timeout(interval) }
@@ -175,32 +227,20 @@ module HTTPX
175
227
  end
176
228
  end
177
229
 
178
- def select_one(interval)
179
- io = @selectables.first
180
-
181
- return unless io
182
-
183
- interests = io.interests
184
-
185
- io.log(level: 2) { "[#{io.state}] registering for select (#{interests})#{" for #{interval} seconds" unless interval.nil?}" }
186
-
187
- result = case interests
188
- when :r then io.to_io.wait_readable(interval)
189
- when :w then io.to_io.wait_writable(interval)
190
- when :rw then io.to_io.wait(interval, :read_write)
191
- when nil then return
192
- end
230
+ def select_one(io, interests, interval)
231
+ result =
232
+ case interests
233
+ when :r then io.to_io.wait_readable(interval)
234
+ when :w then io.to_io.wait_writable(interval)
235
+ when :rw then rw_wait(io, interval)
236
+ end
193
237
 
194
238
  unless result || interval.nil?
195
239
  io.handle_socket_timeout(interval) unless @is_timer_interval
196
240
  return
197
241
  end
198
- # raise TimeoutError.new(interval, "timed out while waiting on select")
199
242
 
200
243
  yield io
201
- # rescue IOError, SystemCallError
202
- # @selectables.reject!(&:closed?)
203
- # raise unless @selectables.empty?
204
244
  end
205
245
 
206
246
  def next_timeout
@@ -220,5 +260,23 @@ module HTTPX
220
260
 
221
261
  connection_interval
222
262
  end
263
+
264
+ if RUBY_ENGINE == "jruby"
265
+ def rw_wait(io, interval)
266
+ io.to_io.wait(interval, :read_write)
267
+ end
268
+ elsif IO.const_defined?(:READABLE)
269
+ def rw_wait(io, interval)
270
+ io.to_io.wait(IO::READABLE | IO::WRITABLE, interval)
271
+ end
272
+ else
273
+ def rw_wait(io, interval)
274
+ if interval
275
+ io.to_io.wait(interval, :read_write)
276
+ else
277
+ io.to_io.wait(:read_write)
278
+ end
279
+ end
280
+ end
223
281
  end
224
282
  end
data/lib/httpx/session.rb CHANGED
@@ -71,12 +71,8 @@ module HTTPX
71
71
 
72
72
  select_connection(connection, selector)
73
73
  end
74
- begin
75
- @closing = true
76
- selector.terminate
77
- ensure
78
- @closing = false
79
- end
74
+
75
+ selector_close(selector)
80
76
  end
81
77
 
82
78
  # performs one, or multple requests; it accepts:
@@ -136,6 +132,9 @@ module HTTPX
136
132
  alias_method :select_resolver, :select_connection
137
133
 
138
134
  def deselect_connection(connection, selector, cloned = false)
135
+ connection.log(level: 2) do
136
+ "deregistering connection##{connection.object_id}(#{connection.state}) from selector##{selector.object_id}"
137
+ end
139
138
  selector.deregister(connection)
140
139
 
141
140
  # when connections coalesce
@@ -145,14 +144,19 @@ module HTTPX
145
144
 
146
145
  return if @closing && connection.state == :closed
147
146
 
147
+ connection.log(level: 2) { "check-in connection##{connection.object_id}(#{connection.state}) in pool##{@pool.object_id}" }
148
148
  @pool.checkin_connection(connection)
149
149
  end
150
150
 
151
151
  def deselect_resolver(resolver, selector)
152
+ resolver.log(level: 2) do
153
+ "deregistering resolver##{resolver.object_id}(#{resolver.state}) from selector##{selector.object_id}"
154
+ end
152
155
  selector.deregister(resolver)
153
156
 
154
157
  return if @closing && resolver.closed?
155
158
 
159
+ resolver.log(level: 2) { "check-in resolver##{resolver.object_id}(#{resolver.state}) in pool##{@pool.object_id}" }
156
160
  @pool.checkin_resolver(resolver)
157
161
  end
158
162
 
@@ -194,7 +198,12 @@ module HTTPX
194
198
  end
195
199
  when :closing, :closed
196
200
  connection.idling
197
- select_connection(connection, selector)
201
+ if connection.addresses?
202
+ select_connection(connection, selector)
203
+ else
204
+ # if addresses expired, resolve again
205
+ resolve_connection(connection, selector)
206
+ end
198
207
  else
199
208
  pin_connection(connection, selector)
200
209
  end
@@ -204,10 +213,23 @@ module HTTPX
204
213
 
205
214
  private
206
215
 
216
+ def selector_close(selector)
217
+ begin
218
+ @closing = true
219
+ selector.terminate
220
+ ensure
221
+ @closing = false
222
+ end
223
+ end
224
+
225
+ # tries deactivating connections in the +selector+, deregistering the ones that have been deactivated.
207
226
  def deactivate(selector)
208
- selector.each_connection do |connection|
209
- connection.deactivate
210
- deselect_connection(connection, selector) if connection.state == :inactive
227
+ selector.each_connection.select do |c|
228
+ c.deactivate
229
+
230
+ c.state == :inactive
231
+ end.each do |c| # rubocop:disable Style/MultilineBlockChain
232
+ deselect_connection(c, selector)
211
233
  end
212
234
  end
213
235
 
@@ -221,7 +243,11 @@ module HTTPX
221
243
  def fetch_response(request, _selector, _options)
222
244
  response = request.response
223
245
 
224
- response if response && response.finished?
246
+ return unless response && response.finished?
247
+
248
+ log(level: 2) { "response fetched" }
249
+
250
+ response
225
251
  end
226
252
 
227
253
  # sends the +request+ to the corresponding HTTPX::Connection
@@ -303,8 +329,7 @@ module HTTPX
303
329
 
304
330
  # returns the array of HTTPX::Response objects corresponding to the array of HTTPX::Request +requests+.
305
331
  def receive_requests(requests, selector)
306
- # @type var responses: Array[response]
307
- responses = []
332
+ responses = [] # : Array[response]
308
333
 
309
334
  # guarantee ordered responses
310
335
  loop do
@@ -313,7 +338,7 @@ module HTTPX
313
338
  return responses unless request
314
339
 
315
340
  catch(:coalesced) { selector.next_tick } until (response = fetch_response(request, selector, request.options))
316
- request.emit(:complete, response)
341
+ request.complete!(response)
317
342
 
318
343
  responses << response
319
344
  requests.shift
@@ -326,18 +351,36 @@ module HTTPX
326
351
  # handshake error, and the error responses have already been emitted, but there was no
327
352
  # opportunity to traverse the requests, hence we're returning only a fraction of the errors
328
353
  # we were supposed to. This effectively fetches the existing responses and return them.
329
- while (request = requests.shift)
330
- response = fetch_response(request, selector, request.options)
331
- request.emit(:complete, response) if response
332
- responses << response
354
+ exit_from_loop = true
355
+
356
+ requests_to_remove = [] # : Array[Request]
357
+
358
+ requests.each do |req|
359
+ response = fetch_response(req, selector, request.options)
360
+
361
+ if exit_from_loop && response
362
+ req.complete!(response)
363
+ responses << response
364
+ requests_to_remove << req
365
+ else
366
+ # fetch_response may resend requests. when that happens, we need to go back to the initial
367
+ # loop and process the selector. we still do a pass-through on the remainder of requests, so
368
+ # that every request that need to be resent, is resent.
369
+ exit_from_loop = false
370
+
371
+ raise Error, "something went wrong, responses not found and requests not resent" if selector.empty?
372
+ end
333
373
  end
334
- break
374
+
375
+ break if exit_from_loop
376
+
377
+ requests -= requests_to_remove
335
378
  end
336
379
  responses
337
380
  end
338
381
 
339
382
  def resolve_connection(connection, selector)
340
- if connection.addresses || connection.open?
383
+ if connection.addresses? || connection.open?
341
384
  #
342
385
  # there are two cases in which we want to activate initialization of
343
386
  # connection immediately:
@@ -380,14 +423,16 @@ module HTTPX
380
423
  end
381
424
 
382
425
  def find_resolver_for(connection, selector)
383
- resolver = selector.find_resolver(connection.options)
384
-
385
- unless resolver
386
- resolver = @pool.checkout_resolver(connection.options)
387
- resolver.current_session = self
388
- resolver.current_selector = selector
426
+ if (resolver = selector.find_resolver(connection.options))
427
+ resolver.log(level: 2) { "found resolver##{connection.object_id}(#{connection.state}) in selector##{selector.object_id}" }
428
+ return resolver
389
429
  end
390
430
 
431
+ resolver = @pool.checkout_resolver(connection.options)
432
+ resolver.log(level: 2) { "found resolver##{connection.object_id}(#{connection.state}) in pool##{@pool.object_id}" }
433
+ resolver.current_session = self
434
+ resolver.current_selector = selector
435
+
391
436
  resolver
392
437
  end
393
438
 
@@ -397,7 +442,10 @@ module HTTPX
397
442
  unless conn1.coalescable?(conn2)
398
443
  conn2.log(level: 2) { "not coalescing with conn##{conn1.object_id}[#{conn1.origin}])" }
399
444
  select_connection(conn2, selector)
400
- @pool.checkin_connection(conn1) if from_pool
445
+ if from_pool
446
+ conn1.log(level: 2) { "check-in connection##{conn1.object_id}(#{conn1.state}) in pool##{@pool.object_id}" }
447
+ @pool.checkin_connection(conn1)
448
+ end
401
449
  return false
402
450
  end
403
451
 
@@ -422,13 +470,18 @@ module HTTPX
422
470
 
423
471
  def selector_store
424
472
  th_current = Thread.current
425
- th_current.thread_variable_get(:httpx_persistent_selector_store) || begin
473
+
474
+ thread_selector_store(th_current) || begin
426
475
  {}.compare_by_identity.tap do |store|
427
476
  th_current.thread_variable_set(:httpx_persistent_selector_store, store)
428
477
  end
429
478
  end
430
479
  end
431
480
 
481
+ def thread_selector_store(th)
482
+ th.thread_variable_get(:httpx_persistent_selector_store)
483
+ end
484
+
432
485
  @default_options = Options.new
433
486
  @default_options.freeze
434
487
  @plugins = []
@@ -452,6 +505,8 @@ module HTTPX
452
505
  label = pl
453
506
  # raise Error, "Cannot add a plugin to a frozen config" if frozen?
454
507
  pl = Plugins.load_plugin(pl) if pl.is_a?(Symbol)
508
+ raise ArgumentError, "Invalid plugin type: #{pl.class.inspect}" unless pl.is_a?(Module)
509
+
455
510
  if !@plugins.include?(pl)
456
511
  @plugins << pl
457
512
  pl.load_dependencies(self, &block) if pl.respond_to?(:load_dependencies)
@@ -463,9 +518,13 @@ module HTTPX
463
518
 
464
519
  opts = @default_options
465
520
  opts.extend_with_plugin_classes(pl)
466
- if defined?(pl::OptionsMethods)
467
521
 
468
- (pl::OptionsMethods.instance_methods - Object.instance_methods).each do |meth|
522
+ if defined?(pl::OptionsMethods)
523
+ # when a class gets dup'ed, the #initialize_dup callbacks isn't triggered.
524
+ # moreover, and because #method_added does not get triggered on mixin include,
525
+ # the callback is also forcefully manually called here.
526
+ opts.options_class.instance_variable_set(:@options_names, opts.options_class.options_names.dup)
527
+ (pl::OptionsMethods.instance_methods + pl::OptionsMethods.private_instance_methods - Object.instance_methods).each do |meth|
469
528
  opts.options_class.method_added(meth)
470
529
  end
471
530
  @default_options = opts.options_class.new(opts)
@@ -11,8 +11,9 @@ module HTTPX
11
11
  options = proxy_session.class.default_options.to_hash
12
12
  original_verbosity = $VERBOSE
13
13
  $VERBOSE = nil
14
- const_set(:Options, proxy_session.class.default_options.options_class)
15
- options[:options_class] = Class.new(options[:options_class])
14
+ new_options_class = proxy_session.class.default_options.options_class.dup
15
+ const_set(:Options, new_options_class)
16
+ options[:options_class] = Class.new(new_options_class).freeze
16
17
  options.freeze
17
18
  Options.send(:const_set, :DEFAULT_OPTIONS, options)
18
19
  Session.instance_variable_set(:@default_options, Options.new(options))
@@ -48,11 +48,7 @@ module HTTPX
48
48
  end
49
49
 
50
50
  def encode(form)
51
- if multipart?(form)
52
- Multipart::Encoder.new(form)
53
- else
54
- Encoder.new(form)
55
- end
51
+ Encoder.new(form)
56
52
  end
57
53
 
58
54
  def decode(response)
@@ -67,14 +63,6 @@ module HTTPX
67
63
  raise Error, "invalid form mime type (#{content_type})"
68
64
  end
69
65
  end
70
-
71
- def multipart?(data)
72
- data.any? do |_, v|
73
- Multipart::MULTIPART_VALUE_COND.call(v) ||
74
- (v.respond_to?(:to_ary) && v.to_ary.any?(&Multipart::MULTIPART_VALUE_COND)) ||
75
- (v.respond_to?(:to_hash) && v.to_hash.any? { |_, e| Multipart::MULTIPART_VALUE_COND.call(e) })
76
- end
77
- end
78
66
  end
79
67
  end
80
68
  end
@@ -44,7 +44,7 @@ module HTTPX
44
44
 
45
45
  Open3.popen3(*%w[file --mime-type --brief -]) do |stdin, stdout, stderr, thread|
46
46
  begin
47
- ::IO.copy_stream(file, stdin.binmode)
47
+ IO.copy_stream(file, stdin.binmode)
48
48
  rescue Errno::EPIPE
49
49
  end
50
50
  file.rewind
@@ -13,5 +13,19 @@ module HTTPX::Transcoder
13
13
  value.key?(:body) &&
14
14
  (value.key?(:filename) || value.key?(:content_type)))
15
15
  end
16
+
17
+ module_function
18
+
19
+ def multipart?(form_data)
20
+ form_data.any? do |_, v|
21
+ Multipart::MULTIPART_VALUE_COND.call(v) ||
22
+ (v.respond_to?(:to_ary) && v.to_ary.any?(&Multipart::MULTIPART_VALUE_COND)) ||
23
+ (v.respond_to?(:to_hash) && v.to_hash.any? { |_, e| Multipart::MULTIPART_VALUE_COND.call(e) })
24
+ end
25
+ end
26
+
27
+ def encode(form_data)
28
+ Encoder.new(form_data)
29
+ end
16
30
  end
17
31
  end
@@ -63,7 +63,7 @@ module HTTPX
63
63
  buffer = Response::Buffer.new(
64
64
  threshold_size: Options::MAX_BODY_THRESHOLD_SIZE
65
65
  )
66
- ::IO.copy_stream(self, buffer)
66
+ IO.copy_stream(self, buffer)
67
67
 
68
68
  buffer.rewind if buffer.respond_to?(:rewind)
69
69
 
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.5.1"
4
+ VERSION = "1.6.0"
5
5
  end
data/sig/callbacks.rbs CHANGED
@@ -8,7 +8,7 @@ module HTTPX
8
8
  def once: (Symbol) { (*untyped) -> void } -> ^(*untyped) -> void
9
9
  def emit: (Symbol, *untyped) -> void
10
10
 
11
- def callbacks_for?: (Symbol) -> bool
11
+ def callbacks_for?: (Symbol) -> boolish
12
12
  def callbacks: () -> Hash[Symbol, Array[_Callable]]
13
13
  | (Symbol) -> Array[_Callable]
14
14
  end
data/sig/chainable.rbs CHANGED
@@ -24,6 +24,7 @@ module HTTPX
24
24
  | (:upgrade, ?options) -> Plugins::sessionUpgrade
25
25
  | (:h2c, ?options) -> Plugins::sessionUpgrade
26
26
  | (:h2, ?options) -> Plugins::sessionUpgrade
27
+ | (:fiber_concurrency, ?options) -> Plugins::sessionFiberConcurrency
27
28
  | (:persistent, ?options) -> Plugins::sessionPersistent
28
29
  | (:proxy, ?options) -> (Plugins::sessionProxy & Plugins::httpProxy)
29
30
  | (:push_promise, ?options) -> Plugins::sessionPushPromise
@@ -54,6 +54,8 @@ module HTTPX
54
54
 
55
55
  def ping: () -> void
56
56
 
57
+ def waiting_for_ping?: () -> bool
58
+
57
59
  def timeout: () -> Numeric?
58
60
 
59
61
  private
@@ -37,6 +37,8 @@ module HTTPX
37
37
 
38
38
  def ping: () -> void
39
39
 
40
+ def waiting_for_ping?: () -> bool
41
+
40
42
  alias reset init_connection
41
43
 
42
44
  def timeout: () -> Numeric?
@@ -97,6 +99,8 @@ module HTTPX
97
99
 
98
100
  def on_pong: (string ping) -> void
99
101
 
102
+ def teardown: (?Request? request) -> void
103
+
100
104
  class Error < ::HTTPX::Error
101
105
  def initialize: (Integer id, Symbol | StandardError error) -> void
102
106
  end
data/sig/connection.rbs CHANGED
@@ -50,17 +50,17 @@ module HTTPX
50
50
  @main_sibling: bool
51
51
 
52
52
 
53
- def addresses: () -> Array[ipaddr]?
53
+ def addresses: () -> Array[Resolver::Entry]?
54
54
 
55
55
  def peer: () -> URI::Generic
56
56
 
57
- def addresses=: (Array[ipaddr] addresses) -> void
57
+ def addresses=: (Array[Resolver::Entry] addresses) -> void
58
58
 
59
59
  def send: (Request request) -> void
60
60
 
61
- def match?: (URI::Generic uri, Options options) -> bool
61
+ def addresses?: () -> boolish
62
62
 
63
- def expired?: () -> boolish
63
+ def match?: (URI::Generic uri, Options options) -> bool
64
64
 
65
65
  def mergeable?: (Connection connection) -> bool
66
66
 
@@ -82,7 +82,7 @@ module HTTPX
82
82
 
83
83
  def interests: () -> io_interests?
84
84
 
85
- def to_io: () -> ::IO
85
+ def to_io: () -> IO
86
86
 
87
87
  def call: () -> void
88
88
 
@@ -140,7 +140,7 @@ module HTTPX
140
140
 
141
141
  def build_altsvc_connection: (URI::Generic alt_origin, String origin, Hash[String, String] alt_params) -> void
142
142
 
143
- def build_socket: (?Array[ipaddr]? addrs) -> (TCP | SSL | UNIX)
143
+ def build_socket: (?Array[Resolver::Entry]? addrs) -> (TCP | SSL | UNIX)
144
144
 
145
145
  def on_error: (HTTPX::TimeoutError | Error | StandardError error, ?Request? request) -> void
146
146
 
data/sig/errors.rbs CHANGED
@@ -51,13 +51,15 @@ module HTTPX
51
51
  class HTTPError < Error
52
52
  attr_reader response: Response
53
53
 
54
+ def status: () -> Integer
55
+
54
56
  private
55
57
 
56
58
  def initialize: (Response response) -> void
57
59
  end
58
60
 
59
61
  class NativeResolveError < ResolveError
60
- attr_reader connection: Connection
62
+ attr_accessor connection: Connection?
61
63
  attr_reader host: String
62
64
 
63
65
  private
data/sig/io/ssl.rbs CHANGED
@@ -12,7 +12,7 @@ module HTTPX
12
12
  attr_writer ssl_session: OpenSSL::SSL::Session?
13
13
 
14
14
  # TODO: lift when https://github.com/ruby/rbs/issues/1497 fixed
15
- # def initialize: (URI::Generic origin, Array[ipaddr]? addresses, options options) ?{ (self) -> void } -> void
15
+ # def initialize: (URI::Generic origin, Array[Resolver::Entry]? addresses, options options) ?{ (self) -> void } -> void
16
16
 
17
17
  def session_new_cb: { (OpenSSL::SSL::Session sess) -> void } -> void
18
18
  def can_verify_peer?: () -> bool
data/sig/io/tcp.rbs CHANGED
@@ -2,11 +2,11 @@ module HTTPX
2
2
  class TCP
3
3
  include Loggable
4
4
 
5
- attr_reader ip: ipaddr?
5
+ attr_reader ip: Resolver::Entry?
6
6
 
7
7
  attr_reader port: Integer
8
8
 
9
- attr_reader addresses: Array[ipaddr]
9
+ attr_reader addresses: Array[Resolver::Entry]
10
10
 
11
11
  attr_reader state: Symbol
12
12
 
@@ -14,18 +14,26 @@ module HTTPX
14
14
 
15
15
  alias host ip
16
16
 
17
+ @io: Socket
18
+
17
19
  @hostname: String
18
20
 
19
21
  @options: Options
20
22
 
21
23
  @fallback_protocol: String
22
24
 
25
+ @keep_open: bool
26
+
27
+ @ip_index: Integer
28
+
23
29
  # TODO: lift when https://github.com/ruby/rbs/issues/1497 fixed
24
- def initialize: (URI::Generic origin, Array[ipaddr]? addresses, Options options) ?{ (instance) -> void } -> void
30
+ def initialize: (URI::Generic origin, Array[Resolver::Entry]? addresses, Options options) ?{ (instance) -> void } -> void
25
31
 
26
- def add_addresses: (Array[ipaddr] addrs) -> void
32
+ def add_addresses: (Array[Resolver::Entry] addrs) -> void
27
33
 
28
- def to_io: () -> ::IO
34
+ def addresses?: () -> bool
35
+
36
+ def to_io: () -> IO
29
37
 
30
38
  def protocol: () -> String
31
39
 
@@ -46,8 +54,6 @@ module HTTPX
46
54
 
47
55
  def connected?: () -> bool
48
56
 
49
- def expired?: () -> boolish
50
-
51
57
  def closed?: () -> bool
52
58
 
53
59
  # :nocov: