httpx 0.18.5 → 0.19.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 (63) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +5 -1
  3. data/doc/release_notes/0_18_5.md +2 -2
  4. data/doc/release_notes/0_18_6.md +5 -0
  5. data/doc/release_notes/0_18_7.md +5 -0
  6. data/doc/release_notes/0_19_0.md +39 -0
  7. data/doc/release_notes/0_19_1.md +5 -0
  8. data/lib/httpx/adapters/faraday.rb +7 -3
  9. data/lib/httpx/connection/http1.rb +5 -5
  10. data/lib/httpx/connection/http2.rb +1 -5
  11. data/lib/httpx/connection.rb +22 -10
  12. data/lib/httpx/extensions.rb +16 -0
  13. data/lib/httpx/headers.rb +0 -2
  14. data/lib/httpx/io/tcp.rb +27 -6
  15. data/lib/httpx/options.rb +44 -11
  16. data/lib/httpx/plugins/cookies.rb +5 -7
  17. data/lib/httpx/plugins/internal_telemetry.rb +1 -1
  18. data/lib/httpx/plugins/multipart/mime_type_detector.rb +7 -1
  19. data/lib/httpx/plugins/proxy/http.rb +10 -23
  20. data/lib/httpx/plugins/proxy/socks4.rb +1 -1
  21. data/lib/httpx/plugins/proxy/socks5.rb +1 -1
  22. data/lib/httpx/plugins/proxy.rb +20 -12
  23. data/lib/httpx/plugins/retries.rb +1 -1
  24. data/lib/httpx/pool.rb +40 -20
  25. data/lib/httpx/resolver/https.rb +32 -42
  26. data/lib/httpx/resolver/multi.rb +79 -0
  27. data/lib/httpx/resolver/native.rb +28 -36
  28. data/lib/httpx/resolver/resolver.rb +92 -0
  29. data/lib/httpx/resolver/system.rb +175 -19
  30. data/lib/httpx/resolver.rb +37 -11
  31. data/lib/httpx/response.rb +4 -2
  32. data/lib/httpx/session.rb +1 -15
  33. data/lib/httpx/session_extensions.rb +26 -0
  34. data/lib/httpx/timers.rb +1 -1
  35. data/lib/httpx/transcoder/chunker.rb +0 -1
  36. data/lib/httpx/version.rb +1 -1
  37. data/lib/httpx.rb +3 -0
  38. data/sig/connection/http1.rbs +0 -2
  39. data/sig/connection/http2.rbs +2 -2
  40. data/sig/connection.rbs +1 -0
  41. data/sig/errors.rbs +8 -0
  42. data/sig/headers.rbs +0 -2
  43. data/sig/httpx.rbs +4 -0
  44. data/sig/options.rbs +10 -7
  45. data/sig/parser/http1.rbs +14 -5
  46. data/sig/pool.rbs +17 -9
  47. data/sig/registry.rbs +3 -0
  48. data/sig/request.rbs +11 -0
  49. data/sig/resolver/https.rbs +15 -27
  50. data/sig/resolver/multi.rbs +7 -0
  51. data/sig/resolver/native.rbs +3 -12
  52. data/sig/resolver/resolver.rbs +36 -0
  53. data/sig/resolver/system.rbs +3 -9
  54. data/sig/resolver.rbs +12 -10
  55. data/sig/response.rbs +15 -5
  56. data/sig/selector.rbs +3 -3
  57. data/sig/timers.rbs +5 -2
  58. data/sig/transcoder/chunker.rbs +16 -5
  59. data/sig/transcoder/json.rbs +5 -0
  60. data/sig/transcoder.rbs +3 -1
  61. metadata +15 -4
  62. data/lib/httpx/resolver/resolver_mixin.rb +0 -75
  63. data/sig/resolver/resolver_mixin.rbs +0 -26
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "resolv"
4
+ require "ipaddr"
5
+
6
+ module HTTPX
7
+ class Resolver::Resolver
8
+ include Callbacks
9
+ include Loggable
10
+
11
+ RECORD_TYPES = {
12
+ Socket::AF_INET6 => Resolv::DNS::Resource::IN::AAAA,
13
+ Socket::AF_INET => Resolv::DNS::Resource::IN::A,
14
+ }.freeze
15
+
16
+ FAMILY_TYPES = {
17
+ Resolv::DNS::Resource::IN::AAAA => "AAAA",
18
+ Resolv::DNS::Resource::IN::A => "A",
19
+ }.freeze
20
+
21
+ class << self
22
+ def multi?
23
+ true
24
+ end
25
+ end
26
+
27
+ attr_reader :family
28
+
29
+ attr_writer :pool
30
+
31
+ def initialize(family, options)
32
+ @family = family
33
+ @record_type = RECORD_TYPES[family]
34
+ @options = Options.new(options)
35
+ end
36
+
37
+ def close; end
38
+
39
+ def closed?
40
+ true
41
+ end
42
+
43
+ def empty?
44
+ true
45
+ end
46
+
47
+ def emit_addresses(connection, family, addresses)
48
+ addresses.map! do |address|
49
+ address.is_a?(IPAddr) ? address : IPAddr.new(address.to_s)
50
+ end
51
+ log { "resolver: answer #{connection.origin.host}: #{addresses.inspect}" }
52
+ if !connection.io &&
53
+ connection.options.ip_families.size > 1 &&
54
+ family == Socket::AF_INET &&
55
+ addresses.first.to_s != connection.origin.host.to_s
56
+ log { "resolver: A response, applying resolution delay..." }
57
+ @pool.after(0.05) do
58
+ connection.addresses = addresses
59
+ emit(:resolve, connection)
60
+ end
61
+ else
62
+ connection.addresses = addresses
63
+ emit(:resolve, connection)
64
+ end
65
+ end
66
+
67
+ private
68
+
69
+ def early_resolve(connection, hostname: connection.origin.host)
70
+ addresses = @resolver_options[:cache] && (connection.addresses || HTTPX::Resolver.nolookup_resolve(hostname))
71
+
72
+ return unless addresses
73
+
74
+ addresses.select! { |addr| addr.family == @family }
75
+
76
+ emit_addresses(connection, @family, addresses)
77
+ end
78
+
79
+ def emit_resolve_error(connection, hostname = connection.origin.host, ex = nil)
80
+ emit(:error, connection, resolve_error(hostname, ex))
81
+ end
82
+
83
+ def resolve_error(hostname, ex = nil)
84
+ return ex if ex.is_a?(ResolveError)
85
+
86
+ message = ex ? ex.message : "Can't resolve #{hostname}"
87
+ error = ResolveError.new(message)
88
+ error.set_backtrace(ex ? ex.backtrace : caller)
89
+ error
90
+ end
91
+ end
92
+ end
@@ -4,48 +4,204 @@ require "forwardable"
4
4
  require "resolv"
5
5
 
6
6
  module HTTPX
7
- class Resolver::System
8
- include Resolver::ResolverMixin
7
+ class Resolver::System < Resolver::Resolver
8
+ using URIExtensions
9
+ extend Forwardable
9
10
 
10
11
  RESOLV_ERRORS = [Resolv::ResolvError,
11
12
  Resolv::DNS::Requester::RequestError,
12
13
  Resolv::DNS::EncodeError,
13
14
  Resolv::DNS::DecodeError].freeze
14
15
 
16
+ DONE = 1
17
+ ERROR = 2
18
+
19
+ class << self
20
+ def multi?
21
+ false
22
+ end
23
+ end
24
+
15
25
  attr_reader :state
16
26
 
27
+ def_delegator :@connections, :empty?
28
+
17
29
  def initialize(options)
18
- @options = Options.new(options)
30
+ super(nil, options)
19
31
  @resolver_options = @options.resolver_options
20
- @state = :idle
21
32
  resolv_options = @resolver_options.dup
22
- timeouts = resolv_options.delete(:timeouts)
33
+ timeouts = resolv_options.delete(:timeouts) || Resolver::RESOLVE_TIMEOUT
34
+ @_timeouts = Array(timeouts)
35
+ @timeouts = Hash.new { |tims, host| tims[host] = @_timeouts.dup }
23
36
  resolv_options.delete(:cache)
24
- @resolver = Resolv::DNS.new(resolv_options.empty? ? nil : resolv_options)
25
- @resolver.timeouts = timeouts || Resolver::RESOLVE_TIMEOUT
37
+ @connections = []
38
+ @queries = []
39
+ @ips = []
40
+ @pipe_mutex = Thread::Mutex.new
41
+ @state = :idle
42
+ end
43
+
44
+ def resolvers
45
+ return enum_for(__method__) unless block_given?
46
+
47
+ yield self
48
+ end
49
+
50
+ def connections
51
+ EMPTY
52
+ end
53
+
54
+ def close
55
+ transition(:closed)
26
56
  end
27
57
 
28
58
  def closed?
29
- true
59
+ @state == :closed
60
+ end
61
+
62
+ def to_io
63
+ @pipe_read.to_io
64
+ end
65
+
66
+ def call
67
+ case @state
68
+ when :open
69
+ consume
70
+ end
71
+ nil
30
72
  end
31
73
 
32
- def empty?
33
- true
74
+ def interests
75
+ return if @queries.empty?
76
+
77
+ :r
78
+ end
79
+
80
+ def timeout
81
+ return unless @queries.empty?
82
+
83
+ _, connection = @queries.first
84
+
85
+ @timeouts[connection.origin.host].first
34
86
  end
35
87
 
36
88
  def <<(connection)
89
+ @connections << connection
90
+ resolve
91
+ end
92
+
93
+ private
94
+
95
+ def transition(nextstate)
96
+ case nextstate
97
+ when :idle
98
+ @timeouts.clear
99
+ when :open
100
+ return unless @state == :idle
101
+
102
+ @pipe_read, @pipe_write = ::IO.pipe
103
+ when :closed
104
+ return unless @state == :open
105
+
106
+ @pipe_write.close
107
+ @pipe_read.close
108
+ end
109
+ @state = nextstate
110
+ end
111
+
112
+ def consume
113
+ return if @connections.empty?
114
+
115
+ while @pipe_read.ready? && (event = @pipe_read.getbyte)
116
+ case event
117
+ when DONE
118
+ *pair, addrs = @pipe_mutex.synchronize { @ips.pop }
119
+ @queries.delete(pair)
120
+
121
+ family, connection = pair
122
+ emit_addresses(connection, family, addrs)
123
+ when ERROR
124
+ *pair, error = @pipe_mutex.synchronize { @ips.pop }
125
+ @queries.delete(pair)
126
+
127
+ family, connection = pair
128
+ emit_resolve_error(connection, connection.origin.host, error)
129
+ end
130
+
131
+ @connections.delete(connection) if @queries.empty?
132
+ end
133
+
134
+ return emit(:close, self) if @connections.empty?
135
+
136
+ resolve
137
+ end
138
+
139
+ def resolve(connection = @connections.first)
140
+ raise Error, "no URI to resolve" unless connection
141
+ return unless @queries.empty?
142
+
37
143
  hostname = connection.origin.host
38
- addresses = connection.addresses ||
39
- ip_resolve(hostname) ||
40
- system_resolve(hostname) ||
41
- @resolver.getaddresses(hostname)
42
- throw(:resolve_error, resolve_error(hostname)) if addresses.empty?
144
+ scheme = connection.origin.scheme
145
+ log { "resolver: resolve IDN #{connection.origin.non_ascii_hostname} as #{hostname}" } if connection.origin.non_ascii_hostname
146
+
147
+ transition(:open)
43
148
 
44
- emit_addresses(connection, addresses)
45
- rescue Errno::EHOSTUNREACH, *RESOLV_ERRORS => e
46
- emit_resolve_error(connection, hostname, e)
149
+ connection.options.ip_families.each do |family|
150
+ @queries << [family, connection]
151
+ end
152
+ async_resolve(connection, hostname, scheme)
153
+ consume
47
154
  end
48
155
 
49
- def uncache(*); end
156
+ def async_resolve(connection, hostname, scheme)
157
+ families = connection.options.ip_families
158
+ log { "resolver: query for #{hostname}" }
159
+ resolve_timeout = @timeouts[connection.origin.host].first
160
+
161
+ Thread.start do
162
+ Thread.current.report_on_exception = false
163
+ begin
164
+ addrs = if resolve_timeout
165
+ Timeout.timeout(resolve_timeout) do
166
+ __addrinfo_resolve(hostname, scheme)
167
+ end
168
+ else
169
+ __addrinfo_resolve(hostname, scheme)
170
+ end
171
+ addrs = addrs.sort_by(&:afamily).group_by(&:afamily)
172
+ families.each do |family|
173
+ addresses = addrs[family]
174
+ next unless addresses
175
+
176
+ addresses.map!(&:ip_address)
177
+ addresses.uniq!
178
+ @pipe_mutex.synchronize do
179
+ @ips.unshift([family, connection, addresses])
180
+ @pipe_write.putc(DONE) unless @pipe_write.closed?
181
+ end
182
+ end
183
+ rescue Timeout::Error => e
184
+ ex = ResolveTimeoutError.new(resolve_timeout, e.message)
185
+ ex.set_backtrace(ex.backtrace)
186
+ @pipe_mutex.synchronize do
187
+ families.each do |family|
188
+ @ips.unshift([family, connection, ex])
189
+ @pipe_write.putc(ERROR) unless @pipe_write.closed?
190
+ end
191
+ end
192
+ rescue StandardError => e
193
+ @pipe_mutex.synchronize do
194
+ families.each do |family|
195
+ @ips.unshift([family, connection, e])
196
+ @pipe_write.putc(ERROR) unless @pipe_write.closed?
197
+ end
198
+ end
199
+ end
200
+ end
201
+ end
202
+
203
+ def __addrinfo_resolve(host, scheme)
204
+ Addrinfo.getaddrinfo(host, scheme, Socket::AF_UNSPEC, Socket::SOCK_STREAM)
205
+ end
50
206
  end
51
207
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "resolv"
4
+ require "ipaddr"
4
5
 
5
6
  module HTTPX
6
7
  module Resolver
@@ -8,10 +9,11 @@ module HTTPX
8
9
 
9
10
  RESOLVE_TIMEOUT = 5
10
11
 
11
- require "httpx/resolver/resolver_mixin"
12
+ require "httpx/resolver/resolver"
12
13
  require "httpx/resolver/system"
13
14
  require "httpx/resolver/native"
14
15
  require "httpx/resolver/https"
16
+ require "httpx/resolver/multi"
15
17
 
16
18
  register :system, System
17
19
  register :native, Native
@@ -22,9 +24,27 @@ module HTTPX
22
24
 
23
25
  @identifier_mutex = Mutex.new
24
26
  @identifier = 1
27
+ @system_resolver = Resolv::Hosts.new
25
28
 
26
29
  module_function
27
30
 
31
+ def nolookup_resolve(hostname)
32
+ ip_resolve(hostname) || cached_lookup(hostname) || system_resolve(hostname)
33
+ end
34
+
35
+ def ip_resolve(hostname)
36
+ [IPAddr.new(hostname)]
37
+ rescue ArgumentError
38
+ end
39
+
40
+ def system_resolve(hostname)
41
+ ips = @system_resolver.getaddresses(hostname)
42
+ return if ips.empty?
43
+
44
+ ips.map { |ip| IPAddr.new(ip) }
45
+ rescue IOError
46
+ end
47
+
28
48
  def cached_lookup(hostname)
29
49
  now = Utils.now
30
50
  @lookup_mutex.synchronize do
@@ -32,25 +52,31 @@ module HTTPX
32
52
  end
33
53
  end
34
54
 
35
- def cached_lookup_set(hostname, entries)
55
+ def cached_lookup_set(hostname, family, entries)
36
56
  now = Utils.now
37
57
  entries.each do |entry|
38
58
  entry["TTL"] += now
39
59
  end
40
60
  @lookup_mutex.synchronize do
41
- @lookups[hostname] += entries
61
+ case family
62
+ when Socket::AF_INET6
63
+ @lookups[hostname].concat(entries)
64
+ when Socket::AF_INET
65
+ @lookups[hostname].unshift(*entries)
66
+ end
42
67
  entries.each do |entry|
43
- @lookups[entry["name"]] << entry if entry["name"] != hostname
68
+ next unless entry["name"] != hostname
69
+
70
+ case family
71
+ when Socket::AF_INET6
72
+ @lookups[entry["name"]] << entry
73
+ when Socket::AF_INET
74
+ @lookups[entry["name"]].unshift(entry)
75
+ end
44
76
  end
45
77
  end
46
78
  end
47
79
 
48
- def uncache(hostname)
49
- @lookup_mutex.synchronize do
50
- @lookups.delete(hostname)
51
- end
52
- end
53
-
54
80
  # do not use directly!
55
81
  def lookup(hostname, ttl)
56
82
  return unless @lookups.key?(hostname)
@@ -62,7 +88,7 @@ module HTTPX
62
88
  if address.key?("alias")
63
89
  lookup(address["alias"], ttl)
64
90
  else
65
- address["data"]
91
+ IPAddr.new(address["data"])
66
92
  end
67
93
  end
68
94
  ips unless ips.empty?
@@ -173,7 +173,7 @@ module HTTPX
173
173
  rescue ArgumentError
174
174
  @buffer.string
175
175
  end
176
- when Tempfile, File
176
+ when Tempfile
177
177
  rewind
178
178
  content = _with_same_buffer_pos { @buffer.read }
179
179
  begin
@@ -253,6 +253,7 @@ module HTTPX
253
253
  @buffer = StringIO.new("".b)
254
254
  end
255
255
  when :memory
256
+ # @type ivar @buffer: StringIO | Tempfile
256
257
  if @length > @threshold_size
257
258
  aux = @buffer
258
259
  @buffer = Tempfile.new("httpx", encoding: Encoding::BINARY, mode: File::RDWR)
@@ -272,11 +273,12 @@ module HTTPX
272
273
  def _with_same_buffer_pos
273
274
  return yield unless @buffer && @buffer.respond_to?(:pos)
274
275
 
276
+ # @type ivar @buffer: StringIO | Tempfile
275
277
  current_pos = @buffer.pos
276
278
  @buffer.rewind
277
279
  begin
278
280
  yield
279
- rescue StandardError
281
+ ensure
280
282
  @buffer.pos = current_pos
281
283
  end
282
284
  end
data/lib/httpx/session.rb CHANGED
@@ -207,7 +207,7 @@ module HTTPX
207
207
 
208
208
  return responses unless request
209
209
 
210
- pool.next_tick until (response = fetch_response(request, connections, request.options))
210
+ catch(:coalesced) { pool.next_tick } until (response = fetch_response(request, connections, request.options))
211
211
 
212
212
  responses << response
213
213
  requests.shift
@@ -309,18 +309,4 @@ module HTTPX
309
309
  # :nocov:
310
310
  end
311
311
  end
312
-
313
- unless ENV.grep(/https?_proxy$/i).empty?
314
- proxy_session = plugin(:proxy)
315
- ::HTTPX.send(:remove_const, :Session)
316
- ::HTTPX.send(:const_set, :Session, proxy_session.class)
317
- end
318
-
319
- # :nocov:
320
- if Session.default_options.debug_level > 2
321
- proxy_session = plugin(:internal_telemetry)
322
- ::HTTPX.send(:remove_const, :Session)
323
- ::HTTPX.send(:const_set, :Session, proxy_session.class)
324
- end
325
- # :nocov:
326
312
  end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HTTPX
4
+ unless ENV.keys.grep(/\Ahttps?_proxy\z/i).empty?
5
+ proxy_session = plugin(:proxy)
6
+ remove_const(:Session)
7
+ const_set(:Session, proxy_session.class)
8
+
9
+ # redefine the default options static var, which needs to
10
+ # refresh options_class
11
+ options = proxy_session.class.default_options.to_hash
12
+ options.freeze
13
+ original_verbosity = $VERBOSE
14
+ $VERBOSE = nil
15
+ Options.send(:const_set, :DEFAULT_OPTIONS, options)
16
+ $VERBOSE = original_verbosity
17
+ end
18
+
19
+ # :nocov:
20
+ if Session.default_options.debug_level > 2
21
+ proxy_session = plugin(:internal_telemetry)
22
+ remove_const(:Session)
23
+ const_set(:Session, proxy_session.class)
24
+ end
25
+ # :nocov:
26
+ end
data/lib/httpx/timers.rb CHANGED
@@ -64,7 +64,7 @@ module HTTPX
64
64
  end
65
65
 
66
66
  def to_f
67
- @interval
67
+ Float(@interval)
68
68
  end
69
69
 
70
70
  def <<(callback)
@@ -40,7 +40,6 @@ module HTTPX::Transcoder
40
40
 
41
41
  def initialize(buffer, trailers = false)
42
42
  @buffer = buffer
43
- @chunk_length = nil
44
43
  @chunk_buffer = "".b
45
44
  @finished = false
46
45
  @state = :length
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.18.5"
4
+ VERSION = "0.19.1"
5
5
  end
data/lib/httpx.rb CHANGED
@@ -25,6 +25,8 @@ require "mutex_m"
25
25
  # Top-Level Namespace
26
26
  #
27
27
  module HTTPX
28
+ EMPTY = [].freeze
29
+
28
30
  # All plugins should be stored under this module/namespace. Can register and load
29
31
  # plugins.
30
32
  #
@@ -64,3 +66,4 @@ module HTTPX
64
66
  end
65
67
 
66
68
  require "httpx/session"
69
+ require "httpx/session_extensions"
@@ -67,8 +67,6 @@ module HTTPX
67
67
 
68
68
  def set_protocol_headers: (Request) -> _Each[[String, String]]
69
69
 
70
- def headline_uri: (Request) -> String
71
-
72
70
  def handle: (Request request) -> void
73
71
 
74
72
  def join_headers: (Request request) -> void
@@ -46,8 +46,6 @@ module HTTPX
46
46
 
47
47
  def send_pending: () -> void
48
48
 
49
- def headline_uri: (Request) -> String
50
-
51
49
  def set_protocol_headers: (Request) -> _Each[[String, String]]
52
50
 
53
51
  def handle: (Request request, HTTP2Next::Stream stream) -> void
@@ -56,6 +54,8 @@ module HTTPX
56
54
 
57
55
  def handle_stream: (HTTP2Next::Stream stream, Request request) -> void
58
56
 
57
+ def join_headline: (Request request) -> String
58
+
59
59
  def join_headers: (HTTP2Next::Stream stream, Request request) -> void
60
60
 
61
61
  def join_trailers: (HTTP2Next::Stream stream, Request request) -> void
data/sig/connection.rbs CHANGED
@@ -22,6 +22,7 @@ module HTTPX
22
22
  BUFFER_SIZE: Integer
23
23
 
24
24
  attr_reader origin: URI::Generic
25
+ attr_reader origins: Array[String]
25
26
  attr_reader state: Symbol
26
27
  attr_reader pending: Array[Request]
27
28
  attr_reader options: Options
data/sig/errors.rbs CHANGED
@@ -26,6 +26,14 @@ module HTTPX
26
26
  class ResolveError < Error
27
27
  end
28
28
 
29
+ class HTTPError < Error
30
+ attr_reader response: Response
31
+
32
+ private
33
+
34
+ def initialize: (Response response) -> void
35
+ end
36
+
29
37
  class NativeResolveError < ResolveError
30
38
  attr_reader connection: Connection
31
39
  attr_reader host: String
data/sig/headers.rbs CHANGED
@@ -2,8 +2,6 @@ module HTTPX
2
2
  class Headers
3
3
  include _ToS
4
4
 
5
- EMPTY: Array[untyped]
6
-
7
5
  @headers: Hash[String, Array[String]]
8
6
 
9
7
  def self.new: (?untyped headers) -> instance
data/sig/httpx.rbs CHANGED
@@ -1,6 +1,8 @@
1
1
  module HTTPX
2
2
  extend Chainable
3
3
 
4
+ EMPTY: Array[untyped]
5
+
4
6
  VERSION: String
5
7
 
6
8
  type uri = URI::HTTP | URI::HTTPS | string
@@ -10,6 +12,8 @@ module HTTPX
10
12
  :propfind | :proppatch | :mkcol | :copy | :move | :lock | :unlock | :orderpatch |
11
13
  :acl | :report | :patch | :search
12
14
 
15
+ type ip_family = Integer #Socket::AF_INET6 | Socket::AF_INET
16
+
13
17
  module Plugins
14
18
  def self?.load_plugin: (Symbol) -> Module
15
19
 
data/sig/options.rbs CHANGED
@@ -83,18 +83,16 @@ module HTTPX
83
83
 
84
84
  attr_reader response_body_class: singleton(Response::Body)
85
85
 
86
- attr_reader ssl: Hash[Symbol, untyped]
86
+ attr_reader resolver_class: Symbol | Class
87
87
 
88
- # request_class response_class headers_class request_body_class
89
- # response_body_class connection_class
90
- # resolver_class resolver_options
88
+ attr_reader ssl: Hash[Symbol, untyped]
91
89
 
92
90
  # io
93
91
  type io_option = _ToIO | Hash[String, _ToIO]
94
92
  attr_reader io: io_option?
95
93
 
96
94
  # fallback_protocol
97
- attr_reader fallback_protocol: String?
95
+ attr_reader fallback_protocol: String
98
96
 
99
97
  # debug
100
98
  attr_reader debug: _IOLogger?
@@ -103,10 +101,13 @@ module HTTPX
103
101
  attr_reader debug_level: Integer
104
102
 
105
103
  # persistent
106
- attr_reader persistent: bool?
104
+ attr_reader persistent: bool
107
105
 
108
106
  # resolver_options
109
- attr_reader resolver_options: Hash[Symbol, untyped]?
107
+ attr_reader resolver_options: Hash[Symbol, untyped]
108
+
109
+ # ip_families
110
+ attr_reader ip_families: Array[ip_family]
110
111
 
111
112
  def ==: (untyped other) -> bool
112
113
  def merge: (_ToHash[Symbol, untyped] other) -> instance
@@ -117,6 +118,8 @@ module HTTPX
117
118
  REQUEST_IVARS: Array[Symbol]
118
119
 
119
120
  def initialize: (?options options) -> untyped
121
+
122
+ def __initialize__: (?options options) -> untyped
120
123
  end
121
124
 
122
125
  type options = Options | Hash[Symbol, untyped]