httpx 0.9.0 → 0.11.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (120) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +48 -0
  3. data/README.md +13 -3
  4. data/doc/release_notes/0_10_0.md +66 -0
  5. data/doc/release_notes/0_10_1.md +37 -0
  6. data/doc/release_notes/0_10_2.md +5 -0
  7. data/doc/release_notes/0_11_0.md +76 -0
  8. data/doc/release_notes/0_11_1.md +1 -0
  9. data/lib/httpx.rb +2 -0
  10. data/lib/httpx/adapters/datadog.rb +205 -0
  11. data/lib/httpx/adapters/faraday.rb +1 -3
  12. data/lib/httpx/adapters/webmock.rb +123 -0
  13. data/lib/httpx/chainable.rb +10 -9
  14. data/lib/httpx/connection.rb +7 -24
  15. data/lib/httpx/connection/http1.rb +15 -2
  16. data/lib/httpx/connection/http2.rb +15 -16
  17. data/lib/httpx/domain_name.rb +438 -0
  18. data/lib/httpx/errors.rb +4 -1
  19. data/lib/httpx/extensions.rb +21 -1
  20. data/lib/httpx/headers.rb +1 -0
  21. data/lib/httpx/io/ssl.rb +4 -9
  22. data/lib/httpx/io/tcp.rb +6 -5
  23. data/lib/httpx/io/udp.rb +8 -4
  24. data/lib/httpx/options.rb +2 -0
  25. data/lib/httpx/parser/http1.rb +14 -17
  26. data/lib/httpx/plugins/compression.rb +28 -63
  27. data/lib/httpx/plugins/compression/brotli.rb +10 -14
  28. data/lib/httpx/plugins/compression/deflate.rb +7 -6
  29. data/lib/httpx/plugins/compression/gzip.rb +23 -5
  30. data/lib/httpx/plugins/cookies.rb +21 -60
  31. data/lib/httpx/plugins/cookies/cookie.rb +173 -0
  32. data/lib/httpx/plugins/cookies/jar.rb +74 -0
  33. data/lib/httpx/plugins/cookies/set_cookie_parser.rb +142 -0
  34. data/lib/httpx/plugins/expect.rb +34 -11
  35. data/lib/httpx/plugins/follow_redirects.rb +20 -2
  36. data/lib/httpx/plugins/h2c.rb +1 -1
  37. data/lib/httpx/plugins/multipart.rb +41 -30
  38. data/lib/httpx/plugins/multipart/encoder.rb +115 -0
  39. data/lib/httpx/plugins/multipart/mime_type_detector.rb +64 -0
  40. data/lib/httpx/plugins/multipart/part.rb +34 -0
  41. data/lib/httpx/plugins/persistent.rb +6 -1
  42. data/lib/httpx/plugins/proxy.rb +16 -2
  43. data/lib/httpx/plugins/proxy/socks4.rb +14 -14
  44. data/lib/httpx/plugins/proxy/socks5.rb +3 -2
  45. data/lib/httpx/plugins/push_promise.rb +2 -2
  46. data/lib/httpx/plugins/rate_limiter.rb +51 -0
  47. data/lib/httpx/plugins/retries.rb +3 -2
  48. data/lib/httpx/plugins/stream.rb +109 -13
  49. data/lib/httpx/pool.rb +14 -20
  50. data/lib/httpx/request.rb +29 -31
  51. data/lib/httpx/resolver.rb +7 -6
  52. data/lib/httpx/resolver/https.rb +25 -25
  53. data/lib/httpx/resolver/native.rb +29 -22
  54. data/lib/httpx/resolver/resolver_mixin.rb +4 -2
  55. data/lib/httpx/resolver/system.rb +3 -3
  56. data/lib/httpx/response.rb +16 -23
  57. data/lib/httpx/selector.rb +11 -17
  58. data/lib/httpx/session.rb +39 -30
  59. data/lib/httpx/transcoder.rb +20 -0
  60. data/lib/httpx/transcoder/chunker.rb +0 -2
  61. data/lib/httpx/transcoder/form.rb +9 -7
  62. data/lib/httpx/transcoder/json.rb +0 -4
  63. data/lib/httpx/utils.rb +45 -0
  64. data/lib/httpx/version.rb +1 -1
  65. data/sig/buffer.rbs +24 -0
  66. data/sig/callbacks.rbs +14 -0
  67. data/sig/chainable.rbs +37 -0
  68. data/sig/connection.rbs +85 -0
  69. data/sig/connection/http1.rbs +66 -0
  70. data/sig/connection/http2.rbs +77 -0
  71. data/sig/domain_name.rbs +17 -0
  72. data/sig/errors.rbs +3 -0
  73. data/sig/headers.rbs +45 -0
  74. data/sig/httpx.rbs +15 -0
  75. data/sig/loggable.rbs +11 -0
  76. data/sig/options.rbs +118 -0
  77. data/sig/parser/http1.rbs +50 -0
  78. data/sig/plugins/authentication.rbs +11 -0
  79. data/sig/plugins/basic_authentication.rbs +13 -0
  80. data/sig/plugins/compression.rbs +55 -0
  81. data/sig/plugins/compression/brotli.rbs +21 -0
  82. data/sig/plugins/compression/deflate.rbs +17 -0
  83. data/sig/plugins/compression/gzip.rbs +29 -0
  84. data/sig/plugins/cookies.rbs +26 -0
  85. data/sig/plugins/cookies/cookie.rbs +50 -0
  86. data/sig/plugins/cookies/jar.rbs +27 -0
  87. data/sig/plugins/digest_authentication.rbs +33 -0
  88. data/sig/plugins/expect.rbs +19 -0
  89. data/sig/plugins/follow_redirects.rbs +37 -0
  90. data/sig/plugins/h2c.rbs +26 -0
  91. data/sig/plugins/multipart.rbs +44 -0
  92. data/sig/plugins/persistent.rbs +17 -0
  93. data/sig/plugins/proxy.rbs +47 -0
  94. data/sig/plugins/proxy/http.rbs +14 -0
  95. data/sig/plugins/proxy/socks4.rbs +33 -0
  96. data/sig/plugins/proxy/socks5.rbs +36 -0
  97. data/sig/plugins/proxy/ssh.rbs +18 -0
  98. data/sig/plugins/push_promise.rbs +22 -0
  99. data/sig/plugins/rate_limiter.rbs +11 -0
  100. data/sig/plugins/retries.rbs +48 -0
  101. data/sig/plugins/stream.rbs +39 -0
  102. data/sig/pool.rbs +36 -0
  103. data/sig/registry.rbs +9 -0
  104. data/sig/request.rbs +61 -0
  105. data/sig/resolver.rbs +26 -0
  106. data/sig/resolver/https.rbs +51 -0
  107. data/sig/resolver/native.rbs +60 -0
  108. data/sig/resolver/resolver_mixin.rbs +27 -0
  109. data/sig/resolver/system.rbs +17 -0
  110. data/sig/response.rbs +87 -0
  111. data/sig/selector.rbs +20 -0
  112. data/sig/session.rbs +49 -0
  113. data/sig/timeout.rbs +29 -0
  114. data/sig/transcoder.rbs +18 -0
  115. data/sig/transcoder/body.rbs +20 -0
  116. data/sig/transcoder/chunker.rbs +32 -0
  117. data/sig/transcoder/form.rbs +22 -0
  118. data/sig/transcoder/json.rbs +16 -0
  119. metadata +99 -59
  120. data/lib/httpx/resolver/options.rb +0 -25
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e15b3e81842118829ecc251093ce5e80ad0c82dada2c7b2588004b2bf7313f63
4
- data.tar.gz: 9d4efcb47f0c269f2c5b9a3c950fe8069c3b76ffb2f9624b557d29a702704712
3
+ metadata.gz: 9b21be17b0c6a6d3e2f60a97582b88f33dc1f62e09e5555cabfc2d6bea1f06a7
4
+ data.tar.gz: e0ca927150864a80a8050cc9fbc2c23e58b55452b536ce4301eceecebf1c6d37
5
5
  SHA512:
6
- metadata.gz: 9fbd146e351da8f603c8b00c236d92c7a2a3c383296736f271c88b0ac310086adf0127af7b630e9087ec45c4a22494128b2efafdb2592de43df4aae4a68ef1f3
7
- data.tar.gz: eecb817b76bc0f217b728c7e862f73758e4b2db9c6a943311e0c7d10d8e7fe6bfa8e56a7c0d4593158fb605927813a1e720ec85a9d7e70aae8ecce015f5da647
6
+ metadata.gz: 1493d50a5b49dd7c83f48078d582f874cc204d3e5df3442d7ea8308b31e6fd011e30cc3fdc5f1825d0daebd270c22af387700ab8f6d2fb9183d2e1fb63bd7265
7
+ data.tar.gz: ac48ea08cacc65a4948fea8a2abdd50fe7d7fd30c6260400cd61197ea7e6e8d87de2b4750ca1452f242569bbf6dc304c14865f809e7871a4f55d33e7e5543c03
@@ -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/commits/master)
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
- `HTTPX` acknowledges the ease-of-use of the [http gem](https://github.com/httprb/http) API (itself inspired by python [requests](http://docs.python-requests.org/en/latest/) library). It therefore aims at reusing the same facade, extending it for the use cases which the http gem doesn't support.
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 test
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,5 @@
1
+ # 0.10.2
2
+
3
+ ## Bugfixes
4
+
5
+ Support for nested params in multipart forms introduced a bug where top-level params weren't being spread out correctly in the request body.
@@ -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
@@ -5,6 +5,8 @@ require "httpx/version"
5
5
  require "httpx/extensions"
6
6
 
7
7
  require "httpx/errors"
8
+ require "httpx/utils"
9
+ require "httpx/domain_name"
8
10
  require "httpx/altsvc"
9
11
  require "httpx/callbacks"
10
12
  require "httpx/loggable"
@@ -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