httpx 1.5.1 → 1.6.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_6_0.md +50 -0
- data/doc/release_notes/1_6_1.md +17 -0
- data/lib/httpx/adapters/datadog.rb +23 -13
- data/lib/httpx/adapters/faraday.rb +14 -9
- data/lib/httpx/adapters/webmock.rb +1 -1
- data/lib/httpx/callbacks.rb +1 -1
- data/lib/httpx/connection/http1.rb +5 -6
- data/lib/httpx/connection/http2.rb +34 -18
- data/lib/httpx/connection.rb +19 -26
- data/lib/httpx/errors.rb +3 -1
- data/lib/httpx/io/ssl.rb +1 -4
- data/lib/httpx/io/tcp.rb +52 -21
- data/lib/httpx/io/unix.rb +4 -3
- data/lib/httpx/loggable.rb +4 -1
- data/lib/httpx/options.rb +248 -160
- data/lib/httpx/plugins/aws_sdk_authentication.rb +2 -0
- data/lib/httpx/plugins/aws_sigv4.rb +2 -0
- data/lib/httpx/plugins/callbacks.rb +13 -1
- data/lib/httpx/plugins/circuit_breaker.rb +2 -0
- data/lib/httpx/plugins/content_digest.rb +2 -0
- data/lib/httpx/plugins/cookies.rb +2 -2
- data/lib/httpx/plugins/digest_auth.rb +2 -0
- data/lib/httpx/plugins/expect.rb +2 -0
- data/lib/httpx/plugins/fiber_concurrency.rb +195 -0
- data/lib/httpx/plugins/follow_redirects.rb +2 -0
- data/lib/httpx/plugins/grpc.rb +2 -0
- data/lib/httpx/plugins/h2c.rb +26 -16
- data/lib/httpx/plugins/internal_telemetry.rb +0 -49
- data/lib/httpx/plugins/ntlm_auth.rb +2 -0
- data/lib/httpx/plugins/oauth.rb +10 -2
- data/lib/httpx/plugins/persistent.rb +27 -18
- data/lib/httpx/plugins/proxy/socks4.rb +1 -1
- data/lib/httpx/plugins/proxy/socks5.rb +1 -1
- data/lib/httpx/plugins/proxy/ssh.rb +2 -0
- data/lib/httpx/plugins/proxy.rb +61 -20
- data/lib/httpx/plugins/response_cache/file_store.rb +2 -2
- data/lib/httpx/plugins/response_cache.rb +2 -0
- data/lib/httpx/plugins/retries.rb +2 -0
- data/lib/httpx/plugins/ssrf_filter.rb +2 -2
- data/lib/httpx/plugins/stream_bidi.rb +3 -3
- data/lib/httpx/plugins/upgrade/h2.rb +11 -1
- data/lib/httpx/plugins/upgrade.rb +8 -0
- data/lib/httpx/pool.rb +15 -10
- data/lib/httpx/request/body.rb +8 -3
- data/lib/httpx/request.rb +22 -11
- data/lib/httpx/resolver/entry.rb +30 -0
- data/lib/httpx/resolver/https.rb +3 -1
- data/lib/httpx/resolver/multi.rb +16 -3
- data/lib/httpx/resolver/native.rb +15 -6
- data/lib/httpx/resolver/resolver.rb +15 -11
- data/lib/httpx/resolver/system.rb +5 -3
- data/lib/httpx/resolver.rb +49 -21
- data/lib/httpx/response/body.rb +1 -1
- data/lib/httpx/response/buffer.rb +13 -18
- data/lib/httpx/selector.rb +92 -34
- data/lib/httpx/session.rb +89 -30
- data/lib/httpx/session_extensions.rb +3 -2
- data/lib/httpx/transcoder/form.rb +1 -13
- data/lib/httpx/transcoder/multipart/mime_type_detector.rb +1 -1
- data/lib/httpx/transcoder/multipart.rb +14 -0
- data/lib/httpx/transcoder/utils/deflater.rb +1 -1
- data/lib/httpx/version.rb +1 -1
- data/sig/callbacks.rbs +1 -1
- data/sig/chainable.rbs +1 -0
- data/sig/connection/http1.rbs +2 -0
- data/sig/connection/http2.rbs +5 -1
- data/sig/connection.rbs +6 -6
- data/sig/errors.rbs +3 -1
- data/sig/io/ssl.rbs +1 -1
- data/sig/io/tcp.rbs +13 -7
- data/sig/io/udp.rbs +7 -2
- data/sig/io/unix.rbs +0 -1
- data/sig/io.rbs +0 -3
- data/sig/options.rbs +64 -11
- data/sig/plugins/fiber_concurrency.rbs +51 -0
- data/sig/plugins/h2c.rbs +5 -1
- data/sig/plugins/oauth.rbs +15 -1
- data/sig/plugins/persistent.rbs +1 -1
- data/sig/plugins/proxy/socks4.rbs +1 -1
- data/sig/plugins/proxy/socks5.rbs +1 -1
- data/sig/plugins/proxy.rbs +5 -2
- data/sig/plugins/ssrf_filter.rbs +1 -1
- data/sig/plugins/stream_bidi.rbs +2 -2
- data/sig/request.rbs +4 -1
- data/sig/resolver/entry.rbs +13 -0
- data/sig/resolver/native.rbs +1 -0
- data/sig/resolver/resolver.rbs +2 -3
- data/sig/resolver/system.rbs +2 -2
- data/sig/resolver.rbs +12 -11
- data/sig/response.rbs +2 -2
- data/sig/selector.rbs +18 -10
- data/sig/session.rbs +4 -0
- data/sig/transcoder/form.rbs +3 -3
- data/sig/transcoder/multipart.rbs +9 -3
- metadata +11 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 947d1ad4fd269f30707292be54687f7be2054147fb3fa471c76395e92c55820e
|
4
|
+
data.tar.gz: d6e321ace4211e8bf8215eff799b5c98aad627990db5b9b2cc091fe5b1b95df7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bd87db725b6da121b79f266a8a309816f5afea4ec1890a14720c16a667ea32632fdbdd9d74249b337672315fd2ac16c1488d8aa13f4e031b33751e1625f2c9a5
|
7
|
+
data.tar.gz: 00027b822dff3985519aba56eb7b3bd28d0d81eacbdeb9d49f6e778023d60ae3eaf1a2469cf11287da12c0dde2a23b1557da33e77310ea6733e03e4f73b822e2
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# 1.6.0
|
2
|
+
|
3
|
+
## Features
|
4
|
+
|
5
|
+
### `:fiber_concurrency` plugin
|
6
|
+
|
7
|
+
While simple use cases of `httpx` being used inside a fiber scheduler (such as [async](github.com/socketry/async)) worked, a serious of issues were identified when connections were reused across fibers for multiple requests (such as when using the `:persistent` plugin). The `:fiber_concurrency` plugin fixes that, by bookkeeping which requests are being used in which fibers in order to avoid spurious wakeups and busy loops.
|
8
|
+
|
9
|
+
This plugin is loaded by default when using the `:persistent` plugin, and by extension the `faraday` adapter.
|
10
|
+
|
11
|
+
You can read more about it in https://honeyryderchuck.gitlab.io/httpx/wiki/Fiber-Concurrency
|
12
|
+
|
13
|
+
## Improvements
|
14
|
+
|
15
|
+
* proxy errors are now retriable (when using the `:retries` plugin alongside the `:proxy` plugin).
|
16
|
+
* several options improvements:
|
17
|
+
* improve initialization by caching options names in the class, which facilitates predictable option ivar initialization, which avoids "too many shapes" performance penalty.
|
18
|
+
* when using `HTTPX::Options#merge`, enforce usage of Hash or `HTTPX::Options` object as the argument to merge with, instead of silently ignoring when none of the former.
|
19
|
+
* `option_` setter methods are now private.
|
20
|
+
* all options ivars are frozen on initialize, which enforces the immutability guarantees (**note**: in case you were relying on it not being truly mutable, this may break your code. Try either passing immutable values to options, or instead use procs).
|
21
|
+
* several selector loop improvements:
|
22
|
+
* move selectable checks a layer above to avoid calling `IO.select` with a single socket at all costs.
|
23
|
+
* Improve connection interest calculation to reduce spurious wakeups.
|
24
|
+
* skip early when finding closed selectables
|
25
|
+
* improve connection initialization to avoid "too many shapes" performance penalty.
|
26
|
+
* Plugins are now able to extend the functionality of both HTTP1 and HTTP2 connections, as well as resolvers.
|
27
|
+
* see instructions in the [custom lugins wiki](https://gitlab.com/os85/httpx/-/wikis/Custom-Plugins).
|
28
|
+
* IP addresses which have expired their TTL (from the respective DNS answer) will be invalidated and force a new name resolution on operations requiring it, such as reconnections or cache lookups.
|
29
|
+
* connections are removed from errors which store it internally (for internal purposes) before returning the respective error response (so that it can be garbage collected).
|
30
|
+
|
31
|
+
## Bugfixes
|
32
|
+
|
33
|
+
* remove check for non-unique local ipv6 which was preventing Happy Eyeballs v2 from kicking in.
|
34
|
+
* recover from "network unreachable" errors triggered by using a cached IP.
|
35
|
+
* dealing with requests which are rerouted for retries in the main session response handling loop.
|
36
|
+
* `datadog` adapter: compatibility with support versions under 1.13.0 is working again.
|
37
|
+
* http2 connection: fix calculation when connection closes and there's no termination handshake
|
38
|
+
* `callback_for`: check for existence of ivar `@callbacks` first.
|
39
|
+
* native resolver: do not buffer DNS query if waiting on a previous reply (even across fibers).
|
40
|
+
* http2: do not allow deactivating connections which finished all requests but are still waiting for the ack of the PING frame (which can happen in a multi-fiber usage scenario).
|
41
|
+
* pool: fix when connection is acquired after waiting on it; return it immediately, instead of bookkeeping on `:max_connections` (when defined).
|
42
|
+
* session: fix deactivation flow, when connections get deregistered from selector and removed from the array being iterated on.
|
43
|
+
* `:proxy` plugin: fix ssl reconnection such as, on close, the IO downgrades to the respective tcp socket, so that reconnection handshake starts from scratch with the original IO.
|
44
|
+
* `:persistent` plugin: calling `HTTPX::Session#close` will close selectors from other threads (instead of just the thread it was called on).
|
45
|
+
* `:callbacks` plugin: propagate callbacks to "derived-via `.plugin`" sessions.
|
46
|
+
* `:callbacks` plugin: do not trigger the `on_response_completed` callback if there was an error (as that's what the `on_request_error` callback is for).
|
47
|
+
|
48
|
+
## Chore
|
49
|
+
|
50
|
+
* decoupled form and multipart transcoders, moved "form or multipart" check to request body.
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# 1.6.1
|
2
|
+
|
3
|
+
## Improvements
|
4
|
+
|
5
|
+
* `:oauth` plugin: `.oauth_session` can be called with an `:audience` parameter, which has the effect of adding it as an extra form body parameter of the token request.
|
6
|
+
|
7
|
+
## Bugfixes
|
8
|
+
|
9
|
+
* options: when freezing the options, skip freezing `:debug`; it's usually a file/IO/stream object (stdout, stderr...), which makes it error when log messages are written.
|
10
|
+
* tcp: fixed adding IPv6 addresses to a tcp object when IPv4 connection probe is ongoing so that the next try uses the first ipv6 address.
|
11
|
+
* tcp: reorder addresses on reconnection, so ipv6 is tried first in case it is still valid.
|
12
|
+
* tcp: make sure ip index is decremented on error, so the next tried IP may be a valid one.
|
13
|
+
* tcp: do not reattempt connecting if there are no available addresses to connect. This may happen in a fiber-aware context, where fiber A waits on connection, fiber B reconnects as a result on an error or GOAWAY frame and waits on the resolver DNS answer, and when context is passed back to fiber B, it should go back to the invalidate the response and try again while waiting on the resolver as well.
|
14
|
+
* ssl: on connection coalescing, do not merge the ssl sessions, as these are frozen post-initialization.
|
15
|
+
* http2: all received GOAWAY frames emit goaway error and teardown the connection independent of the error code (it was only doing it for `:noerror`, but others may appear).
|
16
|
+
* do not check at require time whether the network is multi-homed; instead, defer it to first use and cache (this can break environments which block access to certain syscalls during boot time).
|
17
|
+
* options: do not ignore when user sets `:ip_families` in name resolution.
|
@@ -13,7 +13,11 @@ module Datadog::Tracing
|
|
13
13
|
|
14
14
|
TYPE_OUTBOUND = Datadog::Tracing::Metadata::Ext::HTTP::TYPE_OUTBOUND
|
15
15
|
|
16
|
-
TAG_BASE_SERVICE =
|
16
|
+
TAG_BASE_SERVICE = if Gem::Version.new(DATADOG_VERSION::STRING) < Gem::Version.new("1.15.0")
|
17
|
+
"_dd.base_service"
|
18
|
+
else
|
19
|
+
Datadog::Tracing::Contrib::Ext::Metadata::TAG_BASE_SERVICE
|
20
|
+
end
|
17
21
|
TAG_PEER_HOSTNAME = Datadog::Tracing::Metadata::Ext::TAG_PEER_HOSTNAME
|
18
22
|
|
19
23
|
TAG_KIND = Datadog::Tracing::Metadata::Ext::TAG_KIND
|
@@ -64,16 +68,7 @@ module Datadog::Tracing
|
|
64
68
|
end
|
65
69
|
|
66
70
|
request.on(:response) do |response|
|
67
|
-
|
68
|
-
next unless response.is_a?(::HTTPX::ErrorResponse) && response.error.respond_to?(:connection)
|
69
|
-
|
70
|
-
# handles the case when the +error+ happened during name resolution, which means
|
71
|
-
# that the tracing start point hasn't been triggered yet; in such cases, the approximate
|
72
|
-
# initial resolving time is collected from the connection, and used as span start time,
|
73
|
-
# and the tracing object in inserted before the on response callback is called.
|
74
|
-
span = initialize_span(request, response.error.connection.init_time)
|
75
|
-
|
76
|
-
end
|
71
|
+
span = initialize_span(request, request.init_time) if !span && request.init_time
|
77
72
|
|
78
73
|
finish(response, span)
|
79
74
|
end
|
@@ -89,7 +84,7 @@ module Datadog::Tracing
|
|
89
84
|
|
90
85
|
span.set_tags(
|
91
86
|
Datadog.configuration.tracing.header_tags.response_tags(response.headers.to_h)
|
92
|
-
)
|
87
|
+
) if Datadog.configuration.tracing.respond_to?(:header_tags)
|
93
88
|
end
|
94
89
|
|
95
90
|
span.finish
|
@@ -139,7 +134,7 @@ module Datadog::Tracing
|
|
139
134
|
|
140
135
|
span.set_tags(
|
141
136
|
Datadog.configuration.tracing.header_tags.request_tags(request.headers.to_h)
|
142
|
-
)
|
137
|
+
) if Datadog.configuration.tracing.respond_to?(:header_tags)
|
143
138
|
|
144
139
|
span
|
145
140
|
rescue StandardError => e
|
@@ -185,14 +180,29 @@ module Datadog::Tracing
|
|
185
180
|
end
|
186
181
|
|
187
182
|
module RequestMethods
|
183
|
+
attr_reader :init_time
|
184
|
+
|
188
185
|
# intercepts request initialization to inject the tracing logic.
|
189
186
|
def initialize(*)
|
190
187
|
super
|
191
188
|
|
189
|
+
@init_time = nil
|
190
|
+
|
192
191
|
return unless Datadog::Tracing.enabled?
|
193
192
|
|
194
193
|
RequestTracer.call(self)
|
195
194
|
end
|
195
|
+
|
196
|
+
def response=(response)
|
197
|
+
if response.is_a?(::HTTPX::ErrorResponse) && response.error.respond_to?(:connection)
|
198
|
+
# handles the case when the +error+ happened during name resolution, which means
|
199
|
+
# that the tracing start point hasn't been triggered yet; in such cases, the approximate
|
200
|
+
# initial resolving time is collected from the connection, and used as span start time,
|
201
|
+
# and the tracing object in inserted before the on response callback is called.
|
202
|
+
@init_time = response.error.connection.init_time
|
203
|
+
end
|
204
|
+
super
|
205
|
+
end
|
196
206
|
end
|
197
207
|
|
198
208
|
module ConnectionMethods
|
@@ -7,9 +7,14 @@ require "faraday"
|
|
7
7
|
module Faraday
|
8
8
|
class Adapter
|
9
9
|
class HTTPX < Faraday::Adapter
|
10
|
+
def initialize(app = nil, opts = {}, &block)
|
11
|
+
@connection = @bind = nil
|
12
|
+
super(app, opts, &block)
|
13
|
+
end
|
14
|
+
|
10
15
|
module RequestMixin
|
11
16
|
def build_connection(env)
|
12
|
-
return @connection if
|
17
|
+
return @connection if @connection
|
13
18
|
|
14
19
|
@connection = ::HTTPX.plugin(:persistent).plugin(ReasonPlugin)
|
15
20
|
@connection = @connection.with(@connection_options) unless @connection_options.empty?
|
@@ -54,6 +59,8 @@ module Faraday
|
|
54
59
|
Errno::EPIPE,
|
55
60
|
::HTTPX::ConnectionError => e
|
56
61
|
raise Faraday::ConnectionFailed, e
|
62
|
+
rescue ::HTTPX::TimeoutError => e
|
63
|
+
raise Faraday::TimeoutError, e
|
57
64
|
end
|
58
65
|
|
59
66
|
def build_request(env)
|
@@ -125,9 +132,11 @@ module Faraday
|
|
125
132
|
def response=(response)
|
126
133
|
super
|
127
134
|
|
128
|
-
return
|
135
|
+
return unless @response
|
136
|
+
|
137
|
+
return if @response.is_a?(::HTTPX::ErrorResponse)
|
129
138
|
|
130
|
-
response.body.on_data = @response_on_data
|
139
|
+
@response.body.on_data = @response_on_data
|
131
140
|
end
|
132
141
|
end
|
133
142
|
|
@@ -218,10 +227,10 @@ module Faraday
|
|
218
227
|
handler.on_complete.call(handler.env) if handler.on_complete
|
219
228
|
end
|
220
229
|
end
|
221
|
-
rescue ::HTTPX::TimeoutError => e
|
222
|
-
raise Faraday::TimeoutError, e
|
223
230
|
end
|
224
231
|
|
232
|
+
private
|
233
|
+
|
225
234
|
# from Faraday::Adapter#connection
|
226
235
|
def connection(env)
|
227
236
|
conn = build_connection(env)
|
@@ -230,8 +239,6 @@ module Faraday
|
|
230
239
|
yield conn
|
231
240
|
end
|
232
241
|
|
233
|
-
private
|
234
|
-
|
235
242
|
# from Faraday::Adapter#request_timeout
|
236
243
|
def request_timeout(type, options)
|
237
244
|
key = Faraday::Adapter::TIMEOUT_KEYS[type]
|
@@ -284,8 +291,6 @@ module Faraday
|
|
284
291
|
response.raise_for_status unless response.is_a?(::HTTPX::Response)
|
285
292
|
response
|
286
293
|
end
|
287
|
-
rescue ::HTTPX::TimeoutError => e
|
288
|
-
raise Faraday::TimeoutError, e
|
289
294
|
end
|
290
295
|
|
291
296
|
def parallel?(env)
|
data/lib/httpx/callbacks.rb
CHANGED
@@ -31,12 +31,7 @@ module HTTPX
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def interests
|
34
|
-
|
35
|
-
return :r if @request
|
36
|
-
|
37
|
-
return if @requests.empty?
|
38
|
-
|
39
|
-
request = @requests.first
|
34
|
+
request = @request || @requests.first
|
40
35
|
|
41
36
|
return unless request
|
42
37
|
|
@@ -229,6 +224,10 @@ module HTTPX
|
|
229
224
|
emit(:exhausted)
|
230
225
|
end
|
231
226
|
|
227
|
+
def waiting_for_ping?
|
228
|
+
false
|
229
|
+
end
|
230
|
+
|
232
231
|
private
|
233
232
|
|
234
233
|
def manage_connection(request, response)
|
@@ -23,8 +23,8 @@ module HTTPX
|
|
23
23
|
end
|
24
24
|
|
25
25
|
class GoawayError < Error
|
26
|
-
def initialize
|
27
|
-
super(0,
|
26
|
+
def initialize(code = :no_error)
|
27
|
+
super(0, code)
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
@@ -35,7 +35,7 @@ module HTTPX
|
|
35
35
|
@settings = @options.http2_settings
|
36
36
|
@pending = []
|
37
37
|
@streams = {}
|
38
|
-
@drains
|
38
|
+
@drains = {}
|
39
39
|
@pings = []
|
40
40
|
@buffer = buffer
|
41
41
|
@handshake_completed = false
|
@@ -52,12 +52,11 @@ module HTTPX
|
|
52
52
|
end
|
53
53
|
|
54
54
|
def interests
|
55
|
-
# waiting for WINDOW_UPDATE frames
|
56
|
-
return :r if @buffer.full?
|
57
|
-
|
58
55
|
if @connection.state == :closed
|
59
56
|
return unless @handshake_completed
|
60
57
|
|
58
|
+
return if @buffer.empty?
|
59
|
+
|
61
60
|
return :w
|
62
61
|
end
|
63
62
|
|
@@ -65,6 +64,13 @@ module HTTPX
|
|
65
64
|
return @buffer.empty? ? :r : :rw
|
66
65
|
end
|
67
66
|
|
67
|
+
unless @connection.send_buffer.empty?
|
68
|
+
return :rw unless @buffer.empty?
|
69
|
+
|
70
|
+
# waiting for WINDOW_UPDATE frames
|
71
|
+
return :r
|
72
|
+
end
|
73
|
+
|
68
74
|
return :w if !@pending.empty? && can_buffer_more_requests?
|
69
75
|
|
70
76
|
return :w unless @drains.empty?
|
@@ -72,10 +78,10 @@ module HTTPX
|
|
72
78
|
if @buffer.empty?
|
73
79
|
return if @streams.empty? && @pings.empty?
|
74
80
|
|
75
|
-
|
81
|
+
:r
|
82
|
+
else
|
83
|
+
:w
|
76
84
|
end
|
77
|
-
|
78
|
-
:rw
|
79
85
|
end
|
80
86
|
|
81
87
|
def close
|
@@ -151,6 +157,10 @@ module HTTPX
|
|
151
157
|
@pings << ping
|
152
158
|
end
|
153
159
|
|
160
|
+
def waiting_for_ping?
|
161
|
+
@pings.any?
|
162
|
+
end
|
163
|
+
|
154
164
|
private
|
155
165
|
|
156
166
|
def can_buffer_more_requests?
|
@@ -229,7 +239,7 @@ module HTTPX
|
|
229
239
|
end
|
230
240
|
|
231
241
|
log(level: 1, color: :yellow) do
|
232
|
-
request.headers.merge(extra_headers).each.map { |k, v| "#{stream.id}: -> HEADER: #{k}: #{log_redact(v)}" }.join("\n")
|
242
|
+
"\n#{request.headers.merge(extra_headers).each.map { |k, v| "#{stream.id}: -> HEADER: #{k}: #{log_redact(v)}" }.join("\n")}"
|
233
243
|
end
|
234
244
|
stream.headers(request.headers.each(extra_headers), end_stream: request.body.empty?)
|
235
245
|
end
|
@@ -323,8 +333,7 @@ module HTTPX
|
|
323
333
|
return if error == :stream_closed && !@streams.key?(request)
|
324
334
|
|
325
335
|
log(level: 2) { "#{stream.id}: closing stream" }
|
326
|
-
|
327
|
-
@streams.delete(request)
|
336
|
+
teardown(request)
|
328
337
|
|
329
338
|
if error
|
330
339
|
case error
|
@@ -376,13 +385,10 @@ module HTTPX
|
|
376
385
|
while (request = @pending.shift)
|
377
386
|
emit(:error, request, error)
|
378
387
|
end
|
379
|
-
when :no_error
|
380
|
-
ex = GoawayError.new
|
381
|
-
@pending.unshift(*@streams.keys)
|
382
|
-
@drains.clear
|
383
|
-
@streams.clear
|
384
388
|
else
|
385
|
-
ex =
|
389
|
+
ex = GoawayError.new(error)
|
390
|
+
@pending.unshift(*@streams.keys)
|
391
|
+
teardown
|
386
392
|
end
|
387
393
|
|
388
394
|
if ex
|
@@ -448,5 +454,15 @@ module HTTPX
|
|
448
454
|
|
449
455
|
emit(:pong)
|
450
456
|
end
|
457
|
+
|
458
|
+
def teardown(request = nil)
|
459
|
+
if request
|
460
|
+
@drains.delete(request)
|
461
|
+
@streams.delete(request)
|
462
|
+
else
|
463
|
+
@drains.clear
|
464
|
+
@streams.clear
|
465
|
+
end
|
466
|
+
end
|
451
467
|
end
|
452
468
|
end
|
data/lib/httpx/connection.rb
CHANGED
@@ -34,9 +34,6 @@ module HTTPX
|
|
34
34
|
|
35
35
|
using URIExtensions
|
36
36
|
|
37
|
-
require "httpx/connection/http2"
|
38
|
-
require "httpx/connection/http1"
|
39
|
-
|
40
37
|
def_delegator :@io, :closed?
|
41
38
|
|
42
39
|
def_delegator :@write_buffer, :empty?
|
@@ -47,10 +44,14 @@ module HTTPX
|
|
47
44
|
|
48
45
|
attr_accessor :current_session, :family
|
49
46
|
|
50
|
-
protected :sibling
|
47
|
+
protected :ssl_session, :sibling
|
51
48
|
|
52
49
|
def initialize(uri, options)
|
53
|
-
@current_session = @current_selector =
|
50
|
+
@current_session = @current_selector =
|
51
|
+
@parser = @sibling = @coalesced_connection =
|
52
|
+
@family = @io = @ssl_session = @timeout =
|
53
|
+
@connected_at = @response_received_at = nil
|
54
|
+
|
54
55
|
@exhausted = @cloned = @main_sibling = false
|
55
56
|
|
56
57
|
@options = Options.new(options)
|
@@ -61,6 +62,8 @@ module HTTPX
|
|
61
62
|
@read_buffer = Buffer.new(@options.buffer_size)
|
62
63
|
@write_buffer = Buffer.new(@options.buffer_size)
|
63
64
|
@pending = []
|
65
|
+
@inflight = 0
|
66
|
+
@keep_alive_timeout = @options.timeout[:keep_alive_timeout]
|
64
67
|
|
65
68
|
on(:error, &method(:on_error))
|
66
69
|
if @options.io
|
@@ -98,9 +101,6 @@ module HTTPX
|
|
98
101
|
build_altsvc_connection(alt_origin, origin, alt_params)
|
99
102
|
end
|
100
103
|
|
101
|
-
@inflight = 0
|
102
|
-
@keep_alive_timeout = @options.timeout[:keep_alive_timeout]
|
103
|
-
|
104
104
|
self.addresses = @options.addresses if @options.addresses
|
105
105
|
end
|
106
106
|
|
@@ -122,6 +122,10 @@ module HTTPX
|
|
122
122
|
@io && @io.addresses
|
123
123
|
end
|
124
124
|
|
125
|
+
def addresses?
|
126
|
+
@io && @io.addresses?
|
127
|
+
end
|
128
|
+
|
125
129
|
def match?(uri, options)
|
126
130
|
return false if !used? && (@state == :closing || @state == :closed)
|
127
131
|
|
@@ -135,12 +139,6 @@ module HTTPX
|
|
135
139
|
) && @options == options
|
136
140
|
end
|
137
141
|
|
138
|
-
def expired?
|
139
|
-
return false unless @io
|
140
|
-
|
141
|
-
@io.expired?
|
142
|
-
end
|
143
|
-
|
144
142
|
def mergeable?(connection)
|
145
143
|
return false if @state == :closing || @state == :closed || !@io
|
146
144
|
|
@@ -179,7 +177,7 @@ module HTTPX
|
|
179
177
|
|
180
178
|
def merge(connection)
|
181
179
|
@origins |= connection.instance_variable_get(:@origins)
|
182
|
-
if connection.ssl_session
|
180
|
+
if @ssl_session.nil? && connection.ssl_session
|
183
181
|
@ssl_session = connection.ssl_session
|
184
182
|
@io.session_new_cb do |sess|
|
185
183
|
@ssl_session = sess
|
@@ -229,9 +227,6 @@ module HTTPX
|
|
229
227
|
return @io.interests if connecting?
|
230
228
|
end
|
231
229
|
|
232
|
-
# if the write buffer is full, we drain it
|
233
|
-
return :w unless @write_buffer.empty?
|
234
|
-
|
235
230
|
return @parser.interests if @parser
|
236
231
|
|
237
232
|
nil
|
@@ -369,8 +364,6 @@ module HTTPX
|
|
369
364
|
end
|
370
365
|
|
371
366
|
def handle_connect_error(error)
|
372
|
-
@connect_error = error
|
373
|
-
|
374
367
|
return handle_error(error) unless @sibling && @sibling.connecting?
|
375
368
|
|
376
369
|
@sibling.merge(self)
|
@@ -382,8 +375,7 @@ module HTTPX
|
|
382
375
|
return unless @current_session && @current_selector
|
383
376
|
|
384
377
|
emit(:close)
|
385
|
-
@current_session = nil
|
386
|
-
@current_selector = nil
|
378
|
+
@current_session = @current_selector = nil
|
387
379
|
end
|
388
380
|
|
389
381
|
# :nocov:
|
@@ -545,7 +537,7 @@ module HTTPX
|
|
545
537
|
|
546
538
|
def send_request_to_parser(request)
|
547
539
|
@inflight += 1
|
548
|
-
request.peer_address = @io.ip
|
540
|
+
request.peer_address = @io.ip && @io.ip.address
|
549
541
|
set_request_timeouts(request)
|
550
542
|
|
551
543
|
parser.send(request)
|
@@ -714,7 +706,7 @@ module HTTPX
|
|
714
706
|
return unless @state == :open
|
715
707
|
|
716
708
|
# do not deactivate connection in use
|
717
|
-
return if @inflight.positive?
|
709
|
+
return if @inflight.positive? || @parser.waiting_for_ping?
|
718
710
|
when :closing
|
719
711
|
return unless @state == :idle || @state == :open
|
720
712
|
|
@@ -748,6 +740,7 @@ module HTTPX
|
|
748
740
|
# activate
|
749
741
|
@current_session.select_connection(self, @current_selector)
|
750
742
|
end
|
743
|
+
log(level: 3) { "#{@state} -> #{nextstate}" }
|
751
744
|
@state = nextstate
|
752
745
|
end
|
753
746
|
|
@@ -947,8 +940,8 @@ module HTTPX
|
|
947
940
|
|
948
941
|
def parser_type(protocol)
|
949
942
|
case protocol
|
950
|
-
when "h2" then
|
951
|
-
when "http/1.1" then
|
943
|
+
when "h2" then @options.http2_class
|
944
|
+
when "http/1.1" then @options.http1_class
|
952
945
|
else
|
953
946
|
raise Error, "unsupported protocol (##{protocol})"
|
954
947
|
end
|
data/lib/httpx/errors.rb
CHANGED
@@ -77,7 +77,9 @@ module HTTPX
|
|
77
77
|
# Error raised when there was an error while resolving a domain to an IP
|
78
78
|
# using a HTTPX::Resolver::Native resolver.
|
79
79
|
class NativeResolveError < ResolveError
|
80
|
-
attr_reader :
|
80
|
+
attr_reader :host
|
81
|
+
|
82
|
+
attr_accessor :connection
|
81
83
|
|
82
84
|
# initializes the exception with the +connection+ it refers to, the +host+ domain
|
83
85
|
# which failed to resolve, and the error +message+.
|
data/lib/httpx/io/ssl.rb
CHANGED
@@ -19,6 +19,7 @@ module HTTPX
|
|
19
19
|
def initialize(_, _, options)
|
20
20
|
super
|
21
21
|
|
22
|
+
@ssl_session = nil
|
22
23
|
ctx_options = TLS_OPTIONS.merge(options.ssl)
|
23
24
|
@sni_hostname = ctx_options.delete(:hostname) || @hostname
|
24
25
|
|
@@ -84,10 +85,6 @@ module HTTPX
|
|
84
85
|
@state == :negotiated
|
85
86
|
end
|
86
87
|
|
87
|
-
def expired?
|
88
|
-
super || ssl_session_expired?
|
89
|
-
end
|
90
|
-
|
91
88
|
def ssl_session_expired?
|
92
89
|
@ssl_session.nil? || Process.clock_gettime(Process::CLOCK_REALTIME) >= (@ssl_session.time.to_f + @ssl_session.timeout)
|
93
90
|
end
|