httpx 1.6.3 → 1.7.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/0_11_0.md +3 -3
- data/doc/release_notes/1_6_3.md +2 -2
- data/doc/release_notes/1_7_0.md +149 -0
- data/doc/release_notes/1_7_1.md +21 -0
- data/lib/httpx/adapters/datadog.rb +1 -1
- data/lib/httpx/adapters/faraday.rb +1 -1
- data/lib/httpx/adapters/webmock.rb +18 -9
- data/lib/httpx/altsvc.rb +4 -2
- data/lib/httpx/connection/http1.rb +9 -9
- data/lib/httpx/connection/http2.rb +2 -0
- data/lib/httpx/connection.rb +7 -9
- data/lib/httpx/domain_name.rb +1 -1
- data/lib/httpx/headers.rb +2 -2
- data/lib/httpx/io/tcp.rb +1 -1
- data/lib/httpx/loggable.rb +2 -0
- data/lib/httpx/options.rb +118 -22
- data/lib/httpx/parser/http1.rb +1 -0
- data/lib/httpx/plugins/auth/digest.rb +44 -4
- data/lib/httpx/plugins/auth.rb +113 -4
- data/lib/httpx/plugins/aws_sdk_authentication.rb +0 -1
- data/lib/httpx/plugins/cookies/cookie.rb +1 -0
- data/lib/httpx/plugins/digest_auth.rb +4 -5
- data/lib/httpx/plugins/fiber_concurrency.rb +16 -1
- data/lib/httpx/plugins/grpc/grpc_encoding.rb +1 -1
- data/lib/httpx/plugins/grpc.rb +2 -2
- data/lib/httpx/plugins/internal_telemetry.rb +1 -1
- data/lib/httpx/plugins/ntlm_auth.rb +5 -3
- data/lib/httpx/plugins/oauth.rb +156 -57
- data/lib/httpx/plugins/persistent.rb +3 -5
- data/lib/httpx/plugins/proxy/http.rb +0 -4
- data/lib/httpx/plugins/proxy.rb +3 -1
- data/lib/httpx/plugins/query.rb +1 -1
- data/lib/httpx/plugins/rate_limiter.rb +20 -15
- data/lib/httpx/plugins/response_cache.rb +3 -7
- data/lib/httpx/plugins/retries.rb +60 -24
- data/lib/httpx/plugins/ssrf_filter.rb +1 -1
- data/lib/httpx/plugins/stream.rb +60 -9
- data/lib/httpx/plugins/stream_bidi.rb +84 -16
- data/lib/httpx/pool.rb +12 -3
- data/lib/httpx/request/body.rb +1 -1
- data/lib/httpx/request.rb +10 -1
- data/lib/httpx/resolver/cache/base.rb +136 -0
- data/lib/httpx/resolver/cache/memory.rb +42 -0
- data/lib/httpx/resolver/cache.rb +18 -0
- data/lib/httpx/resolver/https.rb +74 -20
- data/lib/httpx/resolver/multi.rb +10 -2
- data/lib/httpx/resolver/native.rb +32 -6
- data/lib/httpx/resolver/resolver.rb +3 -3
- data/lib/httpx/resolver.rb +36 -114
- data/lib/httpx/response/body.rb +5 -3
- data/lib/httpx/response.rb +22 -6
- data/lib/httpx/selector.rb +14 -3
- data/lib/httpx/session.rb +6 -6
- data/lib/httpx/timers.rb +6 -12
- data/lib/httpx/transcoder/body.rb +1 -1
- data/lib/httpx/transcoder/gzip.rb +7 -2
- data/lib/httpx/transcoder/json.rb +1 -1
- data/lib/httpx/transcoder/multipart/decoder.rb +5 -5
- data/lib/httpx/transcoder/multipart/encoder.rb +1 -1
- data/lib/httpx/transcoder/multipart.rb +17 -9
- data/lib/httpx/transcoder.rb +4 -6
- data/lib/httpx/utils.rb +13 -0
- data/lib/httpx/version.rb +1 -1
- data/sig/altsvc.rbs +9 -3
- data/sig/chainable.rbs +3 -3
- data/sig/connection.rbs +1 -3
- data/sig/loggable.rbs +1 -1
- data/sig/options.rbs +12 -4
- data/sig/plugins/auth/digest.rbs +6 -0
- data/sig/plugins/auth.rbs +37 -4
- data/sig/plugins/basic_auth.rbs +3 -3
- data/sig/plugins/digest_auth.rbs +2 -4
- data/sig/plugins/fiber_concurrency.rbs +6 -0
- data/sig/plugins/ntlm_auth.rbs +2 -2
- data/sig/plugins/oauth.rbs +44 -15
- data/sig/plugins/rate_limiter.rbs +4 -2
- data/sig/plugins/response_cache/file_store.rbs +2 -0
- data/sig/plugins/response_cache.rbs +4 -0
- data/sig/plugins/retries.rbs +12 -4
- data/sig/plugins/stream.rbs +13 -3
- data/sig/plugins/stream_bidi.rbs +2 -2
- data/sig/pool.rbs +1 -1
- data/sig/resolver/cache/base.rbs +28 -0
- data/sig/resolver/cache/memory.rbs +13 -0
- data/sig/resolver/cache.rbs +16 -0
- data/sig/resolver/https.rbs +24 -0
- data/sig/resolver/multi.rbs +8 -0
- data/sig/resolver/native.rbs +2 -0
- data/sig/resolver.rbs +5 -20
- data/sig/response.rbs +3 -0
- data/sig/session.rbs +3 -5
- data/sig/timers.rbs +1 -1
- data/sig/transcoder/multipart.rbs +4 -2
- data/sig/transcoder.rbs +5 -1
- data/sig/utils.rbs +2 -0
- metadata +11 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a9c30e22a2d406a61ef87a58fddd607bb2b1fad7b50d837d8db062d4a538a2d2
|
|
4
|
+
data.tar.gz: 9c5e1997b9c03434071c59b2deb2b004f7b1a1077c2ccaed03b9e3a1db7aafe5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 87d99c4971b99f086f7811be81a8453e71bd2535120b5e560a2fc837d50e8a040e70ab1b2b191beee4b481fcea5063576d8895d318a0089183c21cb59fdd0f24
|
|
7
|
+
data.tar.gz: 85469cf5b5822990367f1e5591798a1512de90a60226853da4b4e6b00dde8816d6218dd2aacc9b5d85f84f6cb1637dd4f7b37836863f44144f05329e4fbdf7f5
|
data/doc/release_notes/0_11_0.md
CHANGED
|
@@ -21,7 +21,7 @@ stub_http_request(:get, "https://www.google.com").and_return(status: 200, body:
|
|
|
21
21
|
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
Read more about it in the [webmock integration documentation](https://
|
|
24
|
+
Read more about it in the [webmock integration documentation](https://honeyryderchuck.gitlab.io/httpx/wiki/Webmock-Adapter).
|
|
25
25
|
|
|
26
26
|
### Datadog Adapter
|
|
27
27
|
|
|
@@ -40,7 +40,7 @@ A trace will be emitted for every request, so this should be an interesting visu
|
|
|
40
40
|
|
|
41
41
|
Customization options and traces are similar to what [the net-http adapter provides](https://docs.datadoghq.com/tracing/setup_overview/setup/ruby/#nethttp).
|
|
42
42
|
|
|
43
|
-
Read more about it in the [datadog integration documentation](https://
|
|
43
|
+
Read more about it in the [datadog integration documentation](https://honeyryderchuck.gitlab.io/httpx/wiki/Datadog-Adapter).
|
|
44
44
|
|
|
45
45
|
## Improvements
|
|
46
46
|
|
|
@@ -52,7 +52,7 @@ Read more about it in the [datadog integration documentation](https://os85.gitla
|
|
|
52
52
|
HTTPX.plugin(:multipart).post(uri, form: {file: File.new("path/to/file")})
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
-
Read more about it in the [multipart plugin documentation](https://
|
|
55
|
+
Read more about it in the [multipart plugin documentation](https://honeyryderchuck.gitlab.io/httpx/wiki/Multipart-Uploads), including also about why this was made.
|
|
56
56
|
|
|
57
57
|
### Expect Plugin
|
|
58
58
|
|
data/doc/release_notes/1_6_3.md
CHANGED
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
## Improvements
|
|
8
8
|
|
|
9
9
|
* `system` resolver now works in a non-blocking manner, initiating the dns query in a separate thread and waiting on the pipe after that (it was blocking the main thread during resolution before).
|
|
10
|
-
* reduce allocation to a
|
|
11
|
-
*
|
|
10
|
+
* reduce allocation to a single shared option object when headers are passed as a session-level option, like `HTTPX.with(headers: headers).get(...)`
|
|
11
|
+
* favour using `String#replace` in buffer operations (instead of "clean-then-append").
|
|
12
12
|
* using `Array#unshift` instead of `Array#concat` in order to ensure that request ordering is respected in the face of an in-between error which requires reconnect-and-resend.
|
|
13
13
|
* replaced more internal callback indirection with plain method calls.
|
|
14
14
|
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# 1.7.0
|
|
2
|
+
|
|
3
|
+
## Features
|
|
4
|
+
|
|
5
|
+
### All AUTH plugin improvements!!
|
|
6
|
+
|
|
7
|
+
#### `:auth`
|
|
8
|
+
|
|
9
|
+
The `:auth` plugin can now be used with a dynamic callable object (methods, procs...) to generate the token.
|
|
10
|
+
|
|
11
|
+
```ruby
|
|
12
|
+
# static token, pre 1.7.0
|
|
13
|
+
HTTPX.plugin(:auth).authorization("API-TOKEN")
|
|
14
|
+
# dynamically generate token!
|
|
15
|
+
HTTPX.plugin(:auth).authorization { generate_new_ephemeral_token }
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
The `.authorization` method is now syntactic sugar for a new option, `:auth_header_value`, which can be used directly, alongside a `:auth_header_type`:
|
|
19
|
+
|
|
20
|
+
```ruby
|
|
21
|
+
HTTPX.plugin(:auth).authorization("API-TOKEN")
|
|
22
|
+
HTTPX.plugin(:auth).authorization { generate_new_ephemeral_token }
|
|
23
|
+
HTTPX.plugin(:auth).authorization("Bearer API-TOKEN")
|
|
24
|
+
# same as
|
|
25
|
+
HTTPX.plugin(:auth, auth_header_value: "API-TOKEN")
|
|
26
|
+
HTTPX.plugin(:auth, auth_header_value: -> { generate_new_ephemeral_token })
|
|
27
|
+
HTTPX.plugin(:auth, auth_header_type: "Bearer", auth_header_value: "API-TOKEN")
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
A new option `:generate_auth_value_on_retry` (which can be passed a callable receiving a response object) is now available; when used alongside the `:retries` plugin, it'll use the callable passed to the `.authorization` method to generate a new token before retrying the request:
|
|
31
|
+
|
|
32
|
+
```ruby
|
|
33
|
+
authed = HTTPX.plugin(:retries).plugin(:auth, generate_auth_value_on_retry: ->(res) {
|
|
34
|
+
res.status == 401
|
|
35
|
+
}).authorization { generate_new_ephemeral_token }
|
|
36
|
+
authed.get("https://example.com")
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Read more about it in the [auth plugin wiki](https://honeyryderchuck.gitlab.io/httpx/wiki/Auth).
|
|
40
|
+
|
|
41
|
+
#### `:oauth`
|
|
42
|
+
|
|
43
|
+
The `:oauth` plugin implementation was revamped to make use of the `:auth` plugin new functionality, in order to make managing an oauth session more seamless.
|
|
44
|
+
|
|
45
|
+
Take the following example:
|
|
46
|
+
|
|
47
|
+
```ruby
|
|
48
|
+
session = HTTPX.plugin(:oauth).with_oauth_options(
|
|
49
|
+
issuer: server.origin,
|
|
50
|
+
client_id: "CLIENT_ID",
|
|
51
|
+
client_secret: "SECRET",
|
|
52
|
+
)
|
|
53
|
+
session.get("https://example.com") #=> will load server metadata, request an access token, and perform the request with the access token.
|
|
54
|
+
# 2 hours later...
|
|
55
|
+
session.get("https://example.com")
|
|
56
|
+
# it'll reuse the same acces token, and if the request fails with 401, it'll request a new
|
|
57
|
+
# access token using the refresh token grant (when supported by the token issuer), and
|
|
58
|
+
# reperform the original request with the new access token.
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
A new option, `:oauth_options`, is now available. The same parameters previously supported by the `:oauth_session` options are supported.
|
|
62
|
+
|
|
63
|
+
The following components are therefore deprecated and scheduled for removal in a future major version:
|
|
64
|
+
|
|
65
|
+
* `:oauth_session` option
|
|
66
|
+
* `.oauth_auth` session method
|
|
67
|
+
* `.with_access_token` session method
|
|
68
|
+
|
|
69
|
+
#### `:bearer_auth`, `:digest_auth`; `:ntlm_auth`
|
|
70
|
+
|
|
71
|
+
The `:auth` plugin is now the foundation of each of these plugins, which haven't suffered major API changes.
|
|
72
|
+
|
|
73
|
+
Read more about it in the [auth plugin wiki](https://honeyryderchuck.gitlab.io/httpx/wiki/OAuth).
|
|
74
|
+
|
|
75
|
+
### `:retries` plugin: `:retry_after` backoff algorithms
|
|
76
|
+
|
|
77
|
+
The `:retries` plugins supports two new possible values for the `:retry_after` option: `:exponential_backoff` and `:polynomial_backoff`. They'll implement the respective calculation per each retry of a given request.
|
|
78
|
+
|
|
79
|
+
```ruby
|
|
80
|
+
# will wait 1, 2, 4, 8, 16 seconds... depending of how many retries it can wait for
|
|
81
|
+
session = HTTPX.plugin(:retries, retry_after: :exponential_backoff)
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Read more about it in the [retries plugin wiki](https://honeyryderchuck.gitlab.io/httpx/wiki/Retries).
|
|
85
|
+
|
|
86
|
+
### Ractor compatibility
|
|
87
|
+
|
|
88
|
+
`httpx` can be used within a ractor:
|
|
89
|
+
|
|
90
|
+
```ruby
|
|
91
|
+
# ruby 4.0 syntax
|
|
92
|
+
response = Ractor.new(uri) do |uri|
|
|
93
|
+
HTTPX.get(uri)
|
|
94
|
+
end.value
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Bear in mind that, if you're connection via HTTPS, you'll need make sure you're using version 4.0 or higher of the `openssl` gem.
|
|
98
|
+
|
|
99
|
+
The test suite isn't exhaustive for ractors yet, but most plugins should also be ractor-compatible. If they don't work, that's a bug, and you're recommended to report it.
|
|
100
|
+
|
|
101
|
+
## Improvements
|
|
102
|
+
|
|
103
|
+
* When encoding the `:json` param to send it as `application/json` payload, (example: `HTTPX.post("https://example.com", json: { foo: "bar })`), and the method uses the `json` standard library, it'll use `JSON.generate` (instead of `JSON.dump`) to encode the JSON payload. The reason is that, unlike `JSON.dump`, it doesn't rely on access to a global mutable hash, and is therefore ractor-safe.
|
|
104
|
+
* `:stream` plugin: the stream response class (the object that is returned in request calls is a stream response) can be extended now. You can add a `StreamResponseMethods` method to your plugin. Read more about it in the documentation.
|
|
105
|
+
* The resolver name cache (used by the native and https resolvers) was remade into a LRU cache, and will therefore not keep on growing when `httpx` is used to connect to a huge number of hostnames in a process.
|
|
106
|
+
* the native and https DNS resolvers will ignore answers with SERVFAIL code while there are retries left (some resolvers use such error code for rate limiting).
|
|
107
|
+
* `:timeout` option values are now validated, and an error is raised when passing an unrecognized timeout option (which is a good layer of protection for typos).
|
|
108
|
+
* pool: try passing the scheduler to a thread waiting on a connection, to avoid the current case where a connection may be checked-in-then-immediately-out-after when doing multiple requests in a loop, never giving a chance to others and potentially making the pool time out.
|
|
109
|
+
* headers deep-freeze and dup.
|
|
110
|
+
|
|
111
|
+
## Bugfixes
|
|
112
|
+
|
|
113
|
+
* recover and close connection when an `IOError` is raised while waiting for IO readiness (could cause busy loops during HTTP/2 termination handshake).
|
|
114
|
+
* `:stream_bidi` plugin: improve thread-safety of buffer operations when the session is used from multiple threads.
|
|
115
|
+
* `:stream_bidi` plugin: added missing methods to signal in order to comply with the Selectable API (it was reported as raising `NoMethodError` under certain conditions).
|
|
116
|
+
* `:stream_bidi` plugin: can support non-bidirectional stream requests using the same session.
|
|
117
|
+
* `:stream` plugin: is now compatible with fiber scheduler engines (via the `:fiber_concurrency` plugin).
|
|
118
|
+
* `:stream` plugin: make sure that stream long-running requests do not share the same connection as regular threads.
|
|
119
|
+
* `:digest_auth` plugin: can now support qop values wrapped inside parentheses in the `www-authenticate` header (i.e. `qop="('auth',)"`).
|
|
120
|
+
* https resolver: handle 3XX redirect responses in HTTP DNS queries.
|
|
121
|
+
* https resolver: do not close HTTP connections whhich are shared across AAAA and A resolution paths when its in use by one of them.
|
|
122
|
+
* fix access to private method from `http-2` which was made public in more recent versions, but not in older still-supported versions.
|
|
123
|
+
* fixed resolver log message using a "connection" label.
|
|
124
|
+
* `HTTPX::Response.copy_to` will explicitly close the response at the end; given that the body file can be moved as a result, there is no guarantee that the response is still usable, so might as well just close it altogether.
|
|
125
|
+
* selector: avoid skipping persistent connections in the selector to deactivate due to iterate-and-modify.
|
|
126
|
+
|
|
127
|
+
## Breaking Changes
|
|
128
|
+
|
|
129
|
+
### `:digest_auth` error
|
|
130
|
+
|
|
131
|
+
The main error class for the `:digest_auth` plugin has been moved to a different location. If you were rescuing the `HTTPX::Plugins::DigestAuth::DigestError` error, you should now point to the `HTTPX::Authentication::Digest::Error`.
|
|
132
|
+
|
|
133
|
+
### `:stream` plugin: `build_request` should receive `stream: true` for stream requests
|
|
134
|
+
|
|
135
|
+
In case you're building request objects before passing them to the session, you're now forced to create them with the `:stream` option on:
|
|
136
|
+
|
|
137
|
+
```ruby
|
|
138
|
+
session = HTTPX.plugin(:stream)
|
|
139
|
+
|
|
140
|
+
# before
|
|
141
|
+
req = session.build_request("GET", "https://example.com/stream")
|
|
142
|
+
session.request(req, stream: true)
|
|
143
|
+
|
|
144
|
+
# after
|
|
145
|
+
req = session.build_request("GET", "https://example.com/stream", stream: true)
|
|
146
|
+
session.request(req)
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Previous code may still work in a few cases, but it is not guaranteed to work on all cases.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# 1.7.1
|
|
2
|
+
|
|
3
|
+
## Improvements
|
|
4
|
+
|
|
5
|
+
* fixed timers handling in the selector loop which caused them to be traversed-for-drop twice on each tick.
|
|
6
|
+
* connection: take proxy connecting states when transitioning to `:closing` state.
|
|
7
|
+
* refactored name resolution cache to a cache adapter API with a default memory cache which keeps the current behaviour and will allow to add others.
|
|
8
|
+
* a new option, `:resolver_cache`, was added, which is `:memory` by default.
|
|
9
|
+
* this fixes an issue introduced for multi-ractor support where the cache store would not be thread-safe when used in a non main ractor.
|
|
10
|
+
* `:auth` plugin: when loaded with the `:retries` plugin, and the auth value method is dynamic/callable, will recover out-of-the-box from 401 HTTP responses by retrying the request with a newly-generated token.
|
|
11
|
+
* the `:rate_limiter` plugin will use this work to retry rate-limited responses without having to set setting `:retry_change_requests` to true, thereby eliminating a potential issue with non-idempotent requests.
|
|
12
|
+
|
|
13
|
+
## Bugfixes
|
|
14
|
+
|
|
15
|
+
* HTTP1 parser: clear buffer on reset.
|
|
16
|
+
* http1 fix: handle the case in `#handle_error` where the response is an error response
|
|
17
|
+
* `:stream_bidi` plugin: fix internal state preventing bidi requests from being retried.
|
|
18
|
+
* `:stream_bidi` plugin: will only allow initial request body being passed using `:body` param (others, like `:json`, will raise an exception)
|
|
19
|
+
* https resolver: return `:idle` on `#state` calls when no connection is available (sometimes called in internal log messages).
|
|
20
|
+
* selector loop fix: when there are no selectables and an interval is passed, sleep instead of returning (thereby avoiding potential busy loop).
|
|
21
|
+
*
|
|
@@ -80,7 +80,7 @@ module Datadog::Tracing
|
|
|
80
80
|
else
|
|
81
81
|
span.set_tag(TAG_STATUS_CODE, response.status.to_s)
|
|
82
82
|
|
|
83
|
-
span.set_error(::HTTPX::HTTPError.new(response)) if response.status
|
|
83
|
+
span.set_error(::HTTPX::HTTPError.new(response)) if response.status.between?(400, 599)
|
|
84
84
|
|
|
85
85
|
span.set_tags(
|
|
86
86
|
Datadog.configuration.tracing.header_tags.response_tags(response.headers.to_h)
|
|
@@ -38,12 +38,15 @@ module WebMock
|
|
|
38
38
|
|
|
39
39
|
return build_error_response(request, webmock_response.exception) if webmock_response.exception
|
|
40
40
|
|
|
41
|
-
request
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
41
|
+
request
|
|
42
|
+
.options
|
|
43
|
+
.response_class
|
|
44
|
+
.new(
|
|
45
|
+
request,
|
|
46
|
+
webmock_response.status[0],
|
|
47
|
+
"2.0",
|
|
48
|
+
webmock_response.headers
|
|
49
|
+
).tap(&:mock!)
|
|
47
50
|
end
|
|
48
51
|
|
|
49
52
|
def build_error_response(request, exception)
|
|
@@ -72,17 +75,23 @@ module WebMock
|
|
|
72
75
|
end
|
|
73
76
|
|
|
74
77
|
module ResponseMethods
|
|
75
|
-
attr_accessor :mocked
|
|
76
|
-
|
|
77
78
|
def initialize(*)
|
|
78
79
|
super
|
|
79
80
|
@mocked = false
|
|
80
81
|
end
|
|
82
|
+
|
|
83
|
+
def mock!
|
|
84
|
+
@mocked = true
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def mocked?
|
|
88
|
+
@mocked
|
|
89
|
+
end
|
|
81
90
|
end
|
|
82
91
|
|
|
83
92
|
module ResponseBodyMethods
|
|
84
93
|
def decode_chunk(chunk)
|
|
85
|
-
return chunk if @response.mocked
|
|
94
|
+
return chunk if @response.mocked?
|
|
86
95
|
|
|
87
96
|
super
|
|
88
97
|
end
|
data/lib/httpx/altsvc.rb
CHANGED
|
@@ -8,6 +8,8 @@ module HTTPX
|
|
|
8
8
|
module ConnectionMixin
|
|
9
9
|
using URIExtensions
|
|
10
10
|
|
|
11
|
+
H2_ALTSVC_SCHEMES = %w[https h2].freeze
|
|
12
|
+
|
|
11
13
|
def send(request)
|
|
12
14
|
request.headers["alt-used"] = @origin.authority if @parser && !@write_buffer.full? && match_altsvcs?(request.uri)
|
|
13
15
|
|
|
@@ -41,12 +43,12 @@ module HTTPX
|
|
|
41
43
|
end
|
|
42
44
|
|
|
43
45
|
def altsvc_match?(uri, other_uri)
|
|
44
|
-
other_uri = URI(other_uri)
|
|
46
|
+
other_uri = URI(other_uri) #: http_uri
|
|
45
47
|
|
|
46
48
|
uri.origin == other_uri.origin || begin
|
|
47
49
|
case uri.scheme
|
|
48
50
|
when "h2"
|
|
49
|
-
(other_uri.scheme
|
|
51
|
+
H2_ALTSVC_SCHEMES.include?(other_uri.scheme) &&
|
|
50
52
|
uri.host == other_uri.host &&
|
|
51
53
|
uri.port == other_uri.port
|
|
52
54
|
else
|
|
@@ -10,6 +10,11 @@ module HTTPX
|
|
|
10
10
|
MAX_REQUESTS = 200
|
|
11
11
|
CRLF = "\r\n"
|
|
12
12
|
|
|
13
|
+
UPCASED = {
|
|
14
|
+
"www-authenticate" => "WWW-Authenticate",
|
|
15
|
+
"http2-settings" => "HTTP2-Settings",
|
|
16
|
+
"content-md5" => "Content-MD5",
|
|
17
|
+
}.freeze
|
|
13
18
|
attr_reader :pending, :requests
|
|
14
19
|
|
|
15
20
|
attr_accessor :max_concurrent_requests
|
|
@@ -192,9 +197,10 @@ module HTTPX
|
|
|
192
197
|
end
|
|
193
198
|
|
|
194
199
|
def handle_error(ex, request = nil)
|
|
195
|
-
if (ex.is_a?(EOFError) || ex.is_a?(TimeoutError)) && @request &&
|
|
196
|
-
|
|
197
|
-
|
|
200
|
+
if (ex.is_a?(EOFError) || ex.is_a?(TimeoutError)) && @request &&
|
|
201
|
+
(response = @request.response) && response.is_a?(Response) &&
|
|
202
|
+
!response.headers.key?("content-length") &&
|
|
203
|
+
!response.headers.key?("transfer-encoding")
|
|
198
204
|
# if the response does not contain a content-length header, the server closing the
|
|
199
205
|
# connnection is the indicator of response consumed.
|
|
200
206
|
# https://greenbytes.de/tech/webdav/rfc2616.html#rfc.section.4.4
|
|
@@ -386,12 +392,6 @@ module HTTPX
|
|
|
386
392
|
end
|
|
387
393
|
end
|
|
388
394
|
|
|
389
|
-
UPCASED = {
|
|
390
|
-
"www-authenticate" => "WWW-Authenticate",
|
|
391
|
-
"http2-settings" => "HTTP2-Settings",
|
|
392
|
-
"content-md5" => "Content-MD5",
|
|
393
|
-
}.freeze
|
|
394
|
-
|
|
395
395
|
def capitalized(field)
|
|
396
396
|
UPCASED[field] || field.split("-").map(&:capitalize).join("-")
|
|
397
397
|
end
|
data/lib/httpx/connection.rb
CHANGED
|
@@ -100,14 +100,13 @@ module HTTPX
|
|
|
100
100
|
def match?(uri, options)
|
|
101
101
|
return false if !used? && (@state == :closing || @state == :closed)
|
|
102
102
|
|
|
103
|
-
(
|
|
104
|
-
@origins.include?(uri.origin) &&
|
|
103
|
+
@origins.include?(uri.origin) &&
|
|
105
104
|
# if there is more than one origin to match, it means that this connection
|
|
106
105
|
# was the result of coalescing. To prevent blind trust in the case where the
|
|
107
106
|
# origin came from an ORIGIN frame, we're going to verify the hostname with the
|
|
108
107
|
# SSL certificate
|
|
109
|
-
(@origins.size == 1 || @origin == uri.origin || (@io.is_a?(SSL) && @io.verify_hostname(uri.host)))
|
|
110
|
-
|
|
108
|
+
(@origins.size == 1 || @origin == uri.origin || (@io.is_a?(SSL) && @io.verify_hostname(uri.host))) &&
|
|
109
|
+
@options == options
|
|
111
110
|
end
|
|
112
111
|
|
|
113
112
|
def mergeable?(connection)
|
|
@@ -146,10 +145,6 @@ module HTTPX
|
|
|
146
145
|
end
|
|
147
146
|
end
|
|
148
147
|
|
|
149
|
-
def create_idle(options = {})
|
|
150
|
-
self.class.new(@origin, @options.merge(options))
|
|
151
|
-
end
|
|
152
|
-
|
|
153
148
|
def merge(connection)
|
|
154
149
|
@origins |= connection.instance_variable_get(:@origins)
|
|
155
150
|
if @ssl_session.nil? && connection.ssl_session
|
|
@@ -729,7 +724,7 @@ module HTTPX
|
|
|
729
724
|
|
|
730
725
|
disconnect
|
|
731
726
|
when :closing
|
|
732
|
-
return unless
|
|
727
|
+
return unless connecting? || @state == :open
|
|
733
728
|
|
|
734
729
|
unless @write_buffer.empty?
|
|
735
730
|
# preset state before handshake, as error callbacks
|
|
@@ -855,6 +850,9 @@ module HTTPX
|
|
|
855
850
|
end
|
|
856
851
|
end
|
|
857
852
|
|
|
853
|
+
# recover internal state and emit all relevant error responses when +error+ was raised.
|
|
854
|
+
# this takes an optiona +request+ which may have already been handled and can be opted out
|
|
855
|
+
# in the state recovery process.
|
|
858
856
|
def handle_error(error, request = nil)
|
|
859
857
|
parser.handle_error(error, request) if @parser && @parser.respond_to?(:handle_error)
|
|
860
858
|
while (req = @pending.shift)
|
data/lib/httpx/domain_name.rb
CHANGED
data/lib/httpx/headers.rb
CHANGED
|
@@ -42,12 +42,12 @@ module HTTPX
|
|
|
42
42
|
# dupped initialization
|
|
43
43
|
def initialize_dup(orig)
|
|
44
44
|
super
|
|
45
|
-
@headers = orig.instance_variable_get(:@headers).dup
|
|
45
|
+
@headers = orig.instance_variable_get(:@headers).transform_values(&:dup)
|
|
46
46
|
end
|
|
47
47
|
|
|
48
48
|
# freezes the headers hash
|
|
49
49
|
def freeze
|
|
50
|
-
@headers.freeze
|
|
50
|
+
@headers.each_value(&:freeze).freeze
|
|
51
51
|
super
|
|
52
52
|
end
|
|
53
53
|
|
data/lib/httpx/io/tcp.rb
CHANGED
|
@@ -111,7 +111,7 @@ module HTTPX
|
|
|
111
111
|
raise e if @ip_index.negative?
|
|
112
112
|
|
|
113
113
|
log { "failed connecting to #{@ip} (#{e.message}), evict from cache and trying next..." }
|
|
114
|
-
|
|
114
|
+
@options.resolver_cache.evict(@hostname, @ip)
|
|
115
115
|
|
|
116
116
|
@io = build_socket
|
|
117
117
|
retry
|