httpx 0.21.0 → 0.22.4

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 (79) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +53 -35
  3. data/doc/release_notes/0_10_0.md +2 -2
  4. data/doc/release_notes/0_11_0.md +3 -5
  5. data/doc/release_notes/0_12_0.md +5 -5
  6. data/doc/release_notes/0_13_0.md +4 -4
  7. data/doc/release_notes/0_14_0.md +2 -2
  8. data/doc/release_notes/0_16_0.md +3 -3
  9. data/doc/release_notes/0_17_0.md +1 -1
  10. data/doc/release_notes/0_18_0.md +4 -4
  11. data/doc/release_notes/0_18_2.md +1 -1
  12. data/doc/release_notes/0_19_0.md +1 -1
  13. data/doc/release_notes/0_20_0.md +1 -1
  14. data/doc/release_notes/0_21_0.md +7 -5
  15. data/doc/release_notes/0_21_1.md +12 -0
  16. data/doc/release_notes/0_22_0.md +13 -0
  17. data/doc/release_notes/0_22_1.md +11 -0
  18. data/doc/release_notes/0_22_2.md +5 -0
  19. data/doc/release_notes/0_22_3.md +55 -0
  20. data/doc/release_notes/0_22_4.md +6 -0
  21. data/lib/httpx/adapters/datadog.rb +1 -1
  22. data/lib/httpx/adapters/faraday.rb +12 -4
  23. data/lib/httpx/adapters/sentry.rb +6 -2
  24. data/lib/httpx/connection/http2.rb +1 -1
  25. data/lib/httpx/connection.rb +34 -6
  26. data/lib/httpx/errors.rb +2 -0
  27. data/lib/httpx/extensions.rb +10 -1
  28. data/lib/httpx/io/tcp.rb +2 -1
  29. data/lib/httpx/io/udp.rb +4 -5
  30. data/lib/httpx/options.rb +2 -2
  31. data/lib/httpx/plugins/authentication.rb +1 -1
  32. data/lib/httpx/plugins/aws_sigv4.rb +2 -2
  33. data/lib/httpx/plugins/basic_authentication.rb +1 -1
  34. data/lib/httpx/plugins/circuit_breaker/circuit.rb +1 -1
  35. data/lib/httpx/plugins/circuit_breaker.rb +1 -1
  36. data/lib/httpx/plugins/compression/gzip.rb +1 -1
  37. data/lib/httpx/plugins/compression.rb +4 -4
  38. data/lib/httpx/plugins/cookies.rb +1 -1
  39. data/lib/httpx/plugins/digest_authentication.rb +3 -1
  40. data/lib/httpx/plugins/expect.rb +4 -3
  41. data/lib/httpx/plugins/follow_redirects.rb +8 -1
  42. data/lib/httpx/plugins/grpc/message.rb +1 -1
  43. data/lib/httpx/plugins/grpc.rb +1 -1
  44. data/lib/httpx/plugins/h2c.rb +1 -1
  45. data/lib/httpx/plugins/multipart/decoder.rb +7 -57
  46. data/lib/httpx/plugins/multipart.rb +2 -2
  47. data/lib/httpx/plugins/ntlm_authentication.rb +3 -1
  48. data/lib/httpx/plugins/persistent.rb +1 -1
  49. data/lib/httpx/plugins/proxy/http.rb +4 -2
  50. data/lib/httpx/plugins/proxy.rb +1 -1
  51. data/lib/httpx/plugins/push_promise.rb +1 -1
  52. data/lib/httpx/plugins/rate_limiter.rb +3 -1
  53. data/lib/httpx/plugins/response_cache.rb +1 -1
  54. data/lib/httpx/plugins/retries.rb +3 -2
  55. data/lib/httpx/plugins/stream.rb +0 -2
  56. data/lib/httpx/plugins/upgrade.rb +3 -1
  57. data/lib/httpx/plugins/webdav.rb +2 -0
  58. data/lib/httpx/pool.rb +41 -2
  59. data/lib/httpx/request.rb +1 -1
  60. data/lib/httpx/resolver/https.rb +16 -2
  61. data/lib/httpx/resolver/native.rb +28 -26
  62. data/lib/httpx/resolver/resolver.rb +9 -8
  63. data/lib/httpx/resolver.rb +8 -0
  64. data/lib/httpx/response.rb +8 -0
  65. data/lib/httpx/transcoder/xml.rb +0 -2
  66. data/lib/httpx/transcoder.rb +1 -1
  67. data/lib/httpx/utils.rb +30 -0
  68. data/lib/httpx/version.rb +1 -1
  69. data/lib/httpx.rb +6 -0
  70. data/sig/connection.rbs +3 -1
  71. data/sig/plugins/multipart.rbs +0 -2
  72. data/sig/pool.rbs +3 -1
  73. data/sig/resolver/https.rbs +3 -2
  74. data/sig/resolver/native.rbs +2 -1
  75. data/sig/resolver/resolver.rbs +3 -1
  76. data/sig/resolver.rbs +1 -1
  77. data/sig/response.rbs +4 -1
  78. data/sig/utils.rbs +2 -0
  79. metadata +21 -9
@@ -9,7 +9,7 @@ module HTTPX
9
9
  # * when the server is unavailable (503);
10
10
  # * when a 3xx request comes with a "retry-after" value
11
11
  #
12
- # https://gitlab.com/honeyryderchuck/httpx/wikis/RateLimiter
12
+ # https://gitlab.com/os85/httpx/wikis/RateLimiter
13
13
  #
14
14
  module RateLimiter
15
15
  class << self
@@ -23,6 +23,8 @@ module HTTPX
23
23
  end
24
24
 
25
25
  def retry_on_rate_limited_response(response)
26
+ return false unless response.is_a?(Response)
27
+
26
28
  status = response.status
27
29
 
28
30
  RATE_LIMIT_CODES.include?(status)
@@ -5,7 +5,7 @@ module HTTPX
5
5
  #
6
6
  # This plugin adds support for retrying requests when certain errors happen.
7
7
  #
8
- # https://gitlab.com/honeyryderchuck/httpx/wikis/Response-Cache
8
+ # https://gitlab.com/os85/httpx/wikis/Response-Cache
9
9
  #
10
10
  module ResponseCache
11
11
  CACHEABLE_VERBS = %i[get head].freeze
@@ -5,7 +5,7 @@ module HTTPX
5
5
  #
6
6
  # This plugin adds support for retrying requests when certain errors happen.
7
7
  #
8
- # https://gitlab.com/honeyryderchuck/httpx/wikis/Retries
8
+ # https://gitlab.com/os85/httpx/wikis/Retries
9
9
  #
10
10
  module Retries
11
11
  MAX_RETRIES = 3
@@ -23,9 +23,10 @@ module HTTPX
23
23
  Parser::Error,
24
24
  TLSError,
25
25
  TimeoutError,
26
+ ConnectionError,
26
27
  Connection::HTTP2::GoawayError,
27
28
  ].freeze
28
- DEFAULT_JITTER = ->(interval) { interval * (0.5 * (1 + rand)) }
29
+ DEFAULT_JITTER = ->(interval) { interval * ((rand + 1) * 0.5) }
29
30
 
30
31
  if ENV.key?("HTTPX_NO_JITTER")
31
32
  def self.extra_options(options)
@@ -95,8 +95,6 @@ module HTTPX
95
95
  #
96
96
  module Stream
97
97
  module InstanceMethods
98
- private
99
-
100
98
  def request(*args, stream: false, **options)
101
99
  return super(*args, **options) unless stream
102
100
 
@@ -35,7 +35,9 @@ module HTTPX
35
35
  response = super
36
36
 
37
37
  if response
38
- return response unless response.respond_to?(:headers) && response.headers.key?("upgrade")
38
+ return response unless response.is_a?(Response)
39
+
40
+ return response unless response.headers.key?("upgrade")
39
41
 
40
42
  upgrade_protocol = response.headers["upgrade"].split(/ *, */).first
41
43
 
@@ -32,6 +32,8 @@ module HTTPX
32
32
  "</D:lockinfo>"
33
33
  response = request(:lock, path, headers: headers, xml: xml)
34
34
 
35
+ return response unless response.is_a?(Response)
36
+
35
37
  return response unless blk && response.status == 200
36
38
 
37
39
  lock_token = response.headers["lock-token"]
data/lib/httpx/pool.rb CHANGED
@@ -72,7 +72,7 @@ module HTTPX
72
72
  end
73
73
 
74
74
  def init_connection(connection, _options)
75
- resolve_connection(connection)
75
+ resolve_connection(connection) unless connection.family
76
76
  connection.timers = @timers
77
77
  connection.on(:open) do
78
78
  @connected_connections += 1
@@ -116,19 +116,57 @@ module HTTPX
116
116
  # resolve a name (not the same as name being an IP, yet)
117
117
  # 2. when the connection is initialized with an external already open IO.
118
118
  #
119
+ connection.once(:connect_error, &connection.method(:handle_error))
119
120
  on_resolver_connection(connection)
120
121
  return
121
122
  end
122
123
 
123
124
  find_resolver_for(connection) do |resolver|
124
- resolver << connection
125
+ resolver << try_clone_connection(connection, resolver.family)
125
126
  next if resolver.empty?
126
127
 
127
128
  select_connection(resolver)
128
129
  end
129
130
  end
130
131
 
132
+ def try_clone_connection(connection, family)
133
+ connection.family ||= family
134
+
135
+ return connection if connection.family == family
136
+
137
+ new_connection = connection.class.new(connection.type, connection.origin, connection.options)
138
+ new_connection.family = family
139
+
140
+ connection.once(:tcp_open) { new_connection.force_reset }
141
+ connection.once(:connect_error) do |err|
142
+ if new_connection.connecting?
143
+ new_connection.merge(connection)
144
+ else
145
+ connection.handle_error(err)
146
+ end
147
+ end
148
+
149
+ new_connection.once(:tcp_open) do |new_conn|
150
+ if new_conn != connection
151
+ new_conn.merge(connection)
152
+ connection.force_reset
153
+ end
154
+ end
155
+ new_connection.once(:connect_error) do |err|
156
+ if connection.connecting?
157
+ # main connection has the requests
158
+ connection.merge(new_connection)
159
+ else
160
+ new_connection.handle_error(err)
161
+ end
162
+ end
163
+
164
+ init_connection(new_connection, connection.options)
165
+ new_connection
166
+ end
167
+
131
168
  def on_resolver_connection(connection)
169
+ @connections << connection unless @connections.include?(connection)
132
170
  found_connection = @connections.find do |ch|
133
171
  ch != connection && ch.mergeable?(connection)
134
172
  end
@@ -186,6 +224,7 @@ module HTTPX
186
224
  def coalesce_connections(conn1, conn2)
187
225
  return register_connection(conn2) unless conn1.coalescable?(conn2)
188
226
 
227
+ conn2.emit(:tcp_open, conn1)
189
228
  conn1.merge(conn2)
190
229
  @connections.delete(conn2)
191
230
  end
data/lib/httpx/request.rb CHANGED
@@ -86,7 +86,7 @@ module HTTPX
86
86
  def response=(response)
87
87
  return unless response
88
88
 
89
- if response.is_a?(Response) && response.status == 100
89
+ if response.is_a?(Response) && response.status == 100 && @headers.key?("expect")
90
90
  @informational_status = response.status
91
91
  return
92
92
  end
@@ -69,7 +69,8 @@ module HTTPX
69
69
  @building_connection = true
70
70
  connection = @options.connection_class.new("ssl", @uri, @options.merge(ssl: { alpn_protocols: %w[h2] }))
71
71
  @pool.init_connection(connection, @options)
72
- emit_addresses(connection, @family, @uri_addresses)
72
+ # only explicity emit addresses if connection didn't pre-resolve, i.e. it's not an IP.
73
+ emit_addresses(connection, @family, @uri_addresses) unless connection.addresses
73
74
  @building_connection = false
74
75
  connection
75
76
  end
@@ -135,9 +136,22 @@ module HTTPX
135
136
  emit_resolve_error(connection, connection.origin.host, e)
136
137
  return
137
138
  end
138
- if answers.nil? || answers.empty?
139
+
140
+ if answers.nil?
141
+ # Indicates no such domain was found.
142
+
139
143
  host = @requests.delete(request)
140
144
  connection = @queries.delete(host)
145
+
146
+ emit_resolve_error(connection) unless @queries.value?(connection)
147
+ elsif answers.empty?
148
+ # no address found, eliminate candidates
149
+ host = @requests.delete(request)
150
+ connection = @queries.delete(host)
151
+
152
+ # eliminate other candidates
153
+ @queries.delete_if { |_, conn| connection == conn }
154
+
141
155
  emit_resolve_error(connection)
142
156
  return
143
157
 
@@ -13,27 +13,15 @@ module HTTPX
13
13
  **Resolv::DNS::Config.default_config_hash,
14
14
  packet_size: 512,
15
15
  timeouts: Resolver::RESOLVE_TIMEOUT,
16
- }.freeze
16
+ }
17
17
  else
18
18
  {
19
19
  nameserver: nil,
20
20
  **Resolv::DNS::Config.default_config_hash,
21
21
  packet_size: 512,
22
22
  timeouts: Resolver::RESOLVE_TIMEOUT,
23
- }.freeze
24
- end
25
-
26
- # nameservers for ipv6 are misconfigured in certain systems;
27
- # this can use an unexpected endless loop
28
- # https://gitlab.com/honeyryderchuck/httpx/issues/56
29
- DEFAULTS[:nameserver].select! do |nameserver|
30
- begin
31
- IPAddr.new(nameserver)
32
- true
33
- rescue IPAddr::InvalidAddressError
34
- false
35
- end
36
- end if DEFAULTS[:nameserver]
23
+ }
24
+ end.freeze
37
25
 
38
26
  DNS_PORT = 53
39
27
 
@@ -152,10 +140,21 @@ module HTTPX
152
140
  host = connection.origin.host
153
141
  timeout = (@timeouts[host][0] -= loop_time)
154
142
 
155
- return unless timeout.negative?
143
+ return unless timeout <= 0
156
144
 
157
145
  @timeouts[host].shift
158
- if @timeouts[host].empty?
146
+
147
+ if !@timeouts[host].empty?
148
+ log { "resolver: timeout after #{timeout}s, retry(#{@timeouts[host].first}) #{host}..." }
149
+ resolve(connection)
150
+ elsif @ns_index + 1 < @nameserver.size
151
+ # try on the next nameserver
152
+ @ns_index += 1
153
+ log { "resolver: failed resolving #{host} on nameserver #{@nameserver[@ns_index - 1]} (timeout error)" }
154
+ transition(:idle)
155
+ resolve(connection)
156
+ else
157
+
159
158
  @timeouts.delete(host)
160
159
  @queries.delete(h)
161
160
 
@@ -165,9 +164,6 @@ module HTTPX
165
164
  # This loop_time passed to the exception is bogus. Ideally we would pass the total
166
165
  # resolve timeout, including from the previous retries.
167
166
  raise ResolveTimeoutError.new(loop_time, "Timed out while resolving #{connection.origin.host}")
168
- else
169
- log { "resolver: timeout after #{timeout}s, retry(#{@timeouts[host].first}) #{host}..." }
170
- resolve(connection)
171
167
  end
172
168
  end
173
169
 
@@ -205,7 +201,8 @@ module HTTPX
205
201
  raise ex
206
202
  end
207
203
 
208
- if addresses.nil? || addresses.empty?
204
+ if addresses.nil?
205
+ # Indicates no such domain was found.
209
206
  hostname, connection = @queries.first
210
207
  @queries.delete(hostname)
211
208
  @timeouts.delete(hostname)
@@ -214,6 +211,14 @@ module HTTPX
214
211
  @connections.delete(connection)
215
212
  raise NativeResolveError.new(connection, connection.origin.host)
216
213
  end
214
+ elsif addresses.empty?
215
+ # no address found, eliminate candidates
216
+ _, 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) }
220
+ @connections.delete(connection)
221
+ raise NativeResolveError.new(connection, connection.origin.host)
217
222
  else
218
223
  address = addresses.first
219
224
  name = address["name"]
@@ -299,11 +304,8 @@ module HTTPX
299
304
 
300
305
  ip, port = @nameserver[@ns_index]
301
306
  port ||= DNS_PORT
302
- uri = URI::Generic.build(scheme: "udp", port: port)
303
- uri.hostname = ip
304
- type = IO.registry(uri.scheme)
305
- log { "resolver: server: #{uri}..." }
306
- @io = type.new(uri, [IPAddr.new(ip)], @options)
307
+ log { "resolver: server: #{ip}:#{port}..." }
308
+ @io = UDP.new(ip, port, @options)
307
309
  end
308
310
 
309
311
  def transition(nextstate)
@@ -54,7 +54,7 @@ module HTTPX
54
54
  # double emission check
55
55
  return if connection.addresses && !addresses.intersect?(connection.addresses)
56
56
 
57
- log { "resolver: answer #{connection.origin.host}: #{addresses.inspect}" }
57
+ log { "resolver: answer #{FAMILY_TYPES[RECORD_TYPES[family]]} #{connection.origin.host}: #{addresses.inspect}" }
58
58
  if @pool && # if triggered by early resolve, pool may not be here yet
59
59
  !connection.io &&
60
60
  connection.options.ip_families.size > 1 &&
@@ -63,20 +63,21 @@ module HTTPX
63
63
  log { "resolver: A response, applying resolution delay..." }
64
64
  @pool.after(0.05) do
65
65
  # double emission check
66
- unless connection.addresses && addresses.intersect?(connection.addresses)
67
-
68
- connection.addresses = addresses
69
- emit(:resolve, connection)
70
- end
66
+ emit_resolved_connection(connection, addresses) unless connection.addresses && addresses.intersect?(connection.addresses)
71
67
  end
72
68
  else
73
- connection.addresses = addresses
74
- emit(:resolve, connection)
69
+ emit_resolved_connection(connection, addresses)
75
70
  end
76
71
  end
77
72
 
78
73
  private
79
74
 
75
+ def emit_resolved_connection(connection, addresses)
76
+ connection.addresses = addresses
77
+
78
+ emit(:resolve, connection)
79
+ end
80
+
80
81
  def early_resolve(connection, hostname: connection.origin.host)
81
82
  addresses = @resolver_options[:cache] && (connection.addresses || HTTPX::Resolver.nolookup_resolve(hostname))
82
83
 
@@ -108,7 +108,15 @@ module HTTPX
108
108
 
109
109
  def decode_dns_answer(payload)
110
110
  message = Resolv::DNS::Message.decode(payload)
111
+
112
+ # no domain was found
113
+ return if message.rcode == Resolv::DNS::RCode::NXDomain
114
+
111
115
  addresses = []
116
+
117
+ # TODO: raise an "other dns OtherResolvError" type of error
118
+ return addresses if message.rcode != Resolv::DNS::RCode::NoError
119
+
112
120
  message.each_answer do |question, _, value|
113
121
  case value
114
122
  when Resolv::DNS::Resource::IN::CNAME
@@ -128,6 +128,8 @@ module HTTPX
128
128
  end
129
129
 
130
130
  class Body
131
+ attr_reader :encoding
132
+
131
133
  def initialize(response, options)
132
134
  @response = response
133
135
  @headers = response.headers
@@ -179,6 +181,12 @@ module HTTPX
179
181
  end
180
182
  end
181
183
 
184
+ def filename
185
+ return unless @headers.key?("content-disposition")
186
+
187
+ Utils.get_filename(@headers["content-disposition"])
188
+ end
189
+
182
190
  def to_s
183
191
  case @buffer
184
192
  when StringIO
@@ -38,7 +38,6 @@ module HTTPX::Transcoder
38
38
  begin
39
39
  require "nokogiri"
40
40
 
41
- # rubocop:disable Lint/DuplicateMethods
42
41
  def decode(response)
43
42
  content_type = response.content_type.mime_type
44
43
 
@@ -51,7 +50,6 @@ module HTTPX::Transcoder
51
50
  raise HTTPX::Error, "\"nokogiri\" is required in order to decode XML"
52
51
  end
53
52
  end
54
- # rubocop:enable Lint/DuplicateMethods
55
53
  end
56
54
  register "xml", Xml
57
55
  end
@@ -73,7 +73,7 @@ module HTTPX
73
73
  end
74
74
 
75
75
  def params_hash_has_key?(hash, key)
76
- return false if /\[\]/.match?(key)
76
+ return false if key.include?("[]")
77
77
 
78
78
  key.split(/[\[\]]+/).inject(hash) do |h, part|
79
79
  next h if part == ""
data/lib/httpx/utils.rb CHANGED
@@ -3,6 +3,12 @@
3
3
  module HTTPX
4
4
  module Utils
5
5
  using URIExtensions
6
+ using HTTPX::RegexpExtensions unless Regexp.method_defined?(:match?)
7
+
8
+ TOKEN = %r{[^\s()<>,;:\\"/\[\]?=]+}.freeze
9
+ VALUE = /"(?:\\"|[^"])*"|#{TOKEN}/.freeze
10
+ FILENAME_REGEX = /\s*filename=(#{VALUE})/.freeze
11
+ FILENAME_EXTENSION_REGEX = /\s*filename\*=(#{VALUE})/.freeze
6
12
 
7
13
  module_function
8
14
 
@@ -25,6 +31,30 @@ module HTTPX
25
31
  time - Time.now
26
32
  end
27
33
 
34
+ def get_filename(header, _prefix_regex = nil)
35
+ filename = nil
36
+ case header
37
+ when FILENAME_REGEX
38
+ filename = Regexp.last_match(1)
39
+ filename = Regexp.last_match(1) if filename =~ /^"(.*)"$/
40
+ when FILENAME_EXTENSION_REGEX
41
+ filename = Regexp.last_match(1)
42
+ encoding, _, filename = filename.split("'", 3)
43
+ end
44
+
45
+ return unless filename
46
+
47
+ filename = URI::DEFAULT_PARSER.unescape(filename) if filename.scan(/%.?.?/).all? { |s| /%[0-9a-fA-F]{2}/.match?(s) }
48
+
49
+ filename.scrub!
50
+
51
+ filename = filename.gsub(/\\(.)/, '\1') unless /\\[^\\"]/.match?(filename)
52
+
53
+ filename.force_encoding ::Encoding.find(encoding) if encoding
54
+
55
+ filename
56
+ end
57
+
28
58
  if RUBY_VERSION < "2.3"
29
59
 
30
60
  def to_uri(uri)
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.21.0"
4
+ VERSION = "0.22.4"
5
5
  end
data/lib/httpx.rb CHANGED
@@ -67,3 +67,9 @@ end
67
67
 
68
68
  require "httpx/session"
69
69
  require "httpx/session_extensions"
70
+
71
+ # load integrations when possible
72
+
73
+ require "httpx/adapters/datadog" if defined?(DDTrace) || defined?(Datadog)
74
+ require "httpx/adapters/sentry" if defined?(Sentry)
75
+ require "httpx/adapters/webmock" if defined?(WebMock)
data/sig/connection.rbs CHANGED
@@ -21,6 +21,7 @@ module HTTPX
21
21
 
22
22
  BUFFER_SIZE: Integer
23
23
 
24
+ attr_reader type: io_type
24
25
  attr_reader origin: URI::Generic
25
26
  attr_reader origins: Array[String]
26
27
  attr_reader state: Symbol
@@ -28,7 +29,8 @@ module HTTPX
28
29
  attr_reader options: Options
29
30
  attr_writer timers: Timers
30
31
 
31
- @type: io_type
32
+ attr_accessor family: Integer?
33
+
32
34
  @window_size: Integer
33
35
  @read_buffer: Buffer
34
36
  @write_buffer: Buffer
@@ -68,8 +68,6 @@ module HTTPX
68
68
  def initialize: (Response response) -> void
69
69
 
70
70
  def parse: () -> void
71
-
72
- def get_filename: (String head) -> String?
73
71
  end
74
72
 
75
73
  class FilePart # < SimpleDelegator
data/sig/pool.rbs CHANGED
@@ -22,7 +22,9 @@ module HTTPX
22
22
 
23
23
  private
24
24
 
25
- def initialize: () -> untyped
25
+ def initialize: () -> void
26
+
27
+ def try_clone_connection: (Connection connection, Integer? family) -> Connection
26
28
 
27
29
  def resolve_connection: (Connection) -> void
28
30
 
@@ -6,7 +6,8 @@ module HTTPX
6
6
  DEFAULTS: Hash[Symbol, untyped]
7
7
  FAMILY_TYPES: Hash[singleton(Resolv::DNS::Resource), String]
8
8
 
9
- @family: ip_family
9
+ attr_reader family: ip_family
10
+
10
11
  @options: Options
11
12
  @requests: Hash[Request, String]
12
13
  @connections: Array[Connection]
@@ -33,7 +34,7 @@ module HTTPX
33
34
 
34
35
  def build_request: (String hostname) -> Request
35
36
 
36
- def decode_response_body: (Response) -> Array[dns_result]
37
+ def decode_response_body: (Response) -> Array[dns_result]?
37
38
  end
38
39
  end
39
40
  end
@@ -7,7 +7,8 @@ module HTTPX
7
7
  DEFAULTS: Hash[Symbol, untyped]
8
8
  DNS_PORT: Integer
9
9
 
10
- @family: ip_family
10
+ attr_reader family: ip_family
11
+
11
12
  @options: Options
12
13
  @ns_index: Integer
13
14
  @nameserver: Array[String]?
@@ -6,7 +6,7 @@ module HTTPX
6
6
 
7
7
  RECORD_TYPES: Hash[Integer, singleton(Resolv::DNS::Resource)]
8
8
 
9
- attr_reader family: ip_family
9
+ attr_reader family: ip_family?
10
10
 
11
11
  @record_type: singleton(Resolv::DNS::Resource)
12
12
  @options: Options
@@ -24,6 +24,8 @@ module HTTPX
24
24
 
25
25
  private
26
26
 
27
+ def emit_resolved_connection: (Connection connection, Array[IPAddr] addresses) -> void
28
+
27
29
  def initialize: (ip_family? family, options options) -> void
28
30
 
29
31
  def early_resolve: (Connection connection, ?hostname: String) -> void
data/sig/resolver.rbs CHANGED
@@ -30,6 +30,6 @@ module HTTPX
30
30
 
31
31
  def self?.encode_dns_query: (String hostname, ?type: dns_resource) -> String
32
32
 
33
- def self?.decode_dns_answer: (String) -> Array[dns_result]
33
+ def self?.decode_dns_answer: (String) -> Array[dns_result]?
34
34
  end
35
35
  end
data/sig/response.rbs CHANGED
@@ -48,13 +48,14 @@ module HTTPX
48
48
  include _ToS
49
49
  include _ToStr
50
50
 
51
+ attr_reader encoding: String
52
+
51
53
  @response: Response
52
54
  @headers: Headers
53
55
  @options: Options
54
56
  @state: :idle | :memory | :buffer | :closed
55
57
  @threshold_size: Integer
56
58
  @window_size: Integer
57
- @encoding: String
58
59
  @length: Integer
59
60
  @buffer: StringIO | Tempfile | nil
60
61
 
@@ -63,6 +64,8 @@ module HTTPX
63
64
  def each: () { (String) -> void } -> void
64
65
  | () -> Enumerable[String]
65
66
 
67
+ def filename: () -> String?
68
+
66
69
  def bytesize: () -> (Integer | Float)
67
70
  def empty?: () -> bool
68
71
  def copy_to: (String | File | _Writer destination) -> void
data/sig/utils.rbs CHANGED
@@ -9,5 +9,7 @@ module HTTPX
9
9
  def self?.elapsed_time: (Integer | Float monotonic_time) -> Float
10
10
 
11
11
  def self?.to_uri: (generic_uri uri) -> URI::Generic
12
+
13
+ def self?.get_filename: (String header) -> String?
12
14
  end
13
15
  end