httpx 0.16.1 → 0.18.2
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/README.md +4 -3
- data/doc/release_notes/0_17_0.md +49 -0
- data/doc/release_notes/0_18_0.md +69 -0
- data/doc/release_notes/0_18_1.md +12 -0
- data/doc/release_notes/0_18_2.md +10 -0
- data/lib/httpx/adapters/datadog.rb +1 -1
- data/lib/httpx/adapters/faraday.rb +5 -3
- data/lib/httpx/adapters/webmock.rb +9 -3
- data/lib/httpx/altsvc.rb +2 -2
- data/lib/httpx/chainable.rb +4 -4
- data/lib/httpx/connection/http1.rb +23 -14
- data/lib/httpx/connection/http2.rb +35 -17
- data/lib/httpx/connection.rb +74 -76
- data/lib/httpx/domain_name.rb +1 -1
- data/lib/httpx/extensions.rb +50 -4
- data/lib/httpx/headers.rb +1 -1
- data/lib/httpx/io/ssl.rb +5 -1
- data/lib/httpx/io/tls.rb +7 -7
- data/lib/httpx/loggable.rb +5 -5
- data/lib/httpx/options.rb +35 -13
- data/lib/httpx/parser/http1.rb +10 -6
- data/lib/httpx/plugins/aws_sdk_authentication.rb +42 -18
- data/lib/httpx/plugins/aws_sigv4.rb +9 -11
- data/lib/httpx/plugins/compression.rb +5 -3
- data/lib/httpx/plugins/cookies/jar.rb +1 -1
- data/lib/httpx/plugins/digest_authentication.rb +4 -4
- data/lib/httpx/plugins/expect.rb +7 -3
- data/lib/httpx/plugins/grpc/message.rb +2 -2
- data/lib/httpx/plugins/grpc.rb +3 -3
- data/lib/httpx/plugins/h2c.rb +7 -3
- data/lib/httpx/plugins/internal_telemetry.rb +8 -8
- data/lib/httpx/plugins/multipart/decoder.rb +187 -0
- data/lib/httpx/plugins/multipart/mime_type_detector.rb +3 -3
- data/lib/httpx/plugins/multipart/part.rb +2 -2
- data/lib/httpx/plugins/multipart.rb +16 -2
- data/lib/httpx/plugins/ntlm_authentication.rb +4 -4
- data/lib/httpx/plugins/proxy/ssh.rb +11 -4
- data/lib/httpx/plugins/proxy.rb +6 -4
- data/lib/httpx/plugins/response_cache/store.rb +55 -0
- data/lib/httpx/plugins/response_cache.rb +88 -0
- data/lib/httpx/plugins/retries.rb +36 -14
- data/lib/httpx/plugins/stream.rb +3 -4
- data/lib/httpx/pool.rb +39 -13
- data/lib/httpx/registry.rb +1 -1
- data/lib/httpx/request.rb +12 -13
- data/lib/httpx/resolver/https.rb +5 -7
- data/lib/httpx/resolver/native.rb +4 -2
- data/lib/httpx/resolver/resolver_mixin.rb +2 -1
- data/lib/httpx/resolver/system.rb +2 -0
- data/lib/httpx/resolver.rb +2 -2
- data/lib/httpx/response.rb +60 -44
- data/lib/httpx/selector.rb +16 -19
- data/lib/httpx/session.rb +22 -15
- data/lib/httpx/session2.rb +1 -1
- data/lib/httpx/timers.rb +84 -0
- data/lib/httpx/transcoder/body.rb +2 -1
- data/lib/httpx/transcoder/form.rb +20 -0
- data/lib/httpx/transcoder/json.rb +12 -0
- data/lib/httpx/transcoder.rb +62 -1
- data/lib/httpx/utils.rb +10 -2
- data/lib/httpx/version.rb +1 -1
- data/lib/httpx.rb +1 -0
- data/sig/buffer.rbs +2 -2
- data/sig/chainable.rbs +7 -1
- data/sig/connection/http1.rbs +15 -4
- data/sig/connection/http2.rbs +19 -5
- data/sig/connection.rbs +15 -9
- data/sig/headers.rbs +19 -18
- data/sig/options.rbs +13 -5
- data/sig/parser/http1.rbs +3 -3
- data/sig/plugins/aws_sdk_authentication.rbs +22 -4
- data/sig/plugins/aws_sigv4.rbs +12 -3
- data/sig/plugins/basic_authentication.rbs +1 -1
- data/sig/plugins/multipart.rbs +64 -8
- data/sig/plugins/proxy.rbs +6 -6
- data/sig/plugins/response_cache.rbs +35 -0
- data/sig/plugins/retries.rbs +3 -0
- data/sig/pool.rbs +6 -0
- data/sig/request.rbs +11 -8
- data/sig/resolver/native.rbs +2 -1
- data/sig/resolver/resolver_mixin.rbs +1 -1
- data/sig/resolver/system.rbs +3 -1
- data/sig/response.rbs +11 -4
- data/sig/selector.rbs +8 -6
- data/sig/session.rbs +8 -14
- data/sig/timers.rbs +32 -0
- data/sig/transcoder/form.rbs +1 -0
- data/sig/transcoder/json.rbs +1 -0
- data/sig/transcoder.rbs +5 -4
- data/sig/utils.rbs +4 -0
- metadata +18 -17
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module HTTPX
|
4
|
+
module Plugins
|
5
|
+
#
|
6
|
+
# This plugin adds support for retrying requests when certain errors happen.
|
7
|
+
#
|
8
|
+
# https://gitlab.com/honeyryderchuck/httpx/wikis/Response-Cache
|
9
|
+
#
|
10
|
+
module ResponseCache
|
11
|
+
CACHEABLE_VERBS = %i[get head].freeze
|
12
|
+
private_constant :CACHEABLE_VERBS
|
13
|
+
|
14
|
+
class << self
|
15
|
+
def load_dependencies(*)
|
16
|
+
require_relative "response_cache/store"
|
17
|
+
end
|
18
|
+
|
19
|
+
def cacheable_request?(request)
|
20
|
+
CACHEABLE_VERBS.include?(request.verb)
|
21
|
+
end
|
22
|
+
|
23
|
+
def cacheable_response?(response)
|
24
|
+
response.is_a?(Response) &&
|
25
|
+
# partial responses shall not be cached, only full ones.
|
26
|
+
response.status != 206 && (
|
27
|
+
response.headers.key?("etag") || response.headers.key?("last-modified-at")
|
28
|
+
)
|
29
|
+
end
|
30
|
+
|
31
|
+
def cached_response?(response)
|
32
|
+
response.is_a?(Response) && response.status == 304
|
33
|
+
end
|
34
|
+
|
35
|
+
def extra_options(options)
|
36
|
+
options.merge(response_cache_store: Store.new)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
module OptionsMethods
|
41
|
+
def option_response_cache_store(value)
|
42
|
+
raise TypeError, "must be an instance of #{Store}" unless value.is_a?(Store)
|
43
|
+
|
44
|
+
value
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
module InstanceMethods
|
49
|
+
def clear_response_cache
|
50
|
+
@options.response_cache_store.clear
|
51
|
+
end
|
52
|
+
|
53
|
+
def build_request(*)
|
54
|
+
request = super
|
55
|
+
return request unless ResponseCache.cacheable_request?(request) && @options.response_cache_store.cached?(request.uri)
|
56
|
+
|
57
|
+
@options.response_cache_store.prepare(request)
|
58
|
+
|
59
|
+
request
|
60
|
+
end
|
61
|
+
|
62
|
+
def fetch_response(request, *)
|
63
|
+
response = super
|
64
|
+
|
65
|
+
if response && ResponseCache.cached_response?(response)
|
66
|
+
log { "returning cached response for #{request.uri}" }
|
67
|
+
cached_response = @options.response_cache_store.lookup(request.uri)
|
68
|
+
|
69
|
+
response.copy_from_cached(cached_response)
|
70
|
+
end
|
71
|
+
|
72
|
+
@options.response_cache_store.cache(request.uri, response) if response && ResponseCache.cacheable_response?(response)
|
73
|
+
|
74
|
+
response
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
module ResponseMethods
|
79
|
+
def copy_from_cached(other)
|
80
|
+
@body = other.body
|
81
|
+
|
82
|
+
@body.__send__(:rewind)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
register_plugin :response_cache, ResponseCache
|
87
|
+
end
|
88
|
+
end
|
@@ -12,19 +12,29 @@ module HTTPX
|
|
12
12
|
# TODO: pass max_retries in a configure/load block
|
13
13
|
|
14
14
|
IDEMPOTENT_METHODS = %i[get options head put delete].freeze
|
15
|
-
RETRYABLE_ERRORS = [
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
15
|
+
RETRYABLE_ERRORS = [
|
16
|
+
IOError,
|
17
|
+
EOFError,
|
18
|
+
Errno::ECONNRESET,
|
19
|
+
Errno::ECONNABORTED,
|
20
|
+
Errno::EPIPE,
|
21
|
+
Errno::EINVAL,
|
22
|
+
Errno::ETIMEDOUT,
|
23
|
+
Parser::Error,
|
24
|
+
TLSError,
|
25
|
+
TimeoutError,
|
26
|
+
Connection::HTTP2::GoawayError,
|
27
|
+
].freeze
|
28
|
+
DEFAULT_JITTER = ->(interval) { interval * (0.5 * (1 + rand)) }
|
29
|
+
|
30
|
+
if ENV.key?("HTTPX_NO_JITTER")
|
31
|
+
def self.extra_options(options)
|
32
|
+
options.merge(max_retries: MAX_RETRIES)
|
33
|
+
end
|
34
|
+
else
|
35
|
+
def self.extra_options(options)
|
36
|
+
options.merge(max_retries: MAX_RETRIES, retry_jitter: DEFAULT_JITTER)
|
37
|
+
end
|
28
38
|
end
|
29
39
|
|
30
40
|
module OptionsMethods
|
@@ -38,6 +48,13 @@ module HTTPX
|
|
38
48
|
value
|
39
49
|
end
|
40
50
|
|
51
|
+
def option_retry_jitter(value)
|
52
|
+
# return early if callable
|
53
|
+
raise TypeError, ":retry_jitter must be callable" unless value.respond_to?(:call)
|
54
|
+
|
55
|
+
value
|
56
|
+
end
|
57
|
+
|
41
58
|
def option_max_retries(value)
|
42
59
|
num = Integer(value)
|
43
60
|
raise TypeError, ":max_retries must be positive" unless num.positive?
|
@@ -87,10 +104,15 @@ module HTTPX
|
|
87
104
|
retry_after = retry_after.call(request, response) if retry_after.respond_to?(:call)
|
88
105
|
|
89
106
|
if retry_after
|
107
|
+
# apply jitter
|
108
|
+
if (jitter = request.options.retry_jitter)
|
109
|
+
retry_after = jitter.call(retry_after)
|
110
|
+
end
|
90
111
|
|
112
|
+
retry_start = Utils.now
|
91
113
|
log { "retrying after #{retry_after} secs..." }
|
92
114
|
pool.after(retry_after) do
|
93
|
-
log { "retrying!!" }
|
115
|
+
log { "retrying (elapsed time: #{Utils.elapsed_time(retry_start)})!!" }
|
94
116
|
connection = find_connection(request, connections, options)
|
95
117
|
connection.send(request)
|
96
118
|
end
|
data/lib/httpx/plugins/stream.rb
CHANGED
@@ -6,11 +6,10 @@ module HTTPX
|
|
6
6
|
@request = request
|
7
7
|
@session = session
|
8
8
|
@connections = connections
|
9
|
-
@options = @request.options
|
10
9
|
end
|
11
10
|
|
12
11
|
def each(&block)
|
13
|
-
return enum_for(__method__) unless
|
12
|
+
return enum_for(__method__) unless block
|
14
13
|
|
15
14
|
raise Error, "response already streamed" if @response
|
16
15
|
|
@@ -72,7 +71,7 @@ module HTTPX
|
|
72
71
|
private
|
73
72
|
|
74
73
|
def response
|
75
|
-
@session.__send__(:receive_requests, [@request], @connections
|
74
|
+
@session.__send__(:receive_requests, [@request], @connections) until @request.response
|
76
75
|
|
77
76
|
@request.response
|
78
77
|
end
|
@@ -106,7 +105,7 @@ module HTTPX
|
|
106
105
|
|
107
106
|
request = requests.first
|
108
107
|
|
109
|
-
connections = _send_requests(requests
|
108
|
+
connections = _send_requests(requests)
|
110
109
|
|
111
110
|
StreamResponse.new(request, self, connections)
|
112
111
|
end
|
data/lib/httpx/pool.rb
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "forwardable"
|
4
|
-
require "timers"
|
5
4
|
require "httpx/selector"
|
6
5
|
require "httpx/connection"
|
7
6
|
require "httpx/resolver"
|
8
7
|
|
9
8
|
module HTTPX
|
10
9
|
class Pool
|
10
|
+
using ArrayExtensions
|
11
11
|
extend Forwardable
|
12
12
|
|
13
13
|
def_delegator :@timers, :after
|
@@ -15,7 +15,7 @@ module HTTPX
|
|
15
15
|
def initialize
|
16
16
|
@resolvers = {}
|
17
17
|
@_resolver_ios = {}
|
18
|
-
@timers = Timers
|
18
|
+
@timers = Timers.new
|
19
19
|
@selector = Selector.new
|
20
20
|
@connections = []
|
21
21
|
@connected_connections = 0
|
@@ -27,15 +27,18 @@ module HTTPX
|
|
27
27
|
|
28
28
|
def next_tick
|
29
29
|
catch(:jump_tick) do
|
30
|
-
timeout =
|
30
|
+
timeout = next_timeout
|
31
31
|
if timeout && timeout.negative?
|
32
32
|
@timers.fire
|
33
33
|
throw(:jump_tick)
|
34
34
|
end
|
35
35
|
|
36
|
-
|
37
|
-
|
38
|
-
|
36
|
+
begin
|
37
|
+
@selector.select(timeout, &:call)
|
38
|
+
@timers.fire
|
39
|
+
rescue TimeoutError => e
|
40
|
+
@timers.fire(e)
|
41
|
+
end
|
39
42
|
end
|
40
43
|
rescue StandardError => e
|
41
44
|
@connections.each do |connection|
|
@@ -64,6 +67,16 @@ module HTTPX
|
|
64
67
|
connection.on(:open) do
|
65
68
|
@connected_connections += 1
|
66
69
|
end
|
70
|
+
connection.on(:activate) do
|
71
|
+
select_connection(connection)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def deactivate(connections)
|
76
|
+
connections.each do |connection|
|
77
|
+
connection.deactivate
|
78
|
+
deselect_connection(connection) if connection.state == :inactive
|
79
|
+
end
|
67
80
|
end
|
68
81
|
|
69
82
|
# opens a connection to the IP reachable through +uri+.
|
@@ -81,7 +94,7 @@ module HTTPX
|
|
81
94
|
def resolve_connection(connection)
|
82
95
|
@connections << connection unless @connections.include?(connection)
|
83
96
|
|
84
|
-
if connection.addresses || connection.
|
97
|
+
if connection.addresses || connection.open?
|
85
98
|
#
|
86
99
|
# there are two cases in which we want to activate initialization of
|
87
100
|
# connection immediately:
|
@@ -98,7 +111,7 @@ module HTTPX
|
|
98
111
|
resolver << connection
|
99
112
|
return if resolver.empty?
|
100
113
|
|
101
|
-
@_resolver_ios[resolver] ||=
|
114
|
+
@_resolver_ios[resolver] ||= select_connection(resolver)
|
102
115
|
end
|
103
116
|
|
104
117
|
def on_resolver_connection(connection)
|
@@ -107,7 +120,7 @@ module HTTPX
|
|
107
120
|
end
|
108
121
|
return register_connection(connection) unless found_connection
|
109
122
|
|
110
|
-
if found_connection.
|
123
|
+
if found_connection.open?
|
111
124
|
coalesce_connections(found_connection, connection)
|
112
125
|
throw(:coalesced, found_connection)
|
113
126
|
else
|
@@ -129,7 +142,7 @@ module HTTPX
|
|
129
142
|
|
130
143
|
@resolvers.delete(resolver_type)
|
131
144
|
|
132
|
-
|
145
|
+
deselect_connection(resolver)
|
133
146
|
@_resolver_ios.delete(resolver)
|
134
147
|
resolver.close unless resolver.closed?
|
135
148
|
end
|
@@ -140,7 +153,7 @@ module HTTPX
|
|
140
153
|
# consider it connected already.
|
141
154
|
@connected_connections += 1
|
142
155
|
end
|
143
|
-
|
156
|
+
select_connection(connection)
|
144
157
|
connection.on(:close) do
|
145
158
|
unregister_connection(connection)
|
146
159
|
end
|
@@ -148,10 +161,18 @@ module HTTPX
|
|
148
161
|
|
149
162
|
def unregister_connection(connection)
|
150
163
|
@connections.delete(connection)
|
151
|
-
|
164
|
+
deselect_connection(connection)
|
152
165
|
@connected_connections -= 1
|
153
166
|
end
|
154
167
|
|
168
|
+
def select_connection(connection)
|
169
|
+
@selector.register(connection)
|
170
|
+
end
|
171
|
+
|
172
|
+
def deselect_connection(connection)
|
173
|
+
@selector.deregister(connection)
|
174
|
+
end
|
175
|
+
|
155
176
|
def coalesce_connections(conn1, conn2)
|
156
177
|
if conn1.coalescable?(conn2)
|
157
178
|
conn1.merge(conn2)
|
@@ -162,7 +183,11 @@ module HTTPX
|
|
162
183
|
end
|
163
184
|
|
164
185
|
def next_timeout
|
165
|
-
|
186
|
+
[
|
187
|
+
@timers.wait_interval,
|
188
|
+
*@resolvers.values.reject(&:closed?).filter_map(&:timeout),
|
189
|
+
*@connections.filter_map(&:timeout),
|
190
|
+
].compact.min
|
166
191
|
end
|
167
192
|
|
168
193
|
def find_resolver_for(connection)
|
@@ -172,6 +197,7 @@ module HTTPX
|
|
172
197
|
|
173
198
|
@resolvers[resolver_type] ||= begin
|
174
199
|
resolver = resolver_type.new(connection_options)
|
200
|
+
resolver.pool = self if resolver.respond_to?(:pool=)
|
175
201
|
resolver.on(:resolve, &method(:on_resolver_connection))
|
176
202
|
resolver.on(:error, &method(:on_resolver_error))
|
177
203
|
resolver.on(:close) { on_resolver_close(resolver) }
|
data/lib/httpx/registry.rb
CHANGED
data/lib/httpx/request.rb
CHANGED
@@ -41,16 +41,15 @@ module HTTPX
|
|
41
41
|
|
42
42
|
def_delegator :@body, :empty?
|
43
43
|
|
44
|
-
def_delegator :@body, :chunk!
|
45
|
-
|
46
44
|
def initialize(verb, uri, options = {})
|
47
45
|
@verb = verb.to_s.downcase.to_sym
|
48
46
|
@options = Options.new(options)
|
49
47
|
@uri = Utils.to_uri(uri)
|
50
48
|
if @uri.relative?
|
51
|
-
|
49
|
+
origin = @options.origin
|
50
|
+
raise(Error, "invalid URI: #{@uri}") unless origin
|
52
51
|
|
53
|
-
@uri =
|
52
|
+
@uri = origin.merge(@uri)
|
54
53
|
end
|
55
54
|
|
56
55
|
raise(Error, "unknown method: #{verb}") unless METHODS.include?(@verb)
|
@@ -98,7 +97,7 @@ module HTTPX
|
|
98
97
|
def response=(response)
|
99
98
|
return unless response
|
100
99
|
|
101
|
-
if response.status == 100
|
100
|
+
if response.is_a?(Response) && response.status == 100
|
102
101
|
@informational_status = response.status
|
103
102
|
return
|
104
103
|
end
|
@@ -149,16 +148,16 @@ module HTTPX
|
|
149
148
|
# :nocov:
|
150
149
|
def inspect
|
151
150
|
"#<HTTPX::Request:#{object_id} " \
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
151
|
+
"#{@verb.to_s.upcase} " \
|
152
|
+
"#{uri} " \
|
153
|
+
"@headers=#{@headers} " \
|
154
|
+
"@body=#{@body}>"
|
156
155
|
end
|
157
156
|
# :nocov:
|
158
157
|
|
159
158
|
class Body < SimpleDelegator
|
160
159
|
class << self
|
161
|
-
def new(
|
160
|
+
def new(_, options)
|
162
161
|
return options.body if options.body.is_a?(self)
|
163
162
|
|
164
163
|
super
|
@@ -182,7 +181,7 @@ module HTTPX
|
|
182
181
|
end
|
183
182
|
|
184
183
|
def each(&block)
|
185
|
-
return enum_for(__method__) unless
|
184
|
+
return enum_for(__method__) unless block
|
186
185
|
return if @body.nil?
|
187
186
|
|
188
187
|
body = stream(@body)
|
@@ -223,7 +222,7 @@ module HTTPX
|
|
223
222
|
def unbounded_body?
|
224
223
|
return @unbounded_body if defined?(@unbounded_body)
|
225
224
|
|
226
|
-
@unbounded_body = (chunked? || @body.bytesize == Float::INFINITY)
|
225
|
+
@unbounded_body = !@body.nil? && (chunked? || @body.bytesize == Float::INFINITY)
|
227
226
|
end
|
228
227
|
|
229
228
|
def chunked?
|
@@ -237,7 +236,7 @@ module HTTPX
|
|
237
236
|
# :nocov:
|
238
237
|
def inspect
|
239
238
|
"#<HTTPX::Request::Body:#{object_id} " \
|
240
|
-
|
239
|
+
"#{unbounded_body? ? "stream" : "@bytesize=#{bytesize}"}>"
|
241
240
|
end
|
242
241
|
# :nocov:
|
243
242
|
end
|
data/lib/httpx/resolver/https.rb
CHANGED
@@ -24,7 +24,9 @@ module HTTPX
|
|
24
24
|
record_types: RECORD_TYPES.keys,
|
25
25
|
}.freeze
|
26
26
|
|
27
|
-
def_delegators :@resolver_connection, :connecting?, :to_io, :call, :close
|
27
|
+
def_delegators :@resolver_connection, :state, :connecting?, :to_io, :call, :close
|
28
|
+
|
29
|
+
attr_writer :pool
|
28
30
|
|
29
31
|
def initialize(options)
|
30
32
|
@options = Options.new(options)
|
@@ -63,15 +65,11 @@ module HTTPX
|
|
63
65
|
|
64
66
|
private
|
65
67
|
|
66
|
-
def pool
|
67
|
-
Thread.current[:httpx_connection_pool] ||= Pool.new
|
68
|
-
end
|
69
|
-
|
70
68
|
def resolver_connection
|
71
|
-
@resolver_connection ||= pool.find_connection(@uri, @options) || begin
|
69
|
+
@resolver_connection ||= @pool.find_connection(@uri, @options) || begin
|
72
70
|
@building_connection = true
|
73
71
|
connection = @options.connection_class.new("ssl", @uri, @options.merge(ssl: { alpn_protocols: %w[h2] }))
|
74
|
-
pool.init_connection(connection, @options)
|
72
|
+
@pool.init_connection(connection, @options)
|
75
73
|
emit_addresses(connection, @uri_addresses)
|
76
74
|
@building_connection = false
|
77
75
|
connection
|
@@ -47,6 +47,8 @@ module HTTPX
|
|
47
47
|
|
48
48
|
def_delegator :@connections, :empty?
|
49
49
|
|
50
|
+
attr_reader :state
|
51
|
+
|
50
52
|
def initialize(options)
|
51
53
|
@options = Options.new(options)
|
52
54
|
@ns_index = 0
|
@@ -120,7 +122,7 @@ module HTTPX
|
|
120
122
|
def timeout
|
121
123
|
return if @connections.empty?
|
122
124
|
|
123
|
-
@start_timeout =
|
125
|
+
@start_timeout = Utils.now
|
124
126
|
hosts = @queries.keys
|
125
127
|
@timeouts.values_at(*hosts).reject(&:empty?).map(&:first).min
|
126
128
|
end
|
@@ -140,7 +142,7 @@ module HTTPX
|
|
140
142
|
def do_retry
|
141
143
|
return if @queries.empty?
|
142
144
|
|
143
|
-
loop_time =
|
145
|
+
loop_time = Utils.elapsed_time(@start_timeout)
|
144
146
|
connections = []
|
145
147
|
queries = {}
|
146
148
|
while (query = @queries.shift)
|
@@ -9,7 +9,7 @@ module HTTPX
|
|
9
9
|
include Callbacks
|
10
10
|
include Loggable
|
11
11
|
|
12
|
-
CHECK_IF_IP =
|
12
|
+
CHECK_IF_IP = lambda do |name|
|
13
13
|
begin
|
14
14
|
IPAddr.new(name)
|
15
15
|
true
|
@@ -55,6 +55,7 @@ module HTTPX
|
|
55
55
|
return if ips.empty?
|
56
56
|
|
57
57
|
ips.map { |ip| IPAddr.new(ip) }
|
58
|
+
rescue IOError
|
58
59
|
end
|
59
60
|
|
60
61
|
def emit_resolve_error(connection, hostname = connection.origin.host, ex = nil)
|
data/lib/httpx/resolver.rb
CHANGED
@@ -26,14 +26,14 @@ module HTTPX
|
|
26
26
|
module_function
|
27
27
|
|
28
28
|
def cached_lookup(hostname)
|
29
|
-
now =
|
29
|
+
now = Utils.now
|
30
30
|
@lookup_mutex.synchronize do
|
31
31
|
lookup(hostname, now)
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
35
|
def cached_lookup_set(hostname, entries)
|
36
|
-
now =
|
36
|
+
now = Utils.now
|
37
37
|
entries.each do |entry|
|
38
38
|
entry["TTL"] += now
|
39
39
|
end
|