httpx 0.9.0 → 0.11.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.
- checksums.yaml +4 -4
- data/LICENSE.txt +48 -0
- data/README.md +13 -3
- data/doc/release_notes/0_10_0.md +66 -0
- data/doc/release_notes/0_10_1.md +37 -0
- data/doc/release_notes/0_10_2.md +5 -0
- data/doc/release_notes/0_11_0.md +76 -0
- data/doc/release_notes/0_11_1.md +1 -0
- data/lib/httpx.rb +2 -0
- data/lib/httpx/adapters/datadog.rb +205 -0
- data/lib/httpx/adapters/faraday.rb +1 -3
- data/lib/httpx/adapters/webmock.rb +123 -0
- data/lib/httpx/chainable.rb +10 -9
- data/lib/httpx/connection.rb +7 -24
- data/lib/httpx/connection/http1.rb +15 -2
- data/lib/httpx/connection/http2.rb +15 -16
- data/lib/httpx/domain_name.rb +438 -0
- data/lib/httpx/errors.rb +4 -1
- data/lib/httpx/extensions.rb +21 -1
- data/lib/httpx/headers.rb +1 -0
- data/lib/httpx/io/ssl.rb +4 -9
- data/lib/httpx/io/tcp.rb +6 -5
- data/lib/httpx/io/udp.rb +8 -4
- data/lib/httpx/options.rb +2 -0
- data/lib/httpx/parser/http1.rb +14 -17
- data/lib/httpx/plugins/compression.rb +28 -63
- data/lib/httpx/plugins/compression/brotli.rb +10 -14
- data/lib/httpx/plugins/compression/deflate.rb +7 -6
- data/lib/httpx/plugins/compression/gzip.rb +23 -5
- data/lib/httpx/plugins/cookies.rb +21 -60
- data/lib/httpx/plugins/cookies/cookie.rb +173 -0
- data/lib/httpx/plugins/cookies/jar.rb +74 -0
- data/lib/httpx/plugins/cookies/set_cookie_parser.rb +142 -0
- data/lib/httpx/plugins/expect.rb +34 -11
- data/lib/httpx/plugins/follow_redirects.rb +20 -2
- data/lib/httpx/plugins/h2c.rb +1 -1
- data/lib/httpx/plugins/multipart.rb +41 -30
- data/lib/httpx/plugins/multipart/encoder.rb +115 -0
- data/lib/httpx/plugins/multipart/mime_type_detector.rb +64 -0
- data/lib/httpx/plugins/multipart/part.rb +34 -0
- data/lib/httpx/plugins/persistent.rb +6 -1
- data/lib/httpx/plugins/proxy.rb +16 -2
- data/lib/httpx/plugins/proxy/socks4.rb +14 -14
- data/lib/httpx/plugins/proxy/socks5.rb +3 -2
- data/lib/httpx/plugins/push_promise.rb +2 -2
- data/lib/httpx/plugins/rate_limiter.rb +51 -0
- data/lib/httpx/plugins/retries.rb +3 -2
- data/lib/httpx/plugins/stream.rb +109 -13
- data/lib/httpx/pool.rb +14 -20
- data/lib/httpx/request.rb +29 -31
- data/lib/httpx/resolver.rb +7 -6
- data/lib/httpx/resolver/https.rb +25 -25
- data/lib/httpx/resolver/native.rb +29 -22
- data/lib/httpx/resolver/resolver_mixin.rb +4 -2
- data/lib/httpx/resolver/system.rb +3 -3
- data/lib/httpx/response.rb +16 -23
- data/lib/httpx/selector.rb +11 -17
- data/lib/httpx/session.rb +39 -30
- data/lib/httpx/transcoder.rb +20 -0
- data/lib/httpx/transcoder/chunker.rb +0 -2
- data/lib/httpx/transcoder/form.rb +9 -7
- data/lib/httpx/transcoder/json.rb +0 -4
- data/lib/httpx/utils.rb +45 -0
- data/lib/httpx/version.rb +1 -1
- data/sig/buffer.rbs +24 -0
- data/sig/callbacks.rbs +14 -0
- data/sig/chainable.rbs +37 -0
- data/sig/connection.rbs +85 -0
- data/sig/connection/http1.rbs +66 -0
- data/sig/connection/http2.rbs +77 -0
- data/sig/domain_name.rbs +17 -0
- data/sig/errors.rbs +3 -0
- data/sig/headers.rbs +45 -0
- data/sig/httpx.rbs +15 -0
- data/sig/loggable.rbs +11 -0
- data/sig/options.rbs +118 -0
- data/sig/parser/http1.rbs +50 -0
- data/sig/plugins/authentication.rbs +11 -0
- data/sig/plugins/basic_authentication.rbs +13 -0
- data/sig/plugins/compression.rbs +55 -0
- data/sig/plugins/compression/brotli.rbs +21 -0
- data/sig/plugins/compression/deflate.rbs +17 -0
- data/sig/plugins/compression/gzip.rbs +29 -0
- data/sig/plugins/cookies.rbs +26 -0
- data/sig/plugins/cookies/cookie.rbs +50 -0
- data/sig/plugins/cookies/jar.rbs +27 -0
- data/sig/plugins/digest_authentication.rbs +33 -0
- data/sig/plugins/expect.rbs +19 -0
- data/sig/plugins/follow_redirects.rbs +37 -0
- data/sig/plugins/h2c.rbs +26 -0
- data/sig/plugins/multipart.rbs +44 -0
- data/sig/plugins/persistent.rbs +17 -0
- data/sig/plugins/proxy.rbs +47 -0
- data/sig/plugins/proxy/http.rbs +14 -0
- data/sig/plugins/proxy/socks4.rbs +33 -0
- data/sig/plugins/proxy/socks5.rbs +36 -0
- data/sig/plugins/proxy/ssh.rbs +18 -0
- data/sig/plugins/push_promise.rbs +22 -0
- data/sig/plugins/rate_limiter.rbs +11 -0
- data/sig/plugins/retries.rbs +48 -0
- data/sig/plugins/stream.rbs +39 -0
- data/sig/pool.rbs +36 -0
- data/sig/registry.rbs +9 -0
- data/sig/request.rbs +61 -0
- data/sig/resolver.rbs +26 -0
- data/sig/resolver/https.rbs +51 -0
- data/sig/resolver/native.rbs +60 -0
- data/sig/resolver/resolver_mixin.rbs +27 -0
- data/sig/resolver/system.rbs +17 -0
- data/sig/response.rbs +87 -0
- data/sig/selector.rbs +20 -0
- data/sig/session.rbs +49 -0
- data/sig/timeout.rbs +29 -0
- data/sig/transcoder.rbs +18 -0
- data/sig/transcoder/body.rbs +20 -0
- data/sig/transcoder/chunker.rbs +32 -0
- data/sig/transcoder/form.rbs +22 -0
- data/sig/transcoder/json.rbs +16 -0
- metadata +99 -59
- data/lib/httpx/resolver/options.rb +0 -25
data/lib/httpx/request.rb
CHANGED
|
@@ -33,11 +33,7 @@ module HTTPX
|
|
|
33
33
|
|
|
34
34
|
USER_AGENT = "httpx.rb/#{VERSION}"
|
|
35
35
|
|
|
36
|
-
attr_reader :verb, :uri, :headers, :body, :state
|
|
37
|
-
|
|
38
|
-
attr_reader :options, :response
|
|
39
|
-
|
|
40
|
-
def_delegator :@body, :<<
|
|
36
|
+
attr_reader :verb, :uri, :headers, :body, :state, :options, :response
|
|
41
37
|
|
|
42
38
|
def_delegator :@body, :empty?
|
|
43
39
|
|
|
@@ -45,7 +41,7 @@ module HTTPX
|
|
|
45
41
|
|
|
46
42
|
def initialize(verb, uri, options = {})
|
|
47
43
|
@verb = verb.to_s.downcase.to_sym
|
|
48
|
-
@uri =
|
|
44
|
+
@uri = Utils.uri(uri)
|
|
49
45
|
@options = Options.new(options)
|
|
50
46
|
|
|
51
47
|
raise(Error, "unknown method: #{verb}") unless METHODS.include?(@verb)
|
|
@@ -64,17 +60,15 @@ module HTTPX
|
|
|
64
60
|
:w
|
|
65
61
|
end
|
|
66
62
|
|
|
67
|
-
# :nocov:
|
|
68
63
|
if RUBY_VERSION < "2.2"
|
|
69
|
-
|
|
64
|
+
URIParser = URI::DEFAULT_PARSER
|
|
65
|
+
|
|
70
66
|
def initialize_with_escape(verb, uri, options = {})
|
|
71
|
-
initialize_without_escape(verb,
|
|
67
|
+
initialize_without_escape(verb, URIParser.escape(uri.to_s), options)
|
|
72
68
|
end
|
|
73
69
|
alias_method :initialize_without_escape, :initialize
|
|
74
70
|
alias_method :initialize, :initialize_with_escape
|
|
75
|
-
# rubocop: enable Lint/UriEscapeUnescape:
|
|
76
71
|
end
|
|
77
|
-
# :nocov:
|
|
78
72
|
|
|
79
73
|
def merge_headers(h)
|
|
80
74
|
@headers = @headers.merge(h)
|
|
@@ -87,6 +81,10 @@ module HTTPX
|
|
|
87
81
|
def response=(response)
|
|
88
82
|
return unless response
|
|
89
83
|
|
|
84
|
+
if response.status == 100
|
|
85
|
+
@informational_status = response.status
|
|
86
|
+
return
|
|
87
|
+
end
|
|
90
88
|
@response = response
|
|
91
89
|
end
|
|
92
90
|
|
|
@@ -112,7 +110,7 @@ module HTTPX
|
|
|
112
110
|
|
|
113
111
|
query = []
|
|
114
112
|
if (q = @options.params)
|
|
115
|
-
query <<
|
|
113
|
+
query << Transcoder.registry("form").encode(q)
|
|
116
114
|
end
|
|
117
115
|
query << @uri.query if @uri.query
|
|
118
116
|
@query = query.join("&")
|
|
@@ -176,23 +174,23 @@ module HTTPX
|
|
|
176
174
|
end
|
|
177
175
|
end
|
|
178
176
|
|
|
177
|
+
def rewind
|
|
178
|
+
return if empty?
|
|
179
|
+
|
|
180
|
+
@body.rewind if @body.respond_to?(:rewind)
|
|
181
|
+
end
|
|
182
|
+
|
|
179
183
|
def empty?
|
|
180
184
|
return true if @body.nil?
|
|
181
185
|
return false if chunked?
|
|
182
186
|
|
|
183
|
-
bytesize.zero?
|
|
187
|
+
@body.bytesize.zero?
|
|
184
188
|
end
|
|
185
189
|
|
|
186
190
|
def bytesize
|
|
187
191
|
return 0 if @body.nil?
|
|
188
192
|
|
|
189
|
-
|
|
190
|
-
@body.bytesize
|
|
191
|
-
elsif @body.respond_to?(:size)
|
|
192
|
-
@body.size
|
|
193
|
-
else
|
|
194
|
-
raise Error, "cannot determine size of body: #{@body.inspect}"
|
|
195
|
-
end
|
|
193
|
+
@body.bytesize
|
|
196
194
|
end
|
|
197
195
|
|
|
198
196
|
def stream(body)
|
|
@@ -224,6 +222,7 @@ module HTTPX
|
|
|
224
222
|
def transition(nextstate)
|
|
225
223
|
case nextstate
|
|
226
224
|
when :idle
|
|
225
|
+
@body.rewind
|
|
227
226
|
@response = nil
|
|
228
227
|
@drainer = nil
|
|
229
228
|
when :headers
|
|
@@ -233,15 +232,15 @@ module HTTPX
|
|
|
233
232
|
@state == :expect
|
|
234
233
|
|
|
235
234
|
if @headers.key?("expect")
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
235
|
+
if @informational_status && @informational_status == 100
|
|
236
|
+
# check for 100 Continue response, and deallocate the var
|
|
237
|
+
# if @informational_status == 100
|
|
238
|
+
# @response = nil
|
|
239
|
+
# end
|
|
240
|
+
else
|
|
241
|
+
return if @state == :expect # do not re-set it
|
|
242
|
+
|
|
243
|
+
nextstate = :expect
|
|
245
244
|
end
|
|
246
245
|
end
|
|
247
246
|
when :done
|
|
@@ -253,8 +252,7 @@ module HTTPX
|
|
|
253
252
|
end
|
|
254
253
|
|
|
255
254
|
def expects?
|
|
256
|
-
@headers["expect"] == "100-continue" &&
|
|
257
|
-
@response && @response.status == 100
|
|
255
|
+
@headers["expect"] == "100-continue" && @informational_status == 100 && !@response
|
|
258
256
|
end
|
|
259
257
|
|
|
260
258
|
class ProcIO
|
data/lib/httpx/resolver.rb
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "resolv"
|
|
4
|
-
require "httpx/resolver/resolver_mixin"
|
|
5
|
-
require "httpx/resolver/system"
|
|
6
|
-
require "httpx/resolver/native"
|
|
7
|
-
require "httpx/resolver/https"
|
|
8
4
|
|
|
9
5
|
module HTTPX
|
|
10
6
|
module Resolver
|
|
11
7
|
extend Registry
|
|
12
8
|
|
|
9
|
+
RESOLVE_TIMEOUT = 5
|
|
10
|
+
|
|
11
|
+
require "httpx/resolver/resolver_mixin"
|
|
12
|
+
require "httpx/resolver/system"
|
|
13
|
+
require "httpx/resolver/native"
|
|
14
|
+
require "httpx/resolver/https"
|
|
15
|
+
|
|
13
16
|
register :system, System
|
|
14
17
|
register :native, Native
|
|
15
18
|
register :https, HTTPS
|
|
@@ -101,5 +104,3 @@ module HTTPX
|
|
|
101
104
|
end
|
|
102
105
|
end
|
|
103
106
|
end
|
|
104
|
-
|
|
105
|
-
require "httpx/resolver/options"
|
data/lib/httpx/resolver/https.rb
CHANGED
|
@@ -21,6 +21,7 @@ module HTTPX
|
|
|
21
21
|
DEFAULTS = {
|
|
22
22
|
uri: NAMESERVER,
|
|
23
23
|
use_get: false,
|
|
24
|
+
record_types: RECORD_TYPES.keys,
|
|
24
25
|
}.freeze
|
|
25
26
|
|
|
26
27
|
def_delegator :@connections, :empty?
|
|
@@ -29,27 +30,29 @@ module HTTPX
|
|
|
29
30
|
|
|
30
31
|
def initialize(options)
|
|
31
32
|
@options = Options.new(options)
|
|
32
|
-
@resolver_options =
|
|
33
|
-
@_record_types = Hash.new { |types, host| types[host] =
|
|
33
|
+
@resolver_options = DEFAULTS.merge(@options.resolver_options)
|
|
34
|
+
@_record_types = Hash.new { |types, host| types[host] = @resolver_options[:record_types].dup }
|
|
34
35
|
@queries = {}
|
|
35
36
|
@requests = {}
|
|
36
37
|
@connections = []
|
|
37
|
-
@uri = URI(@resolver_options
|
|
38
|
+
@uri = URI(@resolver_options[:uri])
|
|
38
39
|
@uri_addresses = nil
|
|
40
|
+
@resolver = Resolv::DNS.new
|
|
41
|
+
@resolver.timeouts = @resolver_options.fetch(:timeouts, Resolver::RESOLVE_TIMEOUT)
|
|
39
42
|
end
|
|
40
43
|
|
|
41
44
|
def <<(connection)
|
|
42
45
|
return if @uri.origin == connection.origin.to_s
|
|
43
46
|
|
|
44
|
-
@uri_addresses ||=
|
|
47
|
+
@uri_addresses ||= ip_resolve(@uri.host) || system_resolve(@uri.host) || @resolver.getaddresses(@uri.host)
|
|
45
48
|
|
|
46
49
|
if @uri_addresses.empty?
|
|
47
|
-
ex = ResolveError.new("Can't resolve #{
|
|
50
|
+
ex = ResolveError.new("Can't resolve DNS server #{@uri.host}")
|
|
48
51
|
ex.set_backtrace(caller)
|
|
49
|
-
|
|
50
|
-
else
|
|
51
|
-
early_resolve(connection) || resolve(connection)
|
|
52
|
+
throw(:resolve_error, ex)
|
|
52
53
|
end
|
|
54
|
+
|
|
55
|
+
early_resolve(connection) || resolve(connection)
|
|
53
56
|
end
|
|
54
57
|
|
|
55
58
|
def timeout
|
|
@@ -70,12 +73,6 @@ module HTTPX
|
|
|
70
73
|
|
|
71
74
|
private
|
|
72
75
|
|
|
73
|
-
def connect
|
|
74
|
-
return if @queries.empty?
|
|
75
|
-
|
|
76
|
-
resolver_connection.__send__(__method__)
|
|
77
|
-
end
|
|
78
|
-
|
|
79
76
|
def pool
|
|
80
77
|
Thread.current[:httpx_connection_pool] ||= Pool.new
|
|
81
78
|
end
|
|
@@ -94,11 +91,18 @@ module HTTPX
|
|
|
94
91
|
def resolve(connection = @connections.first, hostname = nil)
|
|
95
92
|
return if @building_connection
|
|
96
93
|
|
|
97
|
-
hostname
|
|
98
|
-
|
|
94
|
+
hostname ||= @queries.key(connection)
|
|
95
|
+
|
|
96
|
+
if hostname.nil?
|
|
97
|
+
hostname = connection.origin.host
|
|
98
|
+
log { "resolver: resolve IDN #{connection.origin.non_ascii_hostname} as #{hostname}" } if connection.origin.non_ascii_hostname
|
|
99
|
+
end
|
|
100
|
+
type = @_record_types[hostname].first || "A"
|
|
99
101
|
log { "resolver: query #{type} for #{hostname}" }
|
|
100
102
|
begin
|
|
101
103
|
request = build_request(hostname, type)
|
|
104
|
+
request.on(:response, &method(:on_response).curry(2)[request])
|
|
105
|
+
request.on(:promise, &method(:on_promise))
|
|
102
106
|
@requests[request] = connection
|
|
103
107
|
resolver_connection.send(request)
|
|
104
108
|
@queries[hostname] = connection
|
|
@@ -113,9 +117,7 @@ module HTTPX
|
|
|
113
117
|
rescue StandardError => e
|
|
114
118
|
connection = @requests[request]
|
|
115
119
|
hostname = @queries.key(connection)
|
|
116
|
-
|
|
117
|
-
error.set_backtrace(e.backtrace)
|
|
118
|
-
emit(:error, connection, error)
|
|
120
|
+
emit_resolve_error(connection, hostname, e)
|
|
119
121
|
else
|
|
120
122
|
parse(response)
|
|
121
123
|
ensure
|
|
@@ -138,7 +140,7 @@ module HTTPX
|
|
|
138
140
|
return
|
|
139
141
|
end
|
|
140
142
|
end
|
|
141
|
-
if answers.empty?
|
|
143
|
+
if answers.nil? || answers.empty?
|
|
142
144
|
host, connection = @queries.first
|
|
143
145
|
@_record_types[host].shift
|
|
144
146
|
if @_record_types[host].empty?
|
|
@@ -172,7 +174,7 @@ module HTTPX
|
|
|
172
174
|
next unless connection # probably a retried query for which there's an answer
|
|
173
175
|
|
|
174
176
|
@connections.delete(connection)
|
|
175
|
-
Resolver.cached_lookup_set(hostname, addresses) if @resolver_options
|
|
177
|
+
Resolver.cached_lookup_set(hostname, addresses) if @resolver_options[:cache]
|
|
176
178
|
emit_addresses(connection, addresses.map { |addr| addr["data"] })
|
|
177
179
|
end
|
|
178
180
|
end
|
|
@@ -186,7 +188,7 @@ module HTTPX
|
|
|
186
188
|
rklass = @options.request_class
|
|
187
189
|
payload = Resolver.encode_dns_query(hostname, type: RECORD_TYPES[type])
|
|
188
190
|
|
|
189
|
-
if @resolver_options
|
|
191
|
+
if @resolver_options[:use_get]
|
|
190
192
|
params = URI.decode_www_form(uri.query.to_s)
|
|
191
193
|
params << ["type", type]
|
|
192
194
|
params << ["dns", Base64.urlsafe_encode64(payload, padding: false)]
|
|
@@ -197,8 +199,6 @@ module HTTPX
|
|
|
197
199
|
request.headers["content-type"] = "application/dns-message"
|
|
198
200
|
end
|
|
199
201
|
request.headers["accept"] = "application/dns-message"
|
|
200
|
-
request.on(:response, &method(:on_response).curry[request])
|
|
201
|
-
request.on(:promise, &method(:on_promise))
|
|
202
202
|
request
|
|
203
203
|
end
|
|
204
204
|
|
|
@@ -206,7 +206,7 @@ module HTTPX
|
|
|
206
206
|
case response.headers["content-type"]
|
|
207
207
|
when "application/dns-json",
|
|
208
208
|
"application/json",
|
|
209
|
-
%r{^application
|
|
209
|
+
%r{^application/x-javascript} # because google...
|
|
210
210
|
payload = JSON.parse(response.to_s)
|
|
211
211
|
payload["Answer"]
|
|
212
212
|
when "application/dns-udpwireformat",
|
|
@@ -7,19 +7,18 @@ module HTTPX
|
|
|
7
7
|
class Resolver::Native
|
|
8
8
|
extend Forwardable
|
|
9
9
|
include Resolver::ResolverMixin
|
|
10
|
+
using URIExtensions
|
|
10
11
|
|
|
11
|
-
RESOLVE_TIMEOUT = 5
|
|
12
12
|
RECORD_TYPES = {
|
|
13
13
|
"A" => Resolv::DNS::Resource::IN::A,
|
|
14
14
|
"AAAA" => Resolv::DNS::Resource::IN::AAAA,
|
|
15
15
|
}.freeze
|
|
16
16
|
|
|
17
|
-
# :nocov:
|
|
18
17
|
DEFAULTS = if RUBY_VERSION < "2.2"
|
|
19
18
|
{
|
|
20
19
|
**Resolv::DNS::Config.default_config_hash,
|
|
21
20
|
packet_size: 512,
|
|
22
|
-
timeouts: RESOLVE_TIMEOUT,
|
|
21
|
+
timeouts: Resolver::RESOLVE_TIMEOUT,
|
|
23
22
|
record_types: RECORD_TYPES.keys,
|
|
24
23
|
}.freeze
|
|
25
24
|
else
|
|
@@ -27,7 +26,7 @@ module HTTPX
|
|
|
27
26
|
nameserver: nil,
|
|
28
27
|
**Resolv::DNS::Config.default_config_hash,
|
|
29
28
|
packet_size: 512,
|
|
30
|
-
timeouts: RESOLVE_TIMEOUT,
|
|
29
|
+
timeouts: Resolver::RESOLVE_TIMEOUT,
|
|
31
30
|
record_types: RECORD_TYPES.keys,
|
|
32
31
|
}.freeze
|
|
33
32
|
end
|
|
@@ -43,7 +42,6 @@ module HTTPX
|
|
|
43
42
|
false
|
|
44
43
|
end
|
|
45
44
|
end if DEFAULTS[:nameserver]
|
|
46
|
-
# :nocov:
|
|
47
45
|
|
|
48
46
|
DNS_PORT = 53
|
|
49
47
|
|
|
@@ -52,15 +50,15 @@ module HTTPX
|
|
|
52
50
|
def initialize(options)
|
|
53
51
|
@options = Options.new(options)
|
|
54
52
|
@ns_index = 0
|
|
55
|
-
@resolver_options =
|
|
56
|
-
@nameserver = @resolver_options
|
|
57
|
-
@_timeouts = Array(@resolver_options
|
|
53
|
+
@resolver_options = DEFAULTS.merge(@options.resolver_options)
|
|
54
|
+
@nameserver = @resolver_options[:nameserver]
|
|
55
|
+
@_timeouts = Array(@resolver_options[:timeouts])
|
|
58
56
|
@timeouts = Hash.new { |timeouts, host| timeouts[host] = @_timeouts.dup }
|
|
59
|
-
@_record_types = Hash.new { |types, host| types[host] = @resolver_options
|
|
57
|
+
@_record_types = Hash.new { |types, host| types[host] = @resolver_options[:record_types].dup }
|
|
60
58
|
@connections = []
|
|
61
59
|
@queries = {}
|
|
62
60
|
@read_buffer = "".b
|
|
63
|
-
@write_buffer = Buffer.new(@resolver_options
|
|
61
|
+
@write_buffer = Buffer.new(@resolver_options[:packet_size])
|
|
64
62
|
@state = :idle
|
|
65
63
|
end
|
|
66
64
|
|
|
@@ -110,9 +108,9 @@ module HTTPX
|
|
|
110
108
|
return if early_resolve(connection)
|
|
111
109
|
|
|
112
110
|
if @nameserver.nil?
|
|
113
|
-
ex = ResolveError.new("
|
|
111
|
+
ex = ResolveError.new("No available nameserver")
|
|
114
112
|
ex.set_backtrace(caller)
|
|
115
|
-
|
|
113
|
+
throw(:resolve_error, ex)
|
|
116
114
|
else
|
|
117
115
|
@connections << connection
|
|
118
116
|
resolve
|
|
@@ -149,26 +147,30 @@ module HTTPX
|
|
|
149
147
|
queries[h] = connection
|
|
150
148
|
next
|
|
151
149
|
end
|
|
150
|
+
|
|
152
151
|
@timeouts[host].shift
|
|
153
152
|
if @timeouts[host].empty?
|
|
154
153
|
@timeouts.delete(host)
|
|
155
154
|
@connections.delete(connection)
|
|
156
|
-
|
|
155
|
+
# This loop_time passed to the exception is bogus. Ideally we would pass the total
|
|
156
|
+
# resolve timeout, including from the previous retries.
|
|
157
|
+
raise ResolveTimeoutError.new(loop_time, "Timed out")
|
|
158
|
+
# raise NativeResolveError.new(connection, host)
|
|
157
159
|
else
|
|
160
|
+
log { "resolver: timeout after #{timeout}s, retry(#{@timeouts[host].first}) #{host}..." }
|
|
158
161
|
connections << connection
|
|
159
|
-
|
|
162
|
+
queries[h] = connection
|
|
160
163
|
end
|
|
161
164
|
end
|
|
162
165
|
@queries = queries
|
|
163
166
|
connections.each { |ch| resolve(ch) }
|
|
164
167
|
end
|
|
165
168
|
|
|
166
|
-
def dread(wsize = @resolver_options
|
|
169
|
+
def dread(wsize = @resolver_options[:packet_size])
|
|
167
170
|
loop do
|
|
168
171
|
siz = @io.read(wsize, @read_buffer)
|
|
169
172
|
return unless siz && siz.positive?
|
|
170
173
|
|
|
171
|
-
log { "resolver: READ: #{siz} bytes..." }
|
|
172
174
|
parse(@read_buffer)
|
|
173
175
|
return if @state == :closed
|
|
174
176
|
end
|
|
@@ -181,7 +183,6 @@ module HTTPX
|
|
|
181
183
|
siz = @io.write(@write_buffer)
|
|
182
184
|
return unless siz && siz.positive?
|
|
183
185
|
|
|
184
|
-
log { "resolver: WRITE: #{siz} bytes..." }
|
|
185
186
|
return if @state == :closed
|
|
186
187
|
end
|
|
187
188
|
end
|
|
@@ -200,13 +201,14 @@ module HTTPX
|
|
|
200
201
|
end
|
|
201
202
|
end
|
|
202
203
|
|
|
203
|
-
if addresses.empty?
|
|
204
|
+
if addresses.nil? || addresses.empty?
|
|
204
205
|
hostname, connection = @queries.first
|
|
205
206
|
@_record_types[hostname].shift
|
|
206
207
|
if @_record_types[hostname].empty?
|
|
207
208
|
@queries.delete(hostname)
|
|
208
209
|
@_record_types.delete(hostname)
|
|
209
210
|
@connections.delete(connection)
|
|
211
|
+
|
|
210
212
|
raise NativeResolveError.new(connection, hostname)
|
|
211
213
|
end
|
|
212
214
|
else
|
|
@@ -224,7 +226,7 @@ module HTTPX
|
|
|
224
226
|
end
|
|
225
227
|
else
|
|
226
228
|
@connections.delete(connection)
|
|
227
|
-
Resolver.cached_lookup_set(connection.origin.host, addresses) if @resolver_options
|
|
229
|
+
Resolver.cached_lookup_set(connection.origin.host, addresses) if @resolver_options[:cache]
|
|
228
230
|
emit_addresses(connection, addresses.map { |addr| addr["data"] })
|
|
229
231
|
end
|
|
230
232
|
end
|
|
@@ -237,9 +239,14 @@ module HTTPX
|
|
|
237
239
|
raise Error, "no URI to resolve" unless connection
|
|
238
240
|
return unless @write_buffer.empty?
|
|
239
241
|
|
|
240
|
-
hostname
|
|
242
|
+
hostname ||= @queries.key(connection)
|
|
243
|
+
|
|
244
|
+
if hostname.nil?
|
|
245
|
+
hostname = connection.origin.host
|
|
246
|
+
log { "resolver: resolve IDN #{connection.origin.non_ascii_hostname} as #{hostname}" } if connection.origin.non_ascii_hostname
|
|
247
|
+
end
|
|
241
248
|
@queries[hostname] = connection
|
|
242
|
-
type = @_record_types[hostname].first
|
|
249
|
+
type = @_record_types[hostname].first || "A"
|
|
243
250
|
log { "resolver: query #{type} for #{hostname}" }
|
|
244
251
|
begin
|
|
245
252
|
@write_buffer << Resolver.encode_dns_query(hostname, type: RECORD_TYPES[type])
|
|
@@ -276,7 +283,7 @@ module HTTPX
|
|
|
276
283
|
@io.connect
|
|
277
284
|
return unless @io.connected?
|
|
278
285
|
|
|
279
|
-
resolve if @queries.empty?
|
|
286
|
+
resolve if @queries.empty? && !@connections.empty?
|
|
280
287
|
when :closed
|
|
281
288
|
return unless @state == :open
|
|
282
289
|
|