httpx 0.9.0 → 0.11.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE.txt +48 -0
- data/README.md +13 -3
- data/doc/release_notes/0_10_0.md +66 -0
- data/doc/release_notes/0_10_1.md +37 -0
- data/doc/release_notes/0_10_2.md +5 -0
- data/doc/release_notes/0_11_0.md +76 -0
- data/doc/release_notes/0_11_1.md +1 -0
- data/lib/httpx.rb +2 -0
- data/lib/httpx/adapters/datadog.rb +205 -0
- data/lib/httpx/adapters/faraday.rb +1 -3
- data/lib/httpx/adapters/webmock.rb +123 -0
- data/lib/httpx/chainable.rb +10 -9
- data/lib/httpx/connection.rb +7 -24
- data/lib/httpx/connection/http1.rb +15 -2
- data/lib/httpx/connection/http2.rb +15 -16
- data/lib/httpx/domain_name.rb +438 -0
- data/lib/httpx/errors.rb +4 -1
- data/lib/httpx/extensions.rb +21 -1
- data/lib/httpx/headers.rb +1 -0
- data/lib/httpx/io/ssl.rb +4 -9
- data/lib/httpx/io/tcp.rb +6 -5
- data/lib/httpx/io/udp.rb +8 -4
- data/lib/httpx/options.rb +2 -0
- data/lib/httpx/parser/http1.rb +14 -17
- data/lib/httpx/plugins/compression.rb +28 -63
- data/lib/httpx/plugins/compression/brotli.rb +10 -14
- data/lib/httpx/plugins/compression/deflate.rb +7 -6
- data/lib/httpx/plugins/compression/gzip.rb +23 -5
- data/lib/httpx/plugins/cookies.rb +21 -60
- data/lib/httpx/plugins/cookies/cookie.rb +173 -0
- data/lib/httpx/plugins/cookies/jar.rb +74 -0
- data/lib/httpx/plugins/cookies/set_cookie_parser.rb +142 -0
- data/lib/httpx/plugins/expect.rb +34 -11
- data/lib/httpx/plugins/follow_redirects.rb +20 -2
- data/lib/httpx/plugins/h2c.rb +1 -1
- data/lib/httpx/plugins/multipart.rb +41 -30
- data/lib/httpx/plugins/multipart/encoder.rb +115 -0
- data/lib/httpx/plugins/multipart/mime_type_detector.rb +64 -0
- data/lib/httpx/plugins/multipart/part.rb +34 -0
- data/lib/httpx/plugins/persistent.rb +6 -1
- data/lib/httpx/plugins/proxy.rb +16 -2
- data/lib/httpx/plugins/proxy/socks4.rb +14 -14
- data/lib/httpx/plugins/proxy/socks5.rb +3 -2
- data/lib/httpx/plugins/push_promise.rb +2 -2
- data/lib/httpx/plugins/rate_limiter.rb +51 -0
- data/lib/httpx/plugins/retries.rb +3 -2
- data/lib/httpx/plugins/stream.rb +109 -13
- data/lib/httpx/pool.rb +14 -20
- data/lib/httpx/request.rb +29 -31
- data/lib/httpx/resolver.rb +7 -6
- data/lib/httpx/resolver/https.rb +25 -25
- data/lib/httpx/resolver/native.rb +29 -22
- data/lib/httpx/resolver/resolver_mixin.rb +4 -2
- data/lib/httpx/resolver/system.rb +3 -3
- data/lib/httpx/response.rb +16 -23
- data/lib/httpx/selector.rb +11 -17
- data/lib/httpx/session.rb +39 -30
- data/lib/httpx/transcoder.rb +20 -0
- data/lib/httpx/transcoder/chunker.rb +0 -2
- data/lib/httpx/transcoder/form.rb +9 -7
- data/lib/httpx/transcoder/json.rb +0 -4
- data/lib/httpx/utils.rb +45 -0
- data/lib/httpx/version.rb +1 -1
- data/sig/buffer.rbs +24 -0
- data/sig/callbacks.rbs +14 -0
- data/sig/chainable.rbs +37 -0
- data/sig/connection.rbs +85 -0
- data/sig/connection/http1.rbs +66 -0
- data/sig/connection/http2.rbs +77 -0
- data/sig/domain_name.rbs +17 -0
- data/sig/errors.rbs +3 -0
- data/sig/headers.rbs +45 -0
- data/sig/httpx.rbs +15 -0
- data/sig/loggable.rbs +11 -0
- data/sig/options.rbs +118 -0
- data/sig/parser/http1.rbs +50 -0
- data/sig/plugins/authentication.rbs +11 -0
- data/sig/plugins/basic_authentication.rbs +13 -0
- data/sig/plugins/compression.rbs +55 -0
- data/sig/plugins/compression/brotli.rbs +21 -0
- data/sig/plugins/compression/deflate.rbs +17 -0
- data/sig/plugins/compression/gzip.rbs +29 -0
- data/sig/plugins/cookies.rbs +26 -0
- data/sig/plugins/cookies/cookie.rbs +50 -0
- data/sig/plugins/cookies/jar.rbs +27 -0
- data/sig/plugins/digest_authentication.rbs +33 -0
- data/sig/plugins/expect.rbs +19 -0
- data/sig/plugins/follow_redirects.rbs +37 -0
- data/sig/plugins/h2c.rbs +26 -0
- data/sig/plugins/multipart.rbs +44 -0
- data/sig/plugins/persistent.rbs +17 -0
- data/sig/plugins/proxy.rbs +47 -0
- data/sig/plugins/proxy/http.rbs +14 -0
- data/sig/plugins/proxy/socks4.rbs +33 -0
- data/sig/plugins/proxy/socks5.rbs +36 -0
- data/sig/plugins/proxy/ssh.rbs +18 -0
- data/sig/plugins/push_promise.rbs +22 -0
- data/sig/plugins/rate_limiter.rbs +11 -0
- data/sig/plugins/retries.rbs +48 -0
- data/sig/plugins/stream.rbs +39 -0
- data/sig/pool.rbs +36 -0
- data/sig/registry.rbs +9 -0
- data/sig/request.rbs +61 -0
- data/sig/resolver.rbs +26 -0
- data/sig/resolver/https.rbs +51 -0
- data/sig/resolver/native.rbs +60 -0
- data/sig/resolver/resolver_mixin.rbs +27 -0
- data/sig/resolver/system.rbs +17 -0
- data/sig/response.rbs +87 -0
- data/sig/selector.rbs +20 -0
- data/sig/session.rbs +49 -0
- data/sig/timeout.rbs +29 -0
- data/sig/transcoder.rbs +18 -0
- data/sig/transcoder/body.rbs +20 -0
- data/sig/transcoder/chunker.rbs +32 -0
- data/sig/transcoder/form.rbs +22 -0
- data/sig/transcoder/json.rbs +16 -0
- metadata +99 -59
- data/lib/httpx/resolver/options.rb +0 -25
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9b21be17b0c6a6d3e2f60a97582b88f33dc1f62e09e5555cabfc2d6bea1f06a7
|
4
|
+
data.tar.gz: e0ca927150864a80a8050cc9fbc2c23e58b55452b536ce4301eceecebf1c6d37
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1493d50a5b49dd7c83f48078d582f874cc204d3e5df3442d7ea8308b31e6fd011e30cc3fdc5f1825d0daebd270c22af387700ab8f6d2fb9183d2e1fb63bd7265
|
7
|
+
data.tar.gz: ac48ea08cacc65a4948fea8a2abdd50fe7d7fd30c6260400cd61197ea7e6e8d87de2b4750ca1452f242569bbf6dc304c14865f809e7871a4f55d33e7e5543c03
|
data/LICENSE.txt
CHANGED
@@ -189,3 +189,51 @@
|
|
189
189
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
190
190
|
See the License for the specific language governing permissions and
|
191
191
|
limitations under the License.
|
192
|
+
|
193
|
+
|
194
|
+
* lib/httpx/domain_name.rb
|
195
|
+
|
196
|
+
This file is derived from the implementation of punycode available at
|
197
|
+
here:
|
198
|
+
|
199
|
+
https://www.verisign.com/en_US/channel-resources/domain-registry-products/idn-sdks/index.xhtml
|
200
|
+
|
201
|
+
Copyright (C) 2000-2002 Verisign Inc., All rights reserved.
|
202
|
+
|
203
|
+
Redistribution and use in source and binary forms, with or
|
204
|
+
without modification, are permitted provided that the following
|
205
|
+
conditions are met:
|
206
|
+
|
207
|
+
1) Redistributions of source code must retain the above copyright
|
208
|
+
notice, this list of conditions and the following disclaimer.
|
209
|
+
|
210
|
+
2) Redistributions in binary form must reproduce the above copyright
|
211
|
+
notice, this list of conditions and the following disclaimer in
|
212
|
+
the documentation and/or other materials provided with the
|
213
|
+
distribution.
|
214
|
+
|
215
|
+
3) Neither the name of the VeriSign Inc. nor the names of its
|
216
|
+
contributors may be used to endorse or promote products derived
|
217
|
+
from this software without specific prior written permission.
|
218
|
+
|
219
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
220
|
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
221
|
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
222
|
+
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
223
|
+
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
224
|
+
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
225
|
+
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
226
|
+
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
227
|
+
AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
228
|
+
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
229
|
+
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
230
|
+
POSSIBILITY OF SUCH DAMAGE.
|
231
|
+
|
232
|
+
This software is licensed under the BSD open source license. For more
|
233
|
+
information visit www.opensource.org.
|
234
|
+
|
235
|
+
Authors:
|
236
|
+
John Colosi (VeriSign)
|
237
|
+
Srikanth Veeramachaneni (VeriSign)
|
238
|
+
Nagesh Chigurupati (Verisign)
|
239
|
+
Praveen Srinivasan(Verisign)
|
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# HTTPX: A Ruby HTTP library for tomorrow... and beyond!
|
2
2
|
|
3
3
|
[![Gem Version](https://badge.fury.io/rb/httpx.svg)](http://rubygems.org/gems/httpx)
|
4
|
-
[![pipeline status](https://gitlab.com/honeyryderchuck/httpx/badges/master/pipeline.svg)](https://gitlab.com/honeyryderchuck/httpx/
|
4
|
+
[![pipeline status](https://gitlab.com/honeyryderchuck/httpx/badges/master/pipeline.svg)](https://gitlab.com/honeyryderchuck/httpx/pipelines?page=1&scope=all&ref=master)
|
5
5
|
[![coverage report](https://gitlab.com/honeyryderchuck/httpx/badges/master/coverage.svg?job=coverage)](https://honeyryderchuck.gitlab.io/httpx/coverage/#_AllFiles)
|
6
6
|
|
7
7
|
HTTPX is an HTTP client library for the Ruby programming language.
|
@@ -18,6 +18,7 @@ Among its features, it supports:
|
|
18
18
|
And also:
|
19
19
|
|
20
20
|
* Compression (gzip, deflate, brotli)
|
21
|
+
* Streaming Requests
|
21
22
|
* Authentication (Basic Auth, Digest Auth)
|
22
23
|
* Expect 100-continue
|
23
24
|
* Multipart Requests
|
@@ -25,6 +26,7 @@ And also:
|
|
25
26
|
* HTTP/2 Server Push
|
26
27
|
* H2C Upgrade
|
27
28
|
* Automatic follow redirects
|
29
|
+
* International Domain Names
|
28
30
|
|
29
31
|
## How
|
30
32
|
|
@@ -83,7 +85,15 @@ However if the server supports HTTP/1.1, it will try to use HTTP pipelining, fal
|
|
83
85
|
|
84
86
|
### Clean API
|
85
87
|
|
86
|
-
`
|
88
|
+
`httpx` builds all functions around the `HTTPX` module, so that all calls can compose of each other. Here are a few examples:
|
89
|
+
|
90
|
+
```ruby
|
91
|
+
response = HTTPX.get("https://www.google.com")
|
92
|
+
response = HTTPX.post("https://www.nghttp2.org/httpbin/post", params: {name: "John", age: "22"})
|
93
|
+
response = HTTPX.plugin(:basic_authentication)
|
94
|
+
.basic_authentication("user", "pass")
|
95
|
+
.get("https://www.google.com")
|
96
|
+
```
|
87
97
|
|
88
98
|
### Lightweight
|
89
99
|
|
@@ -133,7 +143,7 @@ Doesn't work with ruby 2.4.0 for Windows (see [#36](https://gitlab.com/honeyryde
|
|
133
143
|
|
134
144
|
* Discuss your contribution in an issue
|
135
145
|
* Fork it
|
136
|
-
* Make your changes, add some
|
146
|
+
* Make your changes, add some tests
|
137
147
|
* Ensure all tests pass (`bundle exec rake test`)
|
138
148
|
* Open a Merge Request (that's Pull Request in Github-ish)
|
139
149
|
* Wait for feedback
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# 0.10.0
|
2
|
+
|
3
|
+
## Features
|
4
|
+
|
5
|
+
### Streaming Requests
|
6
|
+
|
7
|
+
The `stream` plugin adds functionality to handle long-lived stream responses, such as the Twitter Streaming API:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
http = HTTPX.plugin(:stream)
|
11
|
+
|
12
|
+
http.get(stream_api_endpoint, stream: true).each_line do |line|
|
13
|
+
payload = JSON.parse(line)
|
14
|
+
# do smth with this
|
15
|
+
end
|
16
|
+
```
|
17
|
+
|
18
|
+
https://gitlab.com/honeyryderchuck/httpx/-/wikis/Stream
|
19
|
+
|
20
|
+
### Rate Limiter
|
21
|
+
|
22
|
+
The `rate_limiter` plugin adds functionality for automatically hooking into rate-limiting responses coming from the server, and waits-and-retries them according to what the server advertises.
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
HTTPX.plugin(:rate_limiter).get(rate_limited_api_endpoint)
|
26
|
+
# => 429 Too Many Requests .... Retry-After: 3
|
27
|
+
# waits 3 seconds before retrying
|
28
|
+
```
|
29
|
+
|
30
|
+
https://gitlab.com/honeyryderchuck/httpx/-/wikis/Rate-Limiter
|
31
|
+
|
32
|
+
### Ruby 3
|
33
|
+
|
34
|
+
This release is the first testing against and targeting Ruby 3 and some of the new features.
|
35
|
+
|
36
|
+
It ships with RBS signatures for all of the client-facing APIs. There's non 100% typinng coverage yet, but I'm gradually (pun intended) working on it.
|
37
|
+
|
38
|
+
|
39
|
+
## Improvements
|
40
|
+
|
41
|
+
### IDN support
|
42
|
+
|
43
|
+
Requests where the domains are formed by non-ASCII characters, are now supported (if you're using ruby 2.3 or more recent).
|
44
|
+
|
45
|
+
```ruby
|
46
|
+
HTTPX.get("http://bücher.ch") # it works!
|
47
|
+
```
|
48
|
+
|
49
|
+
### cookies plugin full implementation
|
50
|
+
|
51
|
+
|
52
|
+
The `cookies` plugin is now independent of 3rd-party gems. The motivation for this was that `http-cookie` was dependent of both `domain_name` and `unf` gems, which are currently unusable in ruby 3, and haven't received any update in the last 3 years.
|
53
|
+
|
54
|
+
The implementation is still compliant with RFC6265, and all of the features provided in earlier versions were ported, exceptwhen loading the cookie jar stored in a Netscape-format file or Mozilla sqlite database, which were not documented for `httpx` anyway, and I considered too niche to backport. If you feel `httpx` should support those, do let me know.
|
55
|
+
|
56
|
+
Some code from these gems, including the ruby punycode implementation, is now part of the source tree, along with its licenses and attribution mentions.
|
57
|
+
|
58
|
+
## Bugfixes
|
59
|
+
|
60
|
+
|
61
|
+
Several edge-case bugs have been fixed solely by the integration of RBS runtime type checking, including some bugs around closing a connection pool that can cause loops.
|
62
|
+
|
63
|
+
|
64
|
+
## Regressions
|
65
|
+
|
66
|
+
`HTTPX::ErrorResponse`'s methods `#headers` and `#reason` were removed, as they didn't provide much value. Consider calling `#raise_for_status` or checking the API (`is_a?(HTTPX::ErrorResponse)` or `respond_to?(:error)` are strategies for this).
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# 0.10.1
|
2
|
+
|
3
|
+
## Improvements
|
4
|
+
|
5
|
+
### URL-encoded nested params
|
6
|
+
|
7
|
+
url encoder now supports nested params, which is a standard of rack-based frameworks:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
HTTPX.post("https://httpbin.org/post", form: { a: { b: 1 }, c: [2, 3] })
|
11
|
+
# a[b]=1&c[]=2&c[]=3
|
12
|
+
```
|
13
|
+
|
14
|
+
This encoding scheme is now the standard for URL-encoded request bodies, query params, and `:multipart` plugin requests.
|
15
|
+
|
16
|
+
### Socks4 IPv6 addresses
|
17
|
+
|
18
|
+
HTTPX supports IPv6 Socks4 proxies now. This support is restricted to rubies where `IPAddr#hton` is implemented though, so you are encouraged to upgrade.
|
19
|
+
|
20
|
+
## More verbose HTTP Errors
|
21
|
+
|
22
|
+
`HTTPX::Response#raise_for_status` was raising exceptions for client/server HTTP errors codes (4xx/5xx). However, only the status code was part of the message.
|
23
|
+
|
24
|
+
From now on, both headers and the responnse payload will also appear, so expected more verbosity, but also more meaningful information.
|
25
|
+
|
26
|
+
## Bugfixes
|
27
|
+
|
28
|
+
* HTTP/2 and HTTP/1.1 exhausted connections now get properly migrated into a new connection;
|
29
|
+
* HTTP/2 421 responses will now correctly migrate the connection and pendign requests to HTTP/1.1 (a hanging loop was being caused);
|
30
|
+
* HTTP/2 connection failed with a GOAWAY settings timeout will now return error responses (instead of hanging indefinitely);
|
31
|
+
* Non-IP proxy name-resolving errors will now move on to the next available proxy in the list (instead of hanging indefinitely);
|
32
|
+
* Non-IP DNS resolve errors for `native` and `https` variants will now return the appropriate error response (instead of hanging indefinitely);
|
33
|
+
|
34
|
+
## Chore
|
35
|
+
|
36
|
+
* `HTTPX.plugins` is now officially deprecated (use `HTTPX.plugin` instead);
|
37
|
+
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# 0.11.0
|
2
|
+
|
3
|
+
## Features
|
4
|
+
|
5
|
+
### Webmock Adapter
|
6
|
+
|
7
|
+
`httpx` can now be integrated with `webmock`, a popular HTTP requests stubbing library.
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
# minitest
|
11
|
+
require "webmock/minitest"
|
12
|
+
require "httpx/adapters/webmock"
|
13
|
+
|
14
|
+
# in rspec
|
15
|
+
require "webmock/rspec"
|
16
|
+
require "httpx/adapters/webmock"
|
17
|
+
|
18
|
+
# and now you're free for mocking
|
19
|
+
WebMock.enable!
|
20
|
+
stub_http_request(:get, "https://www.google.com").and_return(status: 200, body: "here's google")
|
21
|
+
|
22
|
+
```
|
23
|
+
|
24
|
+
Read more about it in the [webmock integration documentation](https://honeyryderchuck.gitlab.io/httpx/wiki/Webmock-Adapter).
|
25
|
+
|
26
|
+
### Datadog Adapter
|
27
|
+
|
28
|
+
`httpx` ships with integration for [ddtrace, datadog's official tracing client](https://github.com/DataDog/dd-trace-rb). You just need to initialize it the following way:
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
require "ddtrace"
|
32
|
+
require "httpx/adapters/datadog"
|
33
|
+
|
34
|
+
Datadog.configure do |c|
|
35
|
+
c.use :httpx
|
36
|
+
end
|
37
|
+
```
|
38
|
+
|
39
|
+
A trace will be emitted for every request, so this should be an interesting visualization if concurrent requests are sent.
|
40
|
+
|
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
|
+
|
43
|
+
Read more about it in the [datadog integration documentation](https://honeyryderchuck.gitlab.io/httpx/wiki/Datadog-Adapter).
|
44
|
+
|
45
|
+
## Improvements
|
46
|
+
|
47
|
+
### Own multipart request encoder
|
48
|
+
|
49
|
+
`httpx` now ships with its own multipart formdata encoder, and does not rely on `http-form_data` anymore:
|
50
|
+
|
51
|
+
```ruby
|
52
|
+
HTTPX.plugin(:multipart).post(uri, form: {file: File.new("path/to/file")})
|
53
|
+
```
|
54
|
+
|
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
|
+
|
57
|
+
### Expect Plugin
|
58
|
+
|
59
|
+
The `:expect` plugin now works reliably when the server does not support the `expect: 100-continue` header, i.e. it'll upload the body after a certain timeout. Building onn that, two behaviours are now implemented:
|
60
|
+
|
61
|
+
* A cache of domains which did not respond to the `expect` header is now kept, so that subsequent requests can skip the timeout and immediately upload the payload.
|
62
|
+
* If the "100 Continue" response arrives **after** the timeout expired and the body has been uploaded, the domain is removed from the cache, and subsequent requests will send the `expect` header.
|
63
|
+
|
64
|
+
### SNI/Host options
|
65
|
+
|
66
|
+
Some extension of the API was applied in order to support custom TLS negotiation parameters. You can now pass `:hostname` under the `:ssl` options, and this will be used for the SNI part of the TLS negotiation. This is useful in scenarios where a proxy certificate doesn't apply for the host one wants to send the request to:
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
response = session.get(proxy_ip, headers: { "host" => upstream_hostname }, ssl: { hostname: sni_hostname }
|
70
|
+
```
|
71
|
+
|
72
|
+
## Bugfixes
|
73
|
+
|
74
|
+
A default 5 second timeout is in-place when using the DNS `:system` resolver, as it was found out that. when using the `resolv` library, the DNS query will not be retried otherwise. You can change this setting py passing `resolver_options: { timeouts: ANOTHER_TIMEOUT}`. In the future, this may become another timeout option, however.
|
75
|
+
|
76
|
+
|
@@ -0,0 +1 @@
|
|
1
|
+
0_11_1.md
|
data/lib/httpx.rb
CHANGED
@@ -0,0 +1,205 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "ddtrace/contrib/integration"
|
4
|
+
require "ddtrace/contrib/rest_client/configuration/settings"
|
5
|
+
require "ddtrace/contrib/rest_client/patcher"
|
6
|
+
|
7
|
+
module Datadog
|
8
|
+
module Contrib
|
9
|
+
module HTTPX
|
10
|
+
# HTTPX Datadog Plugin
|
11
|
+
#
|
12
|
+
# Enables tracing for httpx requests. A span will be created for each individual requests,
|
13
|
+
# and it'll trace since the moment it is fed to the connection, until the moment the response is
|
14
|
+
# fed back to the session.
|
15
|
+
#
|
16
|
+
module Plugin
|
17
|
+
class RequestTracer
|
18
|
+
SPAN_REQUEST = "httpx.request"
|
19
|
+
|
20
|
+
def initialize(request)
|
21
|
+
@request = request
|
22
|
+
end
|
23
|
+
|
24
|
+
def call
|
25
|
+
return if skip_tracing?
|
26
|
+
|
27
|
+
@request.on(:response, &method(:finish))
|
28
|
+
|
29
|
+
verb = @request.verb.to_s.upcase
|
30
|
+
uri = @request.uri
|
31
|
+
|
32
|
+
@span = datadog_pin.tracer.trace(SPAN_REQUEST)
|
33
|
+
service_name = datadog_config[:split_by_domain] ? uri.host : datadog_pin.service_name
|
34
|
+
|
35
|
+
begin
|
36
|
+
@span.service = service_name
|
37
|
+
@span.span_type = Datadog::Ext::HTTP::TYPE_OUTBOUND
|
38
|
+
@span.resource = verb
|
39
|
+
|
40
|
+
Datadog::HTTPPropagator.inject!(@span.context, @request.headers) if datadog_pin.tracer.enabled && !skip_distributed_tracing?
|
41
|
+
|
42
|
+
# Add additional request specific tags to the span.
|
43
|
+
|
44
|
+
@span.set_tag(Datadog::Ext::HTTP::URL, @request.path)
|
45
|
+
@span.set_tag(Datadog::Ext::HTTP::METHOD, verb)
|
46
|
+
|
47
|
+
@span.set_tag(Datadog::Ext::NET::TARGET_HOST, uri.host)
|
48
|
+
@span.set_tag(Datadog::Ext::NET::TARGET_PORT, uri.port.to_s)
|
49
|
+
|
50
|
+
# Tag as an external peer service
|
51
|
+
@span.set_tag(Datadog::Ext::Integration::TAG_PEER_SERVICE, @span.service)
|
52
|
+
|
53
|
+
# Set analytics sample rate
|
54
|
+
if Contrib::Analytics.enabled?(datadog_config[:analytics_enabled])
|
55
|
+
Contrib::Analytics.set_sample_rate(@span, datadog_config[:analytics_sample_rate])
|
56
|
+
end
|
57
|
+
rescue StandardError => e
|
58
|
+
Datadog.logger.error("error preparing span for http request: #{e}")
|
59
|
+
end
|
60
|
+
rescue StandardError => e
|
61
|
+
Datadog.logger.debug("Failed to start span: #{e}")
|
62
|
+
end
|
63
|
+
|
64
|
+
def finish(response)
|
65
|
+
return unless @span
|
66
|
+
|
67
|
+
if response.respond_to?(:error)
|
68
|
+
@span.set_error(response.error)
|
69
|
+
else
|
70
|
+
@span.set_tag(Datadog::Ext::HTTP::STATUS_CODE, response.status.to_s)
|
71
|
+
|
72
|
+
@span.set_error(::HTTPX::HTTPError.new(response)) if response.status >= 400 && response.status <= 599
|
73
|
+
end
|
74
|
+
|
75
|
+
@span.finish
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def skip_tracing?
|
81
|
+
return true if @request.headers.key?(Datadog::Ext::Transport::HTTP::HEADER_META_TRACER_VERSION)
|
82
|
+
|
83
|
+
return false unless @datadog_pin
|
84
|
+
|
85
|
+
span = @datadog_pin.tracer.active_span
|
86
|
+
|
87
|
+
return true if span && (span.name == SPAN_REQUEST)
|
88
|
+
|
89
|
+
false
|
90
|
+
end
|
91
|
+
|
92
|
+
def skip_distributed_tracing?
|
93
|
+
return !datadog_pin.config[:distributed_tracing] if datadog_pin.config && datadog_pin.config.key?(:distributed_tracing)
|
94
|
+
|
95
|
+
!Datadog.configuration[:httpx][:distributed_tracing]
|
96
|
+
end
|
97
|
+
|
98
|
+
def datadog_pin
|
99
|
+
@datadog_pin ||= begin
|
100
|
+
service = datadog_config[:service_name]
|
101
|
+
tracer = datadog_config[:tracer]
|
102
|
+
|
103
|
+
Datadog::Pin.new(
|
104
|
+
service,
|
105
|
+
app: "httpx",
|
106
|
+
app_type: Datadog::Ext::AppTypes::WEB,
|
107
|
+
tracer: -> { tracer }
|
108
|
+
)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def datadog_config
|
113
|
+
@datadog_config ||= Datadog.configuration[:httpx, @request.uri.host]
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
module ConnectionMethods
|
118
|
+
def send(request)
|
119
|
+
RequestTracer.new(request).call
|
120
|
+
super
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
module Configuration
|
126
|
+
# Default settings for httpx
|
127
|
+
#
|
128
|
+
class Settings < Datadog::Contrib::Configuration::Settings
|
129
|
+
option :service_name, default: "httpx"
|
130
|
+
option :distributed_tracing, default: true
|
131
|
+
option :split_by_domain, default: false
|
132
|
+
|
133
|
+
option :enabled do |o|
|
134
|
+
o.default { env_to_bool("DD_TRACE_HTTPX_ENABLED", true) }
|
135
|
+
o.lazy
|
136
|
+
end
|
137
|
+
|
138
|
+
option :analytics_enabled do |o|
|
139
|
+
o.default { env_to_bool(%w[DD_TRACE_HTTPX_ANALYTICS_ENABLED DD_HTTPX_ANALYTICS_ENABLED], false) }
|
140
|
+
o.lazy
|
141
|
+
end
|
142
|
+
|
143
|
+
option :analytics_sample_rate do |o|
|
144
|
+
o.default { env_to_float(%w[DD_TRACE_HTTPX_ANALYTICS_SAMPLE_RATE DD_HTTPX_ANALYTICS_SAMPLE_RATE], 1.0) }
|
145
|
+
o.lazy
|
146
|
+
end
|
147
|
+
|
148
|
+
option :error_handler, default: Datadog::Tracer::DEFAULT_ON_ERROR
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
# Patcher enables patching of 'httpx' with datadog components.
|
153
|
+
#
|
154
|
+
module Patcher
|
155
|
+
include Datadog::Contrib::Patcher
|
156
|
+
|
157
|
+
module_function
|
158
|
+
|
159
|
+
def target_version
|
160
|
+
Integration.version
|
161
|
+
end
|
162
|
+
|
163
|
+
# loads a session instannce with the datadog plugin, and replaces the
|
164
|
+
# base HTTPX::Session with the patched session class.
|
165
|
+
def patch
|
166
|
+
datadog_session = ::HTTPX.plugin(Plugin)
|
167
|
+
|
168
|
+
::HTTPX.send(:remove_const, :Session)
|
169
|
+
::HTTPX.send(:const_set, :Session, datadog_session.class)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
# Datadog Integration for HTTPX.
|
174
|
+
#
|
175
|
+
class Integration
|
176
|
+
include Contrib::Integration
|
177
|
+
|
178
|
+
# MINIMUM_VERSION = Gem::Version.new('0.11.0')
|
179
|
+
MINIMUM_VERSION = Gem::Version.new("0.10.2")
|
180
|
+
|
181
|
+
register_as :httpx
|
182
|
+
|
183
|
+
def self.version
|
184
|
+
Gem.loaded_specs["httpx"] && Gem.loaded_specs["httpx"].version
|
185
|
+
end
|
186
|
+
|
187
|
+
def self.loaded?
|
188
|
+
defined?(::HTTPX::Request)
|
189
|
+
end
|
190
|
+
|
191
|
+
def self.compatible?
|
192
|
+
super && version >= MINIMUM_VERSION
|
193
|
+
end
|
194
|
+
|
195
|
+
def default_configuration
|
196
|
+
Configuration::Settings.new
|
197
|
+
end
|
198
|
+
|
199
|
+
def patcher
|
200
|
+
Patcher
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|