httpx 1.8.4 → 1.9.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/doc/release_notes/1_8_1.md +1 -1
- data/doc/release_notes/1_8_2.md +4 -4
- data/doc/release_notes/1_8_3.md +3 -5
- data/doc/release_notes/1_8_4.md +1 -1
- data/doc/release_notes/1_9_0.md +75 -0
- data/doc/release_notes/1_9_1.md +32 -0
- data/lib/httpx/adapters/faraday.rb +1 -1
- data/lib/httpx/adapters/webmock.rb +15 -2
- data/lib/httpx/altsvc.rb +29 -15
- data/lib/httpx/chainable.rb +4 -1
- data/lib/httpx/connection/http1.rb +34 -35
- data/lib/httpx/connection/http2.rb +146 -33
- data/lib/httpx/connection.rb +282 -162
- data/lib/httpx/headers.rb +2 -2
- data/lib/httpx/io/tcp.rb +42 -21
- data/lib/httpx/options.rb +86 -35
- data/lib/httpx/parser/http1.rb +3 -6
- data/lib/httpx/plugins/auth/digest.rb +1 -2
- data/lib/httpx/plugins/auth.rb +11 -2
- data/lib/httpx/plugins/aws_sdk_authentication.rb +7 -3
- data/lib/httpx/plugins/aws_sigv4.rb +1 -1
- data/lib/httpx/plugins/basic_auth.rb +2 -0
- data/lib/httpx/plugins/cache.rb +1 -1
- data/lib/httpx/plugins/callbacks.rb +8 -6
- data/lib/httpx/plugins/circuit_breaker.rb +1 -0
- data/lib/httpx/plugins/content_digest.rb +3 -5
- data/lib/httpx/plugins/digest_auth.rb +2 -0
- data/lib/httpx/plugins/expect.rb +10 -1
- data/lib/httpx/plugins/fiber_concurrency.rb +59 -16
- data/lib/httpx/plugins/follow_redirects.rb +1 -1
- data/lib/httpx/plugins/grpc.rb +21 -0
- data/lib/httpx/plugins/h2c.rb +12 -11
- data/lib/httpx/plugins/hedging.rb +284 -0
- data/lib/httpx/plugins/ntlm_auth.rb +5 -3
- data/lib/httpx/plugins/ntlm_v2_auth.rb +5 -3
- data/lib/httpx/plugins/oauth.rb +2 -2
- data/lib/httpx/plugins/proxy/http.rb +67 -26
- data/lib/httpx/plugins/proxy/socks5.rb +4 -4
- data/lib/httpx/plugins/proxy/ssh.rb +30 -11
- data/lib/httpx/plugins/proxy.rb +68 -54
- data/lib/httpx/plugins/push_promise.rb +4 -2
- data/lib/httpx/plugins/query.rb +1 -0
- data/lib/httpx/plugins/retries.rb +2 -2
- data/lib/httpx/plugins/server_sent_events.rb +1 -0
- data/lib/httpx/plugins/ssrf_filter.rb +1 -1
- data/lib/httpx/plugins/stream.rb +12 -10
- data/lib/httpx/plugins/stream_bidi.rb +4 -0
- data/lib/httpx/plugins/tracing.rb +99 -11
- data/lib/httpx/plugins/upgrade/h2.rb +3 -3
- data/lib/httpx/plugins/upgrade.rb +2 -0
- data/lib/httpx/plugins/webdav.rb +8 -0
- data/lib/httpx/request/body.rb +2 -1
- data/lib/httpx/request.rb +6 -6
- data/lib/httpx/resolver/https.rb +3 -2
- data/lib/httpx/resolver/native.rb +19 -9
- data/lib/httpx/resolver/resolver.rb +2 -2
- data/lib/httpx/resolver/system.rb +4 -0
- data/lib/httpx/resolver.rb +10 -6
- data/lib/httpx/response.rb +19 -7
- data/lib/httpx/selector.rb +111 -10
- data/lib/httpx/session.rb +36 -10
- data/lib/httpx/transcoder/json.rb +1 -1
- data/lib/httpx/version.rb +1 -1
- data/lib/httpx.rb +1 -0
- data/sig/altsvc.rbs +3 -3
- data/sig/callbacks.rbs +1 -0
- data/sig/chainable.rbs +3 -1
- data/sig/connection/http1.rbs +4 -2
- data/sig/connection/http2.rbs +23 -17
- data/sig/connection.rbs +29 -7
- data/sig/headers.rbs +1 -1
- data/sig/httpx.rbs +2 -0
- data/sig/io/tcp.rbs +5 -0
- data/sig/options.rbs +43 -12
- data/sig/parser/http1.rbs +1 -1
- data/sig/plugins/auth/digest.rbs +0 -1
- data/sig/plugins/auth.rbs +12 -5
- data/sig/plugins/expect.rbs +6 -0
- data/sig/plugins/fiber_concurrency.rbs +10 -1
- data/sig/plugins/hedging.rbs +44 -0
- data/sig/plugins/proxy/http.rbs +9 -2
- data/sig/plugins/proxy.rbs +3 -2
- data/sig/plugins/retries.rbs +2 -2
- data/sig/plugins/stream_bidi.rbs +0 -2
- data/sig/plugins/tracing.rbs +22 -5
- data/sig/request/body.rbs +1 -1
- data/sig/resolver/entry.rbs +2 -2
- data/sig/resolver/https.rbs +2 -0
- data/sig/resolver/native.rbs +3 -0
- data/sig/resolver/resolver.rbs +1 -1
- data/sig/resolver/system.rbs +2 -0
- data/sig/resolver.rbs +1 -1
- data/sig/response.rbs +1 -2
- data/sig/selector.rbs +17 -3
- data/sig/session.rbs +8 -6
- metadata +7 -1
|
@@ -63,13 +63,21 @@ module HTTPX::Plugins
|
|
|
63
63
|
end
|
|
64
64
|
|
|
65
65
|
module RequestMethods
|
|
66
|
+
# time at which a request started being buffered for sending.
|
|
66
67
|
attr_accessor :init_time
|
|
67
68
|
|
|
69
|
+
# when not nil, it means this request was sent to a non-open connection, and contains how much time it took
|
|
70
|
+
# the connection to connect.
|
|
71
|
+
attr_accessor :handshake_time
|
|
72
|
+
|
|
73
|
+
# time at which the request was first handed to a connection, or last moved back to waiting for one.
|
|
74
|
+
attr_accessor :enqueue_time
|
|
75
|
+
|
|
68
76
|
# intercepts request initialization to inject the tracing logic.
|
|
69
77
|
def initialize(*)
|
|
70
78
|
super
|
|
71
79
|
|
|
72
|
-
@init_time = nil
|
|
80
|
+
@init_time = @handshake_time = @enqueue_time = nil
|
|
73
81
|
|
|
74
82
|
tracer = @options.tracer
|
|
75
83
|
|
|
@@ -79,12 +87,15 @@ module HTTPX::Plugins
|
|
|
79
87
|
tracer.reset(self)
|
|
80
88
|
|
|
81
89
|
# request is reset when it's retried.
|
|
82
|
-
@init_time = nil
|
|
90
|
+
@init_time = @handshake_time = nil
|
|
91
|
+
|
|
92
|
+
# going back to idle means waiting to be sent again.
|
|
93
|
+
@enqueue_time = ::Time.now.utc
|
|
83
94
|
end
|
|
84
95
|
on(:headers) do
|
|
85
96
|
# the usual request init time (when not including the connection handshake)
|
|
86
97
|
# should be the time the request is buffered the first time.
|
|
87
|
-
@init_time
|
|
98
|
+
@init_time = calculate_init_time
|
|
88
99
|
|
|
89
100
|
tracer.start(self)
|
|
90
101
|
end
|
|
@@ -92,15 +103,31 @@ module HTTPX::Plugins
|
|
|
92
103
|
end
|
|
93
104
|
|
|
94
105
|
def response=(*)
|
|
95
|
-
#
|
|
96
|
-
# However, there are situations where connection initialization fails.
|
|
106
|
+
# There are situations where connection initialization fails.
|
|
97
107
|
# Example is the :ssrf_filter plugin, which raises an error on
|
|
98
108
|
# initialize if the host is an IP which matches against the known set.
|
|
99
109
|
# in such cases, we'll just set here right here.
|
|
100
|
-
@init_time ||=
|
|
110
|
+
@init_time ||= calculate_init_time
|
|
101
111
|
|
|
102
112
|
super
|
|
103
113
|
end
|
|
114
|
+
|
|
115
|
+
private
|
|
116
|
+
|
|
117
|
+
def calculate_init_time
|
|
118
|
+
init_time = ::Time.now.utc
|
|
119
|
+
|
|
120
|
+
return init_time unless (handshake_time = @handshake_time)
|
|
121
|
+
|
|
122
|
+
init_time -= handshake_time
|
|
123
|
+
|
|
124
|
+
enqueue_time = @enqueue_time
|
|
125
|
+
|
|
126
|
+
# handshake time is measured for the connection, and may happen before the request was sent to it.
|
|
127
|
+
return init_time unless enqueue_time && init_time < enqueue_time
|
|
128
|
+
|
|
129
|
+
enqueue_time
|
|
130
|
+
end
|
|
104
131
|
end
|
|
105
132
|
|
|
106
133
|
# Connection mixin
|
|
@@ -111,12 +138,20 @@ module HTTPX::Plugins
|
|
|
111
138
|
@init_time = nil
|
|
112
139
|
end
|
|
113
140
|
|
|
114
|
-
def
|
|
115
|
-
|
|
116
|
-
|
|
141
|
+
def send(request)
|
|
142
|
+
# requests may be rerouted to other connections (i.e. when coalescing), so only the first
|
|
143
|
+
# connection the request is handed to marks it.
|
|
144
|
+
request.enqueue_time ||= ::Time.now.utc
|
|
145
|
+
|
|
146
|
+
super
|
|
147
|
+
end
|
|
117
148
|
|
|
118
|
-
|
|
119
|
-
|
|
149
|
+
def send_request_to_parser(request, *)
|
|
150
|
+
if connecting? && @init_time
|
|
151
|
+
# at this point, the connection has connected, but hasn't yet transitioned to :open,
|
|
152
|
+
# so it's the time the requests which caused this connection to connect, are finally being
|
|
153
|
+
# sent to the parser, so handshake time should factor into the span time.
|
|
154
|
+
request.handshake_time ||= ::Time.now.utc - @init_time
|
|
120
155
|
end
|
|
121
156
|
|
|
122
157
|
super
|
|
@@ -135,8 +170,37 @@ module HTTPX::Plugins
|
|
|
135
170
|
@init_time = nil
|
|
136
171
|
end
|
|
137
172
|
|
|
173
|
+
def disconnect
|
|
174
|
+
return if @exhausted
|
|
175
|
+
|
|
176
|
+
return unless @current_session && @current_selector
|
|
177
|
+
|
|
178
|
+
# reset init time of connections abandoned while connecting.
|
|
179
|
+
@init_time = nil if connecting?
|
|
180
|
+
|
|
181
|
+
super
|
|
182
|
+
end
|
|
183
|
+
|
|
138
184
|
private
|
|
139
185
|
|
|
186
|
+
def handle_transition(*)
|
|
187
|
+
super
|
|
188
|
+
|
|
189
|
+
# no longer relevant after connection established.
|
|
190
|
+
@init_time = nil unless connecting?
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def handle_error(er, request = nil)
|
|
194
|
+
if connecting? && @init_time
|
|
195
|
+
# bookkeep handshake time back into pending requests, which were never initialized with it.
|
|
196
|
+
handshake_time = ::Time.now.utc - @init_time
|
|
197
|
+
request.handshake_time ||= handshake_time if request
|
|
198
|
+
@pending.each { |req| req.handshake_time ||= handshake_time }
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
super
|
|
202
|
+
end
|
|
203
|
+
|
|
140
204
|
def connect
|
|
141
205
|
@init_time ||= ::Time.now.utc
|
|
142
206
|
|
|
@@ -151,6 +215,30 @@ module HTTPX::Plugins
|
|
|
151
215
|
super
|
|
152
216
|
end
|
|
153
217
|
end
|
|
218
|
+
|
|
219
|
+
module HTTP2Methods
|
|
220
|
+
def initialize(*)
|
|
221
|
+
super
|
|
222
|
+
|
|
223
|
+
@handshake_init_time = ::Time.now.utc
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
private
|
|
227
|
+
|
|
228
|
+
def on_settings(*)
|
|
229
|
+
unless @handshake_completed
|
|
230
|
+
# pending requests must wait for the handshake completion
|
|
231
|
+
handshake_time = ::Time.now.utc - @handshake_init_time
|
|
232
|
+
|
|
233
|
+
@pending.each do |request|
|
|
234
|
+
request.handshake_time ||= 0.0
|
|
235
|
+
request.handshake_time += handshake_time
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
super
|
|
240
|
+
end
|
|
241
|
+
end
|
|
154
242
|
end
|
|
155
243
|
register_plugin :tracing, Tracing
|
|
156
244
|
end
|
|
@@ -25,7 +25,7 @@ module HTTPX
|
|
|
25
25
|
def interests
|
|
26
26
|
return super unless connecting? && @parser
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
try_connect
|
|
29
29
|
|
|
30
30
|
return @io.interests if connecting?
|
|
31
31
|
|
|
@@ -33,9 +33,9 @@ module HTTPX
|
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
def upgrade_to_h2
|
|
36
|
-
|
|
36
|
+
@parser.reset_requests
|
|
37
37
|
|
|
38
|
-
@parser = @options.http2_class.new(@write_buffer, @options)
|
|
38
|
+
@parser = @options.http2_class.new(@write_buffer, @pending, @options)
|
|
39
39
|
set_parser_callbacks(@parser)
|
|
40
40
|
@upgrade_protocol = "h2"
|
|
41
41
|
|
data/lib/httpx/plugins/webdav.rb
CHANGED
|
@@ -13,14 +13,18 @@ module HTTPX
|
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
module InstanceMethods
|
|
16
|
+
# sends a COPY WebDav request for +src+ and +dest+.
|
|
16
17
|
def copy(src, dest)
|
|
17
18
|
request("COPY", src, headers: { "destination" => @options.origin.merge(dest) })
|
|
18
19
|
end
|
|
19
20
|
|
|
21
|
+
# sends a MOVE WebDav request for +src+ and +dest+.
|
|
20
22
|
def move(src, dest)
|
|
21
23
|
request("MOVE", src, headers: { "destination" => @options.origin.merge(dest) })
|
|
22
24
|
end
|
|
23
25
|
|
|
26
|
+
# sends a LOCK WebDav request for +path+ (for the time set by +timeout+, when passed).
|
|
27
|
+
# it calls #unlock after the block is executed.
|
|
24
28
|
def lock(path, timeout: nil, &blk)
|
|
25
29
|
headers = {}
|
|
26
30
|
headers["timeout"] = if timeout && timeout.positive?
|
|
@@ -51,14 +55,17 @@ module HTTPX
|
|
|
51
55
|
response
|
|
52
56
|
end
|
|
53
57
|
|
|
58
|
+
# sends a UNLOCK WebDav request for +path+, using the given +lock_token+.
|
|
54
59
|
def unlock(path, lock_token)
|
|
55
60
|
request("UNLOCK", path, headers: { "lock-token" => lock_token })
|
|
56
61
|
end
|
|
57
62
|
|
|
63
|
+
# sends a MKCOL WebDav request for +dir+.
|
|
58
64
|
def mkcol(dir)
|
|
59
65
|
request("MKCOL", dir)
|
|
60
66
|
end
|
|
61
67
|
|
|
68
|
+
# sends a PROPFIND WebDav request for +path+.
|
|
62
69
|
def propfind(path, xml = nil)
|
|
63
70
|
body = case xml
|
|
64
71
|
when :acl
|
|
@@ -73,6 +80,7 @@ module HTTPX
|
|
|
73
80
|
request("PROPFIND", path, headers: { "depth" => "1" }, xml: body)
|
|
74
81
|
end
|
|
75
82
|
|
|
83
|
+
# sends a PROPPATCH WebDav request for +path+.
|
|
76
84
|
def proppatch(path, xml)
|
|
77
85
|
body = "<?xml version=\"1.0\"?>" \
|
|
78
86
|
"<D:propertyupdate xmlns:D=\"DAV:\" xmlns:Z=\"http://ns.example.com/standards/z39.50/\">#{xml}</D:propertyupdate>"
|
data/lib/httpx/request/body.rb
CHANGED
|
@@ -32,6 +32,7 @@ module HTTPX
|
|
|
32
32
|
@headers = h
|
|
33
33
|
@body = self.class.initialize_body(params)
|
|
34
34
|
@options = options.merge(params)
|
|
35
|
+
@unbounded_body = nil
|
|
35
36
|
|
|
36
37
|
if @body
|
|
37
38
|
if @options.compress_request_body && @headers.key?("content-encoding")
|
|
@@ -102,7 +103,7 @@ module HTTPX
|
|
|
102
103
|
|
|
103
104
|
# returns whether the body yields infinitely.
|
|
104
105
|
def unbounded_body?
|
|
105
|
-
return @unbounded_body
|
|
106
|
+
return @unbounded_body unless @unbounded_body.nil?
|
|
106
107
|
|
|
107
108
|
@unbounded_body = !@body.nil? && (chunked? || @body.bytesize == Float::INFINITY)
|
|
108
109
|
end
|
data/lib/httpx/request.rb
CHANGED
|
@@ -140,22 +140,22 @@ module HTTPX
|
|
|
140
140
|
|
|
141
141
|
# the read timeout defined for this request.
|
|
142
142
|
def read_timeout
|
|
143
|
-
@options.timeout
|
|
143
|
+
@options.timeout.read_timeout
|
|
144
144
|
end
|
|
145
145
|
|
|
146
146
|
# the write timeout defined for this request.
|
|
147
147
|
def write_timeout
|
|
148
|
-
@options.timeout
|
|
148
|
+
@options.timeout.write_timeout
|
|
149
149
|
end
|
|
150
150
|
|
|
151
151
|
# the request timeout defined for this request.
|
|
152
152
|
def request_timeout
|
|
153
|
-
@options.timeout
|
|
153
|
+
@options.timeout.request_timeout
|
|
154
154
|
end
|
|
155
155
|
|
|
156
156
|
# the total request timeout defined for this request.
|
|
157
157
|
def total_request_timeout
|
|
158
|
-
@options.timeout
|
|
158
|
+
@options.timeout.total_request_timeout
|
|
159
159
|
end
|
|
160
160
|
|
|
161
161
|
def persistent?
|
|
@@ -180,7 +180,7 @@ module HTTPX
|
|
|
180
180
|
end
|
|
181
181
|
|
|
182
182
|
def can_buffer?
|
|
183
|
-
@state != :done
|
|
183
|
+
@state != :done && @state != :expect
|
|
184
184
|
end
|
|
185
185
|
|
|
186
186
|
def started?
|
|
@@ -339,7 +339,7 @@ module HTTPX
|
|
|
339
339
|
|
|
340
340
|
# whether the request supports the 100-continue handshake and already processed the 100 response.
|
|
341
341
|
def expects?
|
|
342
|
-
@headers
|
|
342
|
+
@headers.key?("expect") && @headers.get("expect").include?("100-continue") && @informational_status == 100 && !@response
|
|
343
343
|
end
|
|
344
344
|
|
|
345
345
|
def set_timeout_callback(event, &callback)
|
data/lib/httpx/resolver/https.rb
CHANGED
|
@@ -32,7 +32,8 @@ module HTTPX
|
|
|
32
32
|
}.freeze
|
|
33
33
|
|
|
34
34
|
def_delegators :@resolver_connection, :connecting?, :to_io, :call, :close,
|
|
35
|
-
:closed?, :deactivate, :terminate, :inflight?, :handle_socket_timeout
|
|
35
|
+
:closed?, :deactivate, :terminate, :inflight?, :handle_socket_timeout,
|
|
36
|
+
:closed_for_select?
|
|
36
37
|
|
|
37
38
|
def initialize(_, options)
|
|
38
39
|
super
|
|
@@ -49,7 +50,7 @@ module HTTPX
|
|
|
49
50
|
end
|
|
50
51
|
|
|
51
52
|
def state
|
|
52
|
-
@resolver_connection
|
|
53
|
+
@resolver_connection&.state || :idle
|
|
53
54
|
end
|
|
54
55
|
|
|
55
56
|
def <<(connection)
|
|
@@ -38,12 +38,11 @@ module HTTPX
|
|
|
38
38
|
@search = Array(@resolver_options[:search]).map { |srch| srch.scan(/[^.]+/) }
|
|
39
39
|
@_timeouts = Array(@resolver_options[:timeouts])
|
|
40
40
|
@timeouts = Hash.new { |timeouts, host| timeouts[host] = @_timeouts.dup }
|
|
41
|
-
@name = nil
|
|
41
|
+
@name = @message_id = @timer = nil
|
|
42
42
|
@queries = {}
|
|
43
43
|
@read_buffer = "".b
|
|
44
44
|
@write_buffer = Buffer.new(@resolver_options[:packet_size])
|
|
45
45
|
@state = :idle
|
|
46
|
-
@timer = nil
|
|
47
46
|
end
|
|
48
47
|
|
|
49
48
|
def close
|
|
@@ -52,7 +51,7 @@ module HTTPX
|
|
|
52
51
|
|
|
53
52
|
def force_close(*)
|
|
54
53
|
@timer.cancel if @timer
|
|
55
|
-
@timer = @name = nil
|
|
54
|
+
@timer = @name = @message_id = nil
|
|
56
55
|
@queries.clear
|
|
57
56
|
@timeouts.clear
|
|
58
57
|
close
|
|
@@ -87,6 +86,10 @@ module HTTPX
|
|
|
87
86
|
end
|
|
88
87
|
end
|
|
89
88
|
|
|
89
|
+
def closed_for_select?
|
|
90
|
+
@state == :closed
|
|
91
|
+
end
|
|
92
|
+
|
|
90
93
|
def interests
|
|
91
94
|
case @state
|
|
92
95
|
when :idle
|
|
@@ -170,6 +173,7 @@ module HTTPX
|
|
|
170
173
|
if nameserver && @ns_index < nameserver.size
|
|
171
174
|
log { "resolver #{FAMILY_TYPES[@record_type]}: failed resolving on nameserver #{@nameserver[@ns_index - 1]} (#{e.message})" }
|
|
172
175
|
transition(:idle)
|
|
176
|
+
transition(:open)
|
|
173
177
|
@timeouts.clear
|
|
174
178
|
retry
|
|
175
179
|
else
|
|
@@ -195,7 +199,7 @@ module HTTPX
|
|
|
195
199
|
@timer = @current_selector.after(timeout) do
|
|
196
200
|
next unless @connections.include?(connection)
|
|
197
201
|
|
|
198
|
-
@timer = @name = nil
|
|
202
|
+
@timer = @name = @message_id = nil
|
|
199
203
|
|
|
200
204
|
do_retry(h, connection, timeout)
|
|
201
205
|
end
|
|
@@ -310,7 +314,13 @@ module HTTPX
|
|
|
310
314
|
end
|
|
311
315
|
|
|
312
316
|
def parse(buffer)
|
|
313
|
-
code, result = Resolver.decode_dns_answer(buffer)
|
|
317
|
+
code, result, message_id = Resolver.decode_dns_answer(buffer)
|
|
318
|
+
|
|
319
|
+
# discard late message answers for no longer inflight queries.
|
|
320
|
+
if message_id && message_id != @message_id
|
|
321
|
+
log { "resolver #{FAMILY_TYPES[@record_type]}: discarding answer for a query no longer in flight" }
|
|
322
|
+
return
|
|
323
|
+
end
|
|
314
324
|
|
|
315
325
|
case code
|
|
316
326
|
when :ok
|
|
@@ -392,7 +402,7 @@ module HTTPX
|
|
|
392
402
|
orig_name = name
|
|
393
403
|
# absolute name
|
|
394
404
|
name_labels = Resolv::DNS::Name.create(name).to_a
|
|
395
|
-
name = @queries.each_key.
|
|
405
|
+
name = @queries.each_key.find { |hname| name_labels == Resolv::DNS::Name.create(hname).to_a }
|
|
396
406
|
|
|
397
407
|
# probably a retried query for which there's an answer
|
|
398
408
|
unless name
|
|
@@ -462,11 +472,10 @@ module HTTPX
|
|
|
462
472
|
@queries[hostname] = connection
|
|
463
473
|
end
|
|
464
474
|
|
|
465
|
-
@name = hostname
|
|
466
|
-
|
|
467
475
|
log { "resolver #{FAMILY_TYPES[@record_type]}: query for #{hostname}" }
|
|
468
476
|
begin
|
|
469
477
|
@write_buffer << encode_dns_query(hostname)
|
|
478
|
+
@name = hostname
|
|
470
479
|
rescue Resolv::DNS::EncodeError => e
|
|
471
480
|
reset_hostname(hostname, connection: connection)
|
|
472
481
|
@connections.delete(connection)
|
|
@@ -479,6 +488,7 @@ module HTTPX
|
|
|
479
488
|
message_id = Resolver.generate_id
|
|
480
489
|
msg = Resolver.encode_dns_query(hostname, type: @record_type, message_id: message_id)
|
|
481
490
|
msg[0, 2] = [msg.size, message_id].pack("nn") if @socket_type == :tcp
|
|
491
|
+
@message_id = message_id
|
|
482
492
|
msg
|
|
483
493
|
end
|
|
484
494
|
|
|
@@ -574,7 +584,7 @@ module HTTPX
|
|
|
574
584
|
def reset_query
|
|
575
585
|
@timer.cancel
|
|
576
586
|
|
|
577
|
-
@timer = @name = nil
|
|
587
|
+
@timer = @name = @message_id = nil
|
|
578
588
|
end
|
|
579
589
|
|
|
580
590
|
def reset_hostname(hostname, connection: @queries.delete(hostname), reset_candidates: true)
|
|
@@ -29,9 +29,9 @@ module HTTPX
|
|
|
29
29
|
|
|
30
30
|
attr_reader :family, :options
|
|
31
31
|
|
|
32
|
-
attr_writer :
|
|
32
|
+
attr_writer :current_session
|
|
33
33
|
|
|
34
|
-
attr_accessor :multi
|
|
34
|
+
attr_accessor :current_selector, :multi
|
|
35
35
|
|
|
36
36
|
def initialize(family, options)
|
|
37
37
|
@family = family
|
data/lib/httpx/resolver.rb
CHANGED
|
@@ -51,16 +51,20 @@ module HTTPX
|
|
|
51
51
|
end
|
|
52
52
|
|
|
53
53
|
# no domain was found
|
|
54
|
-
return :no_domain_found if message.rcode == Resolv::DNS::RCode::NXDomain
|
|
54
|
+
return :no_domain_found, nil, message.id if message.rcode == Resolv::DNS::RCode::NXDomain
|
|
55
55
|
|
|
56
|
-
return :message_truncated if message.tc == 1
|
|
56
|
+
return :message_truncated, nil, message.id if message.tc == 1
|
|
57
57
|
|
|
58
58
|
if message.rcode != Resolv::DNS::RCode::NoError
|
|
59
59
|
case message.rcode
|
|
60
|
-
when Resolv::DNS::RCode::ServFail
|
|
61
|
-
|
|
60
|
+
when Resolv::DNS::RCode::ServFail,
|
|
61
|
+
# getaddrinfo also retries these errors, as they're not about the hostname being resolved,
|
|
62
|
+
# but the DNS resolver state.
|
|
63
|
+
Resolv::DNS::RCode::NotImp,
|
|
64
|
+
Resolv::DNS::RCode::Refused
|
|
65
|
+
return :retriable_error, message.rcode, message.id
|
|
62
66
|
else
|
|
63
|
-
return :dns_error, message.rcode
|
|
67
|
+
return :dns_error, message.rcode, message.id
|
|
64
68
|
end
|
|
65
69
|
end
|
|
66
70
|
|
|
@@ -85,7 +89,7 @@ module HTTPX
|
|
|
85
89
|
end
|
|
86
90
|
end
|
|
87
91
|
|
|
88
|
-
[:ok, addresses]
|
|
92
|
+
[:ok, addresses, message.id]
|
|
89
93
|
end
|
|
90
94
|
|
|
91
95
|
private
|
data/lib/httpx/response.rb
CHANGED
|
@@ -119,7 +119,6 @@ module HTTPX
|
|
|
119
119
|
# marks the response as finished, freezes the headers.
|
|
120
120
|
def finish!
|
|
121
121
|
@finished = true
|
|
122
|
-
@headers.freeze
|
|
123
122
|
@request.connection = nil
|
|
124
123
|
end
|
|
125
124
|
|
|
@@ -215,8 +214,7 @@ module HTTPX
|
|
|
215
214
|
|
|
216
215
|
# Helper class which decodes the HTTP "content-type" header.
|
|
217
216
|
class ContentType
|
|
218
|
-
|
|
219
|
-
CHARSET_RE = /;\s*charset=([^;]+)/i.freeze
|
|
217
|
+
SPLIT_PATTERN = /[;,]/.freeze
|
|
220
218
|
|
|
221
219
|
def initialize(header_value)
|
|
222
220
|
@header_value = header_value
|
|
@@ -250,11 +248,25 @@ module HTTPX
|
|
|
250
248
|
private
|
|
251
249
|
|
|
252
250
|
def load
|
|
253
|
-
|
|
254
|
-
|
|
251
|
+
if @header_value && !@header_value.empty?
|
|
252
|
+
m, c = @header_value.split(SPLIT_PATTERN, 2)
|
|
255
253
|
|
|
256
|
-
|
|
257
|
-
|
|
254
|
+
if m
|
|
255
|
+
@mime_type = m.strip
|
|
256
|
+
@mime_type.downcase
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
if c
|
|
260
|
+
c.strip!
|
|
261
|
+
c.delete_prefix!("charset=")
|
|
262
|
+
c.gsub!(/\A"(.*?)(?<!\\)"\z/) do
|
|
263
|
+
c2 = ::Regexp.last_match(1)
|
|
264
|
+
c2.gsub!(/\\(.)/, '\1')
|
|
265
|
+
c2
|
|
266
|
+
end
|
|
267
|
+
@charset = c
|
|
268
|
+
end
|
|
269
|
+
end
|
|
258
270
|
|
|
259
271
|
@initialized = true
|
|
260
272
|
end
|