httpx 0.21.0 → 0.22.4

Sign up to get free protection for your applications and to get access to all the features.
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