httpx 0.22.5 → 0.23.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/doc/release_notes/0_23_0.md +42 -0
  3. data/lib/httpx/adapters/datadog.rb +1 -1
  4. data/lib/httpx/adapters/faraday.rb +1 -1
  5. data/lib/httpx/adapters/sentry.rb +4 -4
  6. data/lib/httpx/adapters/webmock.rb +2 -2
  7. data/lib/httpx/buffer.rb +4 -0
  8. data/lib/httpx/chainable.rb +4 -4
  9. data/lib/httpx/connection/http1.rb +2 -2
  10. data/lib/httpx/connection/http2.rb +2 -3
  11. data/lib/httpx/connection.rb +29 -10
  12. data/lib/httpx/io/udp.rb +2 -0
  13. data/lib/httpx/io/unix.rb +1 -5
  14. data/lib/httpx/io.rb +0 -10
  15. data/lib/httpx/options.rb +16 -2
  16. data/lib/httpx/plugins/authentication/digest.rb +1 -1
  17. data/lib/httpx/plugins/aws_sdk_authentication.rb +1 -3
  18. data/lib/httpx/plugins/aws_sigv4.rb +1 -1
  19. data/lib/httpx/plugins/compression/brotli.rb +4 -4
  20. data/lib/httpx/plugins/compression/deflate.rb +12 -7
  21. data/lib/httpx/plugins/compression/gzip.rb +7 -5
  22. data/lib/httpx/plugins/compression.rb +9 -8
  23. data/lib/httpx/plugins/digest_authentication.rb +1 -4
  24. data/lib/httpx/plugins/follow_redirects.rb +1 -1
  25. data/lib/httpx/plugins/grpc/message.rb +3 -1
  26. data/lib/httpx/plugins/grpc.rb +3 -3
  27. data/lib/httpx/plugins/h2c.rb +5 -9
  28. data/lib/httpx/plugins/internal_telemetry.rb +16 -0
  29. data/lib/httpx/plugins/multipart.rb +14 -2
  30. data/lib/httpx/plugins/proxy/http.rb +4 -4
  31. data/lib/httpx/plugins/proxy.rb +65 -31
  32. data/lib/httpx/plugins/response_cache.rb +2 -2
  33. data/lib/httpx/plugins/retries.rb +49 -2
  34. data/lib/httpx/plugins/upgrade/h2.rb +3 -3
  35. data/lib/httpx/plugins/upgrade.rb +4 -7
  36. data/lib/httpx/plugins/webdav.rb +7 -7
  37. data/lib/httpx/pool.rb +1 -1
  38. data/lib/httpx/request.rb +23 -13
  39. data/lib/httpx/resolver/https.rb +37 -20
  40. data/lib/httpx/resolver/native.rb +128 -36
  41. data/lib/httpx/resolver.rb +26 -14
  42. data/lib/httpx/response.rb +14 -16
  43. data/lib/httpx/session.rb +1 -0
  44. data/lib/httpx/transcoder/body.rb +0 -1
  45. data/lib/httpx/transcoder/chunker.rb +0 -1
  46. data/lib/httpx/transcoder/form.rb +0 -1
  47. data/lib/httpx/transcoder/json.rb +0 -1
  48. data/lib/httpx/transcoder/xml.rb +0 -1
  49. data/lib/httpx/transcoder.rb +0 -2
  50. data/lib/httpx/version.rb +1 -1
  51. data/lib/httpx.rb +0 -1
  52. data/sig/buffer.rbs +1 -0
  53. data/sig/chainable.rbs +3 -3
  54. data/sig/connection.rbs +17 -6
  55. data/sig/errors.rbs +9 -0
  56. data/sig/httpx.rbs +3 -3
  57. data/sig/io/ssl.rbs +17 -0
  58. data/sig/io/tcp.rbs +57 -0
  59. data/sig/io/udp.rbs +20 -0
  60. data/sig/io/unix.rbs +10 -0
  61. data/sig/options.rbs +5 -1
  62. data/sig/plugins/compression.rbs +6 -2
  63. data/sig/plugins/cookies/jar.rbs +2 -2
  64. data/sig/plugins/grpc.rbs +3 -3
  65. data/sig/plugins/h2c.rbs +1 -1
  66. data/sig/plugins/proxy.rbs +1 -5
  67. data/sig/plugins/response_cache.rbs +1 -1
  68. data/sig/plugins/retries.rbs +28 -8
  69. data/sig/plugins/upgrade.rbs +5 -3
  70. data/sig/request.rbs +6 -2
  71. data/sig/resolver/https.rbs +3 -1
  72. data/sig/resolver/native.rbs +7 -2
  73. data/sig/resolver/resolver.rbs +0 -2
  74. data/sig/resolver/system.rbs +2 -0
  75. data/sig/resolver.rbs +8 -4
  76. data/sig/response.rbs +6 -2
  77. data/sig/session.rbs +10 -10
  78. data/sig/transcoder/xml.rbs +1 -1
  79. data/sig/transcoder.rbs +4 -5
  80. metadata +9 -5
  81. data/lib/httpx/registry.rb +0 -85
  82. 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,63 @@ 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
239
+ code, result = Resolver.decode_dns_answer(buffer)
240
+
241
+ case code
242
+ when :ok
243
+ parse_addresses(result)
244
+ when :no_domain_found
245
+ # Indicates no such domain was found.
195
246
  hostname, connection = @queries.first
196
- @queries.delete(hostname)
197
- @timeouts.delete(hostname)
247
+ reset_hostname(hostname)
248
+
198
249
  @connections.delete(connection)
199
- ex = NativeResolveError.new(connection, connection.origin.host, e.message)
250
+ raise NativeResolveError.new(connection, connection.origin.host, "name or service not known (#{hostname})")
251
+ when :message_truncated
252
+ # TODO: what to do if it's already tcp??
253
+ return if @socket_type == :tcp
254
+
255
+ @socket_type = :tcp
256
+
257
+ hostname, _ = @queries.first
258
+ reset_hostname(hostname)
259
+ transition(:closed)
260
+ when :dns_error
261
+ hostname, connection = @queries.first
262
+ reset_hostname(hostname)
263
+ @connections.delete(connection)
264
+ ex = NativeResolveError.new(connection, connection.origin.host, "unknown DNS error (error code #{result})")
200
265
  ex.set_backtrace(e.backtrace)
201
266
  raise ex
202
- end
203
-
204
- if addresses.nil?
205
- # Indicates no such domain was found.
267
+ when :decode_error
206
268
  hostname, connection = @queries.first
207
- @queries.delete(hostname)
208
- @timeouts.delete(hostname)
269
+ reset_hostname(hostname)
270
+ @connections.delete(connection)
271
+ ex = NativeResolveError.new(connection, connection.origin.host, result.message)
272
+ ex.set_backtrace(result.backtrace)
273
+ raise ex
274
+ end
275
+ end
209
276
 
210
- unless @queries.value?(connection)
211
- @connections.delete(connection)
212
- raise NativeResolveError.new(connection, connection.origin.host)
213
- end
214
- elsif addresses.empty?
277
+ def parse_addresses(addresses)
278
+ if addresses.empty?
215
279
  # no address found, eliminate candidates
216
280
  _, 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) }
281
+ reset_hostname(hostname)
220
282
  @connections.delete(connection)
221
283
  raise NativeResolveError.new(connection, connection.origin.host)
222
284
  else
@@ -226,20 +288,21 @@ module HTTPX
226
288
  connection = @queries.delete(name)
227
289
 
228
290
  unless connection
291
+ orig_name = name
229
292
  # absolute name
230
293
  name_labels = Resolv::DNS::Name.create(name).to_a
231
- name = @queries.keys.first { |hname| name_labels == Resolv::DNS::Name.create(hname).to_a }
294
+ name = @queries.each_key.first { |hname| name_labels == Resolv::DNS::Name.create(hname).to_a }
232
295
 
233
296
  # probably a retried query for which there's an answer
234
- return unless name
297
+ unless name
298
+ @timeouts.delete(orig_name)
299
+ return
300
+ end
235
301
 
236
302
  address["name"] = name
237
303
  connection = @queries.delete(name)
238
304
  end
239
305
 
240
- # eliminate other candidates
241
- @queries.delete_if { |_, conn| connection == conn }
242
-
243
306
  if address.key?("alias") # CNAME
244
307
  # clean up intermediate queries
245
308
  @timeouts.delete(name) unless connection.origin.host == name
@@ -265,6 +328,7 @@ module HTTPX
265
328
 
266
329
  def resolve(connection = @connections.first, hostname = nil)
267
330
  raise Error, "no URI to resolve" unless connection
331
+
268
332
  return unless @write_buffer.empty?
269
333
 
270
334
  hostname ||= @queries.key(connection)
@@ -281,12 +345,19 @@ module HTTPX
281
345
  end
282
346
  log { "resolver: query #{@record_type.name.split("::").last} for #{hostname}" }
283
347
  begin
284
- @write_buffer << Resolver.encode_dns_query(hostname, type: @record_type)
348
+ @write_buffer << encode_dns_query(hostname)
285
349
  rescue Resolv::DNS::EncodeError => e
286
350
  emit_resolve_error(connection, hostname, e)
287
351
  end
288
352
  end
289
353
 
354
+ def encode_dns_query(hostname)
355
+ message_id = Resolver.generate_id
356
+ msg = Resolver.encode_dns_query(hostname, type: @record_type, message_id: message_id)
357
+ msg[0, 2] = [msg.size, message_id].pack("nn") if @socket_type == :tcp
358
+ msg
359
+ end
360
+
290
361
  def generate_candidates(name)
291
362
  return [name] if name.end_with?(".")
292
363
 
@@ -294,18 +365,25 @@ module HTTPX
294
365
  name_parts = name.scan(/[^.]+/)
295
366
  candidates = [name] if @ndots <= name_parts.size - 1
296
367
  candidates.concat(@search.map { |domain| [*name_parts, *domain].join(".") })
297
- candidates << name unless candidates.include?(name)
368
+ fname = "#{name}."
369
+ candidates << fname unless candidates.include?(fname)
298
370
 
299
371
  candidates
300
372
  end
301
373
 
302
374
  def build_socket
303
- return if @io
304
-
305
375
  ip, port = @nameserver[@ns_index]
306
376
  port ||= DNS_PORT
307
- log { "resolver: server: #{ip}:#{port}..." }
308
- @io = UDP.new(ip, port, @options)
377
+
378
+ case @socket_type
379
+ when :udp
380
+ log { "resolver: server: udp://#{ip}:#{port}..." }
381
+ UDP.new(ip, port, @options)
382
+ when :tcp
383
+ log { "resolver: server: tcp://#{ip}:#{port}..." }
384
+ origin = URI("tcp://#{ip}:#{port}")
385
+ TCP.new(origin, [ip], @options)
386
+ end
309
387
  end
310
388
 
311
389
  def transition(nextstate)
@@ -319,7 +397,7 @@ module HTTPX
319
397
  when :open
320
398
  return unless @state == :idle
321
399
 
322
- build_socket
400
+ @io ||= build_socket
323
401
 
324
402
  @io.connect
325
403
  return unless @io.connected?
@@ -346,5 +424,19 @@ module HTTPX
346
424
  end
347
425
  end
348
426
  end
427
+
428
+ def reset_hostname(hostname, reset_candidates: true)
429
+ @timeouts.delete(hostname)
430
+ connection = @queries.delete(hostname)
431
+ @timeouts.delete(hostname)
432
+
433
+ return unless connection && reset_candidates
434
+
435
+ # eliminate other candidates
436
+ candidates = @queries.select { |_, conn| connection == conn }.keys
437
+ @queries.delete_if { |h, _| candidates.include?(h) }
438
+ # reset timeouts
439
+ @timeouts.delete_if { |h, _| candidates.include?(h) }
440
+ end
349
441
  end
350
442
  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.0"
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