httpx 0.22.5 → 0.23.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 (83) hide show
  1. checksums.yaml +4 -4
  2. data/doc/release_notes/0_23_0.md +42 -0
  3. data/doc/release_notes/0_23_1.md +5 -0
  4. data/lib/httpx/adapters/datadog.rb +1 -1
  5. data/lib/httpx/adapters/faraday.rb +1 -1
  6. data/lib/httpx/adapters/sentry.rb +4 -4
  7. data/lib/httpx/adapters/webmock.rb +2 -2
  8. data/lib/httpx/buffer.rb +4 -0
  9. data/lib/httpx/chainable.rb +4 -4
  10. data/lib/httpx/connection/http1.rb +2 -2
  11. data/lib/httpx/connection/http2.rb +2 -3
  12. data/lib/httpx/connection.rb +29 -10
  13. data/lib/httpx/io/udp.rb +2 -0
  14. data/lib/httpx/io/unix.rb +1 -5
  15. data/lib/httpx/io.rb +0 -10
  16. data/lib/httpx/options.rb +16 -2
  17. data/lib/httpx/plugins/authentication/digest.rb +1 -1
  18. data/lib/httpx/plugins/aws_sdk_authentication.rb +1 -3
  19. data/lib/httpx/plugins/aws_sigv4.rb +1 -1
  20. data/lib/httpx/plugins/compression/brotli.rb +4 -4
  21. data/lib/httpx/plugins/compression/deflate.rb +12 -7
  22. data/lib/httpx/plugins/compression/gzip.rb +7 -5
  23. data/lib/httpx/plugins/compression.rb +9 -8
  24. data/lib/httpx/plugins/digest_authentication.rb +1 -4
  25. data/lib/httpx/plugins/follow_redirects.rb +1 -1
  26. data/lib/httpx/plugins/grpc/message.rb +3 -1
  27. data/lib/httpx/plugins/grpc.rb +3 -3
  28. data/lib/httpx/plugins/h2c.rb +5 -9
  29. data/lib/httpx/plugins/internal_telemetry.rb +16 -0
  30. data/lib/httpx/plugins/multipart.rb +14 -2
  31. data/lib/httpx/plugins/proxy/http.rb +4 -4
  32. data/lib/httpx/plugins/proxy.rb +65 -31
  33. data/lib/httpx/plugins/response_cache.rb +2 -2
  34. data/lib/httpx/plugins/retries.rb +49 -2
  35. data/lib/httpx/plugins/upgrade/h2.rb +3 -3
  36. data/lib/httpx/plugins/upgrade.rb +4 -7
  37. data/lib/httpx/plugins/webdav.rb +7 -7
  38. data/lib/httpx/pool.rb +1 -1
  39. data/lib/httpx/request.rb +23 -13
  40. data/lib/httpx/resolver/https.rb +37 -20
  41. data/lib/httpx/resolver/native.rb +131 -35
  42. data/lib/httpx/resolver.rb +26 -14
  43. data/lib/httpx/response.rb +14 -16
  44. data/lib/httpx/session.rb +1 -0
  45. data/lib/httpx/transcoder/body.rb +0 -1
  46. data/lib/httpx/transcoder/chunker.rb +0 -1
  47. data/lib/httpx/transcoder/form.rb +0 -1
  48. data/lib/httpx/transcoder/json.rb +0 -1
  49. data/lib/httpx/transcoder/xml.rb +0 -1
  50. data/lib/httpx/transcoder.rb +0 -2
  51. data/lib/httpx/version.rb +1 -1
  52. data/lib/httpx.rb +0 -1
  53. data/sig/buffer.rbs +1 -0
  54. data/sig/chainable.rbs +3 -3
  55. data/sig/connection.rbs +17 -6
  56. data/sig/errors.rbs +9 -0
  57. data/sig/httpx.rbs +3 -3
  58. data/sig/io/ssl.rbs +17 -0
  59. data/sig/io/tcp.rbs +57 -0
  60. data/sig/io/udp.rbs +20 -0
  61. data/sig/io/unix.rbs +10 -0
  62. data/sig/options.rbs +5 -1
  63. data/sig/plugins/compression.rbs +6 -2
  64. data/sig/plugins/cookies/jar.rbs +2 -2
  65. data/sig/plugins/grpc.rbs +3 -3
  66. data/sig/plugins/h2c.rbs +1 -1
  67. data/sig/plugins/proxy.rbs +1 -5
  68. data/sig/plugins/response_cache.rbs +1 -1
  69. data/sig/plugins/retries.rbs +28 -8
  70. data/sig/plugins/upgrade.rbs +5 -3
  71. data/sig/request.rbs +6 -2
  72. data/sig/resolver/https.rbs +3 -1
  73. data/sig/resolver/native.rbs +7 -2
  74. data/sig/resolver/resolver.rbs +0 -2
  75. data/sig/resolver/system.rbs +2 -0
  76. data/sig/resolver.rbs +8 -4
  77. data/sig/response.rbs +6 -2
  78. data/sig/session.rbs +10 -10
  79. data/sig/transcoder/xml.rbs +1 -1
  80. data/sig/transcoder.rbs +4 -5
  81. metadata +11 -5
  82. data/lib/httpx/registry.rb +0 -85
  83. data/sig/registry.rbs +0 -13
@@ -33,6 +33,7 @@ module HTTPX
33
33
  super
34
34
  @ns_index = 0
35
35
  @resolver_options = DEFAULTS.merge(@options.resolver_options)
36
+ @socket_type = @resolver_options.fetch(:socket_type, :udp)
36
37
  @nameserver = Array(@resolver_options[:nameserver]) if @resolver_options[:nameserver]
37
38
  @ndots = @resolver_options[:ndots]
38
39
  @search = Array(@resolver_options[:search]).map { |srch| srch.scan(/[^.]+/) }
@@ -156,7 +157,7 @@ module HTTPX
156
157
  else
157
158
 
158
159
  @timeouts.delete(host)
159
- @queries.delete(h)
160
+ reset_hostname(h, reset_candidates: false)
160
161
 
161
162
  return unless @queries.empty?
162
163
 
@@ -169,10 +170,49 @@ module HTTPX
169
170
 
170
171
  def dread(wsize = @resolver_options[:packet_size])
171
172
  loop do
173
+ wsize = @large_packet.capacity if @large_packet
174
+
172
175
  siz = @io.read(wsize, @read_buffer)
173
- return unless siz && siz.positive?
174
176
 
175
- parse(@read_buffer)
177
+ unless siz
178
+ ex = EOFError.new("descriptor closed")
179
+ ex.set_backtrace(caller)
180
+ raise ex
181
+ end
182
+
183
+ return unless siz.positive?
184
+
185
+ if @socket_type == :tcp
186
+ # packet may be incomplete, need to keep draining from the socket
187
+ if @large_packet
188
+ # large packet buffer already exists, continue pumping
189
+ @large_packet << @read_buffer
190
+
191
+ next unless @large_packet.full?
192
+
193
+ parse(@large_packet.to_s)
194
+
195
+ @socket_type = @resolver_options.fetch(:socket_type, :udp)
196
+ @large_packet = nil
197
+ transition(:closed)
198
+ return
199
+ else
200
+ size = @read_buffer[0, 2].unpack1("n")
201
+
202
+ if size > @read_buffer.bytesize
203
+ # only do buffer logic if it's worth it, and the whole packet isn't here already
204
+ @large_packet = Buffer.new(size)
205
+ @large_packet << @read_buffer.byteslice(2..-1)
206
+
207
+ next
208
+ else
209
+ parse(@read_buffer)
210
+ end
211
+ end
212
+ else # udp
213
+ parse(@read_buffer)
214
+ end
215
+
176
216
  return if @state == :closed
177
217
  end
178
218
  end
@@ -182,41 +222,67 @@ module HTTPX
182
222
  return if @write_buffer.empty?
183
223
 
184
224
  siz = @io.write(@write_buffer)
185
- return unless siz && siz.positive?
225
+
226
+ unless siz
227
+ ex = EOFError.new("descriptor closed")
228
+ ex.set_backtrace(caller)
229
+ raise ex
230
+ end
231
+
232
+ return unless siz.positive?
186
233
 
187
234
  return if @state == :closed
188
235
  end
189
236
  end
190
237
 
191
238
  def parse(buffer)
192
- begin
193
- addresses = Resolver.decode_dns_answer(buffer)
194
- rescue Resolv::DNS::DecodeError => e
195
- hostname, connection = @queries.first
196
- @queries.delete(hostname)
197
- @timeouts.delete(hostname)
198
- @connections.delete(connection)
199
- ex = NativeResolveError.new(connection, connection.origin.host, e.message)
200
- ex.set_backtrace(e.backtrace)
201
- raise ex
202
- end
239
+ code, result = Resolver.decode_dns_answer(buffer)
203
240
 
204
- if addresses.nil?
241
+ case code
242
+ when :ok
243
+ parse_addresses(result)
244
+ when :no_domain_found
205
245
  # Indicates no such domain was found.
206
246
  hostname, connection = @queries.first
207
- @queries.delete(hostname)
208
- @timeouts.delete(hostname)
247
+ reset_hostname(hostname, reset_candidates: false)
209
248
 
210
249
  unless @queries.value?(connection)
211
250
  @connections.delete(connection)
212
- raise NativeResolveError.new(connection, connection.origin.host)
251
+ raise NativeResolveError.new(connection, connection.origin.host, "name or service not known")
213
252
  end
214
- elsif addresses.empty?
253
+
254
+ resolve
255
+ when :message_truncated
256
+ # TODO: what to do if it's already tcp??
257
+ return if @socket_type == :tcp
258
+
259
+ @socket_type = :tcp
260
+
261
+ hostname, _ = @queries.first
262
+ reset_hostname(hostname)
263
+ transition(:closed)
264
+ when :dns_error
265
+ hostname, connection = @queries.first
266
+ reset_hostname(hostname)
267
+ @connections.delete(connection)
268
+ ex = NativeResolveError.new(connection, connection.origin.host, "unknown DNS error (error code #{result})")
269
+ ex.set_backtrace(e.backtrace)
270
+ raise ex
271
+ when :decode_error
272
+ hostname, connection = @queries.first
273
+ reset_hostname(hostname)
274
+ @connections.delete(connection)
275
+ ex = NativeResolveError.new(connection, connection.origin.host, result.message)
276
+ ex.set_backtrace(result.backtrace)
277
+ raise ex
278
+ end
279
+ end
280
+
281
+ def parse_addresses(addresses)
282
+ if addresses.empty?
215
283
  # no address found, eliminate candidates
216
284
  _, connection = @queries.first
217
- candidates = @queries.select { |_, conn| connection == conn }.keys
218
- @queries.delete_if { |hs, _| candidates.include?(hs) }
219
- @timeouts.delete_if { |hs, _| candidates.include?(hs) }
285
+ reset_hostname(hostname)
220
286
  @connections.delete(connection)
221
287
  raise NativeResolveError.new(connection, connection.origin.host)
222
288
  else
@@ -226,20 +292,21 @@ module HTTPX
226
292
  connection = @queries.delete(name)
227
293
 
228
294
  unless connection
295
+ orig_name = name
229
296
  # absolute name
230
297
  name_labels = Resolv::DNS::Name.create(name).to_a
231
- name = @queries.keys.first { |hname| name_labels == Resolv::DNS::Name.create(hname).to_a }
298
+ name = @queries.each_key.first { |hname| name_labels == Resolv::DNS::Name.create(hname).to_a }
232
299
 
233
300
  # probably a retried query for which there's an answer
234
- return unless name
301
+ unless name
302
+ @timeouts.delete(orig_name)
303
+ return
304
+ end
235
305
 
236
306
  address["name"] = name
237
307
  connection = @queries.delete(name)
238
308
  end
239
309
 
240
- # eliminate other candidates
241
- @queries.delete_if { |_, conn| connection == conn }
242
-
243
310
  if address.key?("alias") # CNAME
244
311
  # clean up intermediate queries
245
312
  @timeouts.delete(name) unless connection.origin.host == name
@@ -265,6 +332,7 @@ module HTTPX
265
332
 
266
333
  def resolve(connection = @connections.first, hostname = nil)
267
334
  raise Error, "no URI to resolve" unless connection
335
+
268
336
  return unless @write_buffer.empty?
269
337
 
270
338
  hostname ||= @queries.key(connection)
@@ -281,12 +349,19 @@ module HTTPX
281
349
  end
282
350
  log { "resolver: query #{@record_type.name.split("::").last} for #{hostname}" }
283
351
  begin
284
- @write_buffer << Resolver.encode_dns_query(hostname, type: @record_type)
352
+ @write_buffer << encode_dns_query(hostname)
285
353
  rescue Resolv::DNS::EncodeError => e
286
354
  emit_resolve_error(connection, hostname, e)
287
355
  end
288
356
  end
289
357
 
358
+ def encode_dns_query(hostname)
359
+ message_id = Resolver.generate_id
360
+ msg = Resolver.encode_dns_query(hostname, type: @record_type, message_id: message_id)
361
+ msg[0, 2] = [msg.size, message_id].pack("nn") if @socket_type == :tcp
362
+ msg
363
+ end
364
+
290
365
  def generate_candidates(name)
291
366
  return [name] if name.end_with?(".")
292
367
 
@@ -294,18 +369,25 @@ module HTTPX
294
369
  name_parts = name.scan(/[^.]+/)
295
370
  candidates = [name] if @ndots <= name_parts.size - 1
296
371
  candidates.concat(@search.map { |domain| [*name_parts, *domain].join(".") })
297
- candidates << name unless candidates.include?(name)
372
+ fname = "#{name}."
373
+ candidates << fname unless candidates.include?(fname)
298
374
 
299
375
  candidates
300
376
  end
301
377
 
302
378
  def build_socket
303
- return if @io
304
-
305
379
  ip, port = @nameserver[@ns_index]
306
380
  port ||= DNS_PORT
307
- log { "resolver: server: #{ip}:#{port}..." }
308
- @io = UDP.new(ip, port, @options)
381
+
382
+ case @socket_type
383
+ when :udp
384
+ log { "resolver: server: udp://#{ip}:#{port}..." }
385
+ UDP.new(ip, port, @options)
386
+ when :tcp
387
+ log { "resolver: server: tcp://#{ip}:#{port}..." }
388
+ origin = URI("tcp://#{ip}:#{port}")
389
+ TCP.new(origin, [ip], @options)
390
+ end
309
391
  end
310
392
 
311
393
  def transition(nextstate)
@@ -319,7 +401,7 @@ module HTTPX
319
401
  when :open
320
402
  return unless @state == :idle
321
403
 
322
- build_socket
404
+ @io ||= build_socket
323
405
 
324
406
  @io.connect
325
407
  return unless @io.connected?
@@ -346,5 +428,19 @@ module HTTPX
346
428
  end
347
429
  end
348
430
  end
431
+
432
+ def reset_hostname(hostname, reset_candidates: true)
433
+ @timeouts.delete(hostname)
434
+ connection = @queries.delete(hostname)
435
+ @timeouts.delete(hostname)
436
+
437
+ return unless connection && reset_candidates
438
+
439
+ # eliminate other candidates
440
+ candidates = @queries.select { |_, conn| connection == conn }.keys
441
+ @queries.delete_if { |h, _| candidates.include?(h) }
442
+ # reset timeouts
443
+ @timeouts.delete_if { |h, _| candidates.include?(h) }
444
+ end
349
445
  end
350
446
  end
@@ -5,8 +5,6 @@ require "ipaddr"
5
5
 
6
6
  module HTTPX
7
7
  module Resolver
8
- extend Registry
9
-
10
8
  RESOLVE_TIMEOUT = 5
11
9
 
12
10
  require "httpx/resolver/resolver"
@@ -15,10 +13,6 @@ module HTTPX
15
13
  require "httpx/resolver/https"
16
14
  require "httpx/resolver/multi"
17
15
 
18
- register :system, System
19
- register :native, Native
20
- register :https, HTTPS
21
-
22
16
  @lookup_mutex = Mutex.new
23
17
  @lookups = Hash.new { |h, k| h[k] = [] }
24
18
 
@@ -28,6 +22,18 @@ module HTTPX
28
22
 
29
23
  module_function
30
24
 
25
+ def resolver_for(resolver_type)
26
+ case resolver_type
27
+ when :native then Native
28
+ when :system then System
29
+ when :https then HTTPS
30
+ else
31
+ return resolver_type if resolver_type.is_a?(Class) && resolver_type < Resolver
32
+
33
+ raise Error, "unsupported resolver type (#{resolver_type})"
34
+ end
35
+ end
36
+
31
37
  def nolookup_resolve(hostname)
32
38
  ip_resolve(hostname) || cached_lookup(hostname) || system_resolve(hostname)
33
39
  end
@@ -98,24 +104,29 @@ module HTTPX
98
104
  @identifier_mutex.synchronize { @identifier = (@identifier + 1) & 0xFFFF }
99
105
  end
100
106
 
101
- def encode_dns_query(hostname, type: Resolv::DNS::Resource::IN::A)
107
+ def encode_dns_query(hostname, type: Resolv::DNS::Resource::IN::A, message_id: generate_id)
102
108
  Resolv::DNS::Message.new.tap do |query|
103
- query.id = generate_id
109
+ query.id = message_id
104
110
  query.rd = 1
105
111
  query.add_question(hostname, type)
106
112
  end.encode
107
113
  end
108
114
 
109
115
  def decode_dns_answer(payload)
110
- message = Resolv::DNS::Message.decode(payload)
116
+ begin
117
+ message = Resolv::DNS::Message.decode(payload)
118
+ rescue Resolv::DNS::DecodeError => e
119
+ return :decode_error, e
120
+ end
111
121
 
112
122
  # no domain was found
113
- return if message.rcode == Resolv::DNS::RCode::NXDomain
123
+ return :no_domain_found if message.rcode == Resolv::DNS::RCode::NXDomain
114
124
 
115
- addresses = []
125
+ return :message_truncated if message.tc == 1
116
126
 
117
- # TODO: raise an "other dns OtherResolvError" type of error
118
- return addresses if message.rcode != Resolv::DNS::RCode::NoError
127
+ return :dns_error, message.rcode if message.rcode != Resolv::DNS::RCode::NoError
128
+
129
+ addresses = []
119
130
 
120
131
  message.each_answer do |question, _, value|
121
132
  case value
@@ -134,7 +145,8 @@ module HTTPX
134
145
  }
135
146
  end
136
147
  end
137
- addresses
148
+
149
+ [:ok, addresses]
138
150
  end
139
151
  end
140
152
  end
@@ -56,12 +56,12 @@ module HTTPX
56
56
  end
57
57
 
58
58
  def bodyless?
59
- @request.verb == :head ||
59
+ @request.verb == "HEAD" ||
60
60
  no_data?
61
61
  end
62
62
 
63
63
  def complete?
64
- bodyless? || (@request.verb == :connect && @status == 200)
64
+ bodyless? || (@request.verb == "CONNECT" && @status == 200)
65
65
  end
66
66
 
67
67
  # :nocov:
@@ -87,32 +87,27 @@ module HTTPX
87
87
  end
88
88
 
89
89
  def json(*args)
90
- decode("json", *args)
90
+ decode(Transcoder::JSON, *args)
91
91
  end
92
92
 
93
93
  def form
94
- decode("form")
94
+ decode(Transcoder::Form)
95
95
  end
96
96
 
97
97
  def xml
98
- decode("xml")
98
+ decode(Transcoder::Xml)
99
99
  end
100
100
 
101
101
  private
102
102
 
103
- def decode(format, *args)
103
+ def decode(transcoder, *args)
104
104
  # TODO: check if content-type is a valid format, i.e. "application/json" for json parsing
105
- transcoder = Transcoder.registry(format)
106
-
107
- raise Error, "no decoder available for \"#{format}\"" unless transcoder.respond_to?(:decode)
108
105
 
109
106
  decoder = transcoder.decode(self)
110
107
 
111
- raise Error, "no decoder available for \"#{format}\"" unless decoder
108
+ raise Error, "no decoder available for \"#{transcoder}\"" unless decoder
112
109
 
113
110
  decoder.call(self, *args)
114
- rescue Registry::Error
115
- raise Error, "no decoder available for \"#{format}\""
116
111
  end
117
112
 
118
113
  def no_data?
@@ -203,10 +198,8 @@ module HTTPX
203
198
  rescue ArgumentError # ex: unknown encoding name - utf
204
199
  content
205
200
  end
206
- when nil
207
- "".b
208
201
  else
209
- @buffer
202
+ "".b
210
203
  end
211
204
  end
212
205
  alias_method :to_str, :to_s
@@ -334,12 +327,13 @@ module HTTPX
334
327
  include Loggable
335
328
  extend Forwardable
336
329
 
337
- attr_reader :request, :error
330
+ attr_reader :request, :response, :error
338
331
 
339
332
  def_delegator :@request, :uri
340
333
 
341
334
  def initialize(request, error, options)
342
335
  @request = request
336
+ @response = request.response if request.response.is_a?(Response)
343
337
  @error = error
344
338
  @options = Options.new(options)
345
339
  log_exception(@error)
@@ -361,6 +355,10 @@ module HTTPX
361
355
  end
362
356
  end
363
357
 
358
+ def close
359
+ @response.close if @response.respond_to?(:close)
360
+ end
361
+
364
362
  def finished?
365
363
  true
366
364
  end
data/lib/httpx/session.rb CHANGED
@@ -203,6 +203,7 @@ module HTTPX
203
203
  end
204
204
 
205
205
  def receive_requests(requests, connections)
206
+ # @type var responses: Array[response]
206
207
  responses = []
207
208
 
208
209
  begin
@@ -55,5 +55,4 @@ module HTTPX::Transcoder
55
55
  Encoder.new(body)
56
56
  end
57
57
  end
58
- register "body", Body
59
58
  end
@@ -112,5 +112,4 @@ module HTTPX::Transcoder
112
112
  Encoder.new(chunks)
113
113
  end
114
114
  end
115
- register "chunker", Chunker
116
115
  end
@@ -55,5 +55,4 @@ module HTTPX::Transcoder
55
55
  Decoder
56
56
  end
57
57
  end
58
- register "form", Form
59
58
  end
@@ -56,5 +56,4 @@ module HTTPX::Transcoder
56
56
  end
57
57
  # rubocop:enable Style/SingleLineMethods
58
58
  end
59
- register "json", JSON
60
59
  end
@@ -51,5 +51,4 @@ module HTTPX::Transcoder
51
51
  end
52
52
  end
53
53
  end
54
- register "xml", Xml
55
54
  end
@@ -2,8 +2,6 @@
2
2
 
3
3
  module HTTPX
4
4
  module Transcoder
5
- extend Registry
6
-
7
5
  using RegexpExtensions unless Regexp.method_defined?(:match?)
8
6
 
9
7
  module_function
data/lib/httpx/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module HTTPX
4
- VERSION = "0.22.5"
4
+ VERSION = "0.23.1"
5
5
  end
data/lib/httpx.rb CHANGED
@@ -11,7 +11,6 @@ require "httpx/domain_name"
11
11
  require "httpx/altsvc"
12
12
  require "httpx/callbacks"
13
13
  require "httpx/loggable"
14
- require "httpx/registry"
15
14
  require "httpx/transcoder"
16
15
  require "httpx/timers"
17
16
  require "httpx/pool"
data/sig/buffer.rbs CHANGED
@@ -11,6 +11,7 @@ module HTTPX
11
11
 
12
12
  def full?: () -> bool
13
13
  def shift!: (Integer) -> void
14
+ def capacity: () -> Integer
14
15
 
15
16
  # delegated
16
17
  def <<: (string data) -> String
data/sig/chainable.rbs CHANGED
@@ -2,9 +2,9 @@ module HTTPX
2
2
  module Chainable
3
3
  def request: (*Request, **untyped) -> Array[response]
4
4
  | (Request, **untyped) -> response
5
- | (verb | string, uri | [uri], **untyped) -> response
6
- | (Array[[verb | string, uri] | [verb | string, uri, options]], **untyped) -> Array[response]
7
- | (verb | string, _Each[uri | [uri, options]], **untyped) -> Array[response]
5
+ | (verb, uri | [uri], **untyped) -> response
6
+ | (Array[[verb, uri] | [verb, uri, options]], **untyped) -> Array[response]
7
+ | (verb, _Each[uri | [uri, options]], **untyped) -> Array[response]
8
8
 
9
9
  def accept: (String) -> Session
10
10
  def wrap: () { (Session) -> void } -> void
data/sig/connection.rbs CHANGED
@@ -17,9 +17,7 @@ module HTTPX
17
17
  extend Forwardable
18
18
  include Loggable
19
19
  include Callbacks
20
- include HTTPX::Registry[String, Class]
21
20
 
22
- BUFFER_SIZE: Integer
23
21
 
24
22
  attr_reader type: io_type
25
23
  attr_reader origin: URI::Generic
@@ -36,7 +34,13 @@ module HTTPX
36
34
  @write_buffer: Buffer
37
35
  @inflight: Integer
38
36
  @keep_alive_timeout: Numeric?
37
+ @timeout: Numeric?
38
+ @current_timeout: Numeric?
39
39
  @total_timeout: Numeric?
40
+ @io: TCP | SSL | UNIX
41
+ @parser: HTTP1 | HTTP2 | _Parser
42
+ @connected_at: Float
43
+ @response_received_at: Float
40
44
 
41
45
  def addresses: () -> Array[ipaddr]?
42
46
 
@@ -77,6 +81,8 @@ module HTTPX
77
81
 
78
82
  def deactivate: () -> void
79
83
 
84
+ def open?: () -> bool
85
+
80
86
  def raise_timeout_error: (Numeric interval) -> void
81
87
 
82
88
  private
@@ -91,17 +97,20 @@ module HTTPX
91
97
 
92
98
  def send_pending: () -> void
93
99
 
94
- def parser: () -> _Parser
100
+ def parser: () -> (HTTP1 | HTTP2 | _Parser)
95
101
 
96
102
  def send_request_to_parser: (Request request) -> void
97
103
 
98
- def build_parser: () -> _Parser
99
- | (String) -> _Parser
104
+ def build_parser: (?String protocol) -> (HTTP1 | HTTP2)
100
105
 
101
- def set_parser_callbacks: (_Parser) -> void
106
+ def set_parser_callbacks: (HTTP1 | HTTP2 parser) -> void
102
107
 
103
108
  def transition: (Symbol) -> void
104
109
 
110
+ def handle_transition: (Symbol) -> void
111
+
112
+ def build_socket: (?Array[ipaddr]? addrs) -> (TCP | SSL | UNIX)
113
+
105
114
  def on_error: (HTTPX::TimeoutError | Error | StandardError) -> void
106
115
 
107
116
  def handle_error: (StandardError) -> void
@@ -113,5 +122,7 @@ module HTTPX
113
122
  def write_timeout_callback: (Request request, Numeric write_timeout) -> void
114
123
 
115
124
  def read_timeout_callback: (Request request, Numeric read_timeout, ?singleton(RequestTimeoutError) error_type) -> void
125
+
126
+ def self.parser_type: (String protocol) -> (singleton(HTTP1) | singleton(HTTP2))
116
127
  end
117
128
  end
data/sig/errors.rbs CHANGED
@@ -2,6 +2,12 @@ module HTTPX
2
2
  class Error < StandardError
3
3
  end
4
4
 
5
+ class UnsupportedSchemeError < Error
6
+ end
7
+
8
+ class ConnectionError < Error
9
+ end
10
+
5
11
  class TimeoutError < Error
6
12
  attr_reader timeout: Numeric
7
13
 
@@ -55,4 +61,7 @@ module HTTPX
55
61
 
56
62
  def initialize: (Connection connection, String hostname, ?String message) -> untyped
57
63
  end
64
+
65
+ class MisdirectedRequestError < HTTPError
66
+ end
58
67
  end
data/sig/httpx.rbs CHANGED
@@ -8,9 +8,9 @@ module HTTPX
8
8
  type uri = URI::HTTP | URI::HTTPS | string
9
9
  type generic_uri = String | URI::Generic
10
10
 
11
- type verb = :options | :get | :head | :post | :put | :delete | :trace | :connect |
12
- :propfind | :proppatch | :mkcol | :copy | :move | :lock | :unlock | :orderpatch |
13
- :acl | :report | :patch | :search
11
+ type verb = "OPTIONS" | "GET" | "HEAD" | "POST" | "PUT" | "DELETE" | "TRACE" | "CONNECT" |
12
+ "PROPFIND" | "PROPPATCH" | "MKCOL" | "COPY" | "MOVE" | "LOCK" | "UNLOCK" | "ORDERPATCH" |
13
+ "ACL" | "REPORT" | "PATCH" | "SEARCH"
14
14
 
15
15
  type ip_family = Integer #Socket::AF_INET6 | Socket::AF_INET
16
16
 
data/sig/io/ssl.rbs ADDED
@@ -0,0 +1,17 @@
1
+ module HTTPX
2
+ IPRegex: Regexp
3
+
4
+ class TLSError < OpenSSL::SSL::SSLError
5
+ end
6
+
7
+ class SSL < TCP
8
+ TLS_OPTIONS: Hash[Symbol, untyped]
9
+
10
+ def can_verify_peer?: () -> bool
11
+
12
+ def verify_hostname: (String host) -> bool
13
+
14
+ # :nocov:
15
+ def try_ssl_connect: () -> void
16
+ end
17
+ end