httpx 1.2.6 → 1.4.4

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.
Files changed (130) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -2
  3. data/doc/release_notes/1_3_0.md +18 -0
  4. data/doc/release_notes/1_3_1.md +17 -0
  5. data/doc/release_notes/1_3_2.md +6 -0
  6. data/doc/release_notes/1_3_3.md +5 -0
  7. data/doc/release_notes/1_3_4.md +6 -0
  8. data/doc/release_notes/1_4_0.md +43 -0
  9. data/doc/release_notes/1_4_1.md +19 -0
  10. data/doc/release_notes/1_4_2.md +20 -0
  11. data/doc/release_notes/1_4_3.md +11 -0
  12. data/doc/release_notes/1_4_4.md +14 -0
  13. data/lib/httpx/adapters/datadog.rb +56 -80
  14. data/lib/httpx/adapters/faraday.rb +5 -2
  15. data/lib/httpx/adapters/webmock.rb +24 -8
  16. data/lib/httpx/callbacks.rb +2 -7
  17. data/lib/httpx/chainable.rb +3 -1
  18. data/lib/httpx/connection/http1.rb +11 -7
  19. data/lib/httpx/connection/http2.rb +57 -34
  20. data/lib/httpx/connection.rb +270 -71
  21. data/lib/httpx/errors.rb +15 -4
  22. data/lib/httpx/io/ssl.rb +6 -3
  23. data/lib/httpx/io/tcp.rb +1 -1
  24. data/lib/httpx/io/unix.rb +1 -1
  25. data/lib/httpx/loggable.rb +17 -10
  26. data/lib/httpx/options.rb +30 -23
  27. data/lib/httpx/plugins/aws_sdk_authentication.rb +3 -0
  28. data/lib/httpx/plugins/aws_sigv4.rb +36 -17
  29. data/lib/httpx/plugins/callbacks.rb +13 -2
  30. data/lib/httpx/plugins/circuit_breaker.rb +11 -5
  31. data/lib/httpx/plugins/content_digest.rb +202 -0
  32. data/lib/httpx/plugins/cookies.rb +9 -6
  33. data/lib/httpx/plugins/digest_auth.rb +3 -0
  34. data/lib/httpx/plugins/expect.rb +10 -4
  35. data/lib/httpx/plugins/follow_redirects.rb +68 -33
  36. data/lib/httpx/plugins/grpc/grpc_encoding.rb +2 -0
  37. data/lib/httpx/plugins/grpc.rb +2 -2
  38. data/lib/httpx/plugins/h2c.rb +23 -20
  39. data/lib/httpx/plugins/internal_telemetry.rb +48 -1
  40. data/lib/httpx/plugins/oauth.rb +1 -1
  41. data/lib/httpx/plugins/persistent.rb +16 -0
  42. data/lib/httpx/plugins/proxy/http.rb +19 -16
  43. data/lib/httpx/plugins/proxy/socks4.rb +1 -1
  44. data/lib/httpx/plugins/proxy/socks5.rb +1 -1
  45. data/lib/httpx/plugins/proxy.rb +96 -85
  46. data/lib/httpx/plugins/retries.rb +28 -10
  47. data/lib/httpx/plugins/ssrf_filter.rb +4 -1
  48. data/lib/httpx/plugins/stream.rb +42 -18
  49. data/lib/httpx/plugins/upgrade.rb +5 -10
  50. data/lib/httpx/plugins/webdav.rb +6 -0
  51. data/lib/httpx/plugins/xml.rb +76 -0
  52. data/lib/httpx/pool.rb +73 -244
  53. data/lib/httpx/request/body.rb +50 -55
  54. data/lib/httpx/request.rb +77 -14
  55. data/lib/httpx/resolver/https.rb +17 -20
  56. data/lib/httpx/resolver/multi.rb +34 -16
  57. data/lib/httpx/resolver/native.rb +140 -61
  58. data/lib/httpx/resolver/resolver.rb +64 -19
  59. data/lib/httpx/resolver/system.rb +32 -16
  60. data/lib/httpx/resolver.rb +21 -14
  61. data/lib/httpx/response/body.rb +12 -1
  62. data/lib/httpx/response.rb +16 -9
  63. data/lib/httpx/selector.rb +170 -91
  64. data/lib/httpx/session.rb +282 -139
  65. data/lib/httpx/timers.rb +17 -2
  66. data/lib/httpx/transcoder/body.rb +15 -29
  67. data/lib/httpx/transcoder/form.rb +2 -0
  68. data/lib/httpx/transcoder/gzip.rb +0 -3
  69. data/lib/httpx/transcoder/json.rb +16 -2
  70. data/lib/httpx/transcoder/multipart/encoder.rb +11 -2
  71. data/lib/httpx/transcoder/multipart/part.rb +1 -1
  72. data/lib/httpx/transcoder/utils/deflater.rb +7 -4
  73. data/lib/httpx/transcoder.rb +0 -1
  74. data/lib/httpx/version.rb +1 -1
  75. data/lib/httpx.rb +20 -21
  76. data/sig/callbacks.rbs +2 -3
  77. data/sig/chainable.rbs +6 -2
  78. data/sig/connection/http1.rbs +2 -2
  79. data/sig/connection/http2.rbs +22 -18
  80. data/sig/connection.rbs +40 -9
  81. data/sig/errors.rbs +9 -3
  82. data/sig/httpx.rbs +3 -3
  83. data/sig/io/tcp.rbs +1 -1
  84. data/sig/io/unix.rbs +1 -1
  85. data/sig/loggable.rbs +4 -2
  86. data/sig/options.rbs +8 -13
  87. data/sig/plugins/aws_sigv4.rbs +8 -2
  88. data/sig/plugins/content_digest.rbs +51 -0
  89. data/sig/plugins/cookies/cookie.rbs +9 -0
  90. data/sig/plugins/follow_redirects.rbs +1 -1
  91. data/sig/plugins/grpc/call.rbs +4 -0
  92. data/sig/plugins/persistent.rbs +4 -1
  93. data/sig/plugins/proxy/http.rbs +3 -0
  94. data/sig/plugins/proxy/socks5.rbs +11 -3
  95. data/sig/plugins/proxy.rbs +18 -9
  96. data/sig/plugins/push_promise.rbs +6 -3
  97. data/sig/plugins/rate_limiter.rbs +2 -0
  98. data/sig/plugins/retries.rbs +1 -1
  99. data/sig/plugins/ssrf_filter.rbs +26 -0
  100. data/sig/plugins/stream.rbs +3 -0
  101. data/sig/plugins/webdav.rbs +23 -0
  102. data/sig/plugins/xml.rbs +37 -0
  103. data/sig/pool.rbs +27 -33
  104. data/sig/request/body.rbs +4 -10
  105. data/sig/request.rbs +14 -1
  106. data/sig/resolver/multi.rbs +26 -1
  107. data/sig/resolver/native.rbs +6 -3
  108. data/sig/resolver/resolver.rbs +22 -3
  109. data/sig/resolver.rbs +5 -1
  110. data/sig/response/body.rbs +2 -2
  111. data/sig/response/buffer.rbs +2 -2
  112. data/sig/response.rbs +9 -4
  113. data/sig/selector.rbs +31 -4
  114. data/sig/session.rbs +54 -20
  115. data/sig/timers.rbs +15 -4
  116. data/sig/transcoder/body.rbs +2 -4
  117. data/sig/transcoder/chunker.rbs +1 -1
  118. data/sig/transcoder/deflate.rbs +1 -0
  119. data/sig/transcoder/form.rbs +8 -0
  120. data/sig/transcoder/gzip.rbs +4 -1
  121. data/sig/transcoder/json.rbs +1 -1
  122. data/sig/transcoder/multipart.rbs +6 -4
  123. data/sig/transcoder/utils/body_reader.rbs +3 -3
  124. data/sig/transcoder/utils/deflater.rbs +2 -3
  125. metadata +32 -14
  126. data/lib/httpx/session2.rb +0 -23
  127. data/lib/httpx/transcoder/utils/inflater.rb +0 -19
  128. data/lib/httpx/transcoder/xml.rb +0 -52
  129. data/sig/transcoder/utils/inflater.rbs +0 -12
  130. data/sig/transcoder/xml.rbs +0 -22
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0fc8cbe89a9d05f24f615e5de7874c65147954cc8d06524955fea9d0e4ef5598
4
- data.tar.gz: e97b5febb579cd1c5e035faef9cf0368ab7148882d2ed95a0454b52fd0d31621
3
+ metadata.gz: 4aa5b1cfd43d05f50fc7246219d6a90cb5591e11c8bfeee1f1cf62ffa91993fc
4
+ data.tar.gz: 58f96325ac13b8caddb708464a75ee6dafcfe7b8284f0825803ac3d0c4d8ccc1
5
5
  SHA512:
6
- metadata.gz: 55631972d465e4ea086dcaced389f7998380f052c369004f45d286d0502c612289dc5a19deff7ca26c9c0cfd6e2c4926ba5e32744c366f18884f97aedb3ad5bf
7
- data.tar.gz: 9eb1be90bceb56c335a84b180ae6c7fc065944ae1fd6dab17d9e4802c7fb62c7d3f34d3c98ba41a9cb1b8e503a929eb97cd8a667a9f536090ef266936efb81d9
6
+ metadata.gz: 43a032f78a86df04428af78f32077483b8c01500ebb001ec97100ac3923b4915a28b299cadb8b47fab8fa875c3897732c21eec63769ad98dfd98b901f006b051
7
+ data.tar.gz: dfff14a83428e2472ff53a50cadf5dd7a270f09523eca4c5aa66e7a3093ca8bd096c9c3d12070ed6a54ef1ddaec4966efd456653e666429f0ce47f04fe68e35a
data/README.md CHANGED
@@ -157,7 +157,6 @@ All Rubies greater or equal to 2.7, and always latest JRuby and Truffleruby.
157
157
 
158
158
  * Discuss your contribution in an issue
159
159
  * Fork it
160
- * Make your changes, add some tests
161
- * Ensure all tests pass (`docker-compose -f docker-compose.yml -f docker-compose-ruby-{RUBY_VERSION}.yml run httpx bundle exec rake test`)
160
+ * Make your changes, add some tests (follow the instructions from [here](test/README.md))
162
161
  * Open a Merge Request (that's Pull Request in Github-ish)
163
162
  * Wait for feedback
@@ -0,0 +1,18 @@
1
+ # 1.3.0
2
+
3
+ ## Dependencies
4
+
5
+ `http-2` v1.0.0 is replacing `http-2-next` as the HTTP/2 parser.
6
+
7
+ `http-2-next` was forked from `http-2` 5 years ago; its improvements have been merged back to `http-2` recently though, so `http-2-next` willl therefore no longer be maintained.
8
+
9
+ ## Improvements
10
+
11
+ Request-specific options (`:params`, `:form`, `:json` and `:xml`) are now separately kept by the request, which allows them to share `HTTPX::Options`, and reduce the number of copying / allocations.
12
+
13
+ This means that `HTTPX::Options` will throw an error if you initialize an object which such keys; this should not happen, as this class is considered internal and you should not be using it directly.
14
+
15
+ ## Fixes
16
+
17
+ * support for the `datadog` gem v2.0.0 in its adapter has been unblocked, now that the gem has been released.
18
+ * loading the `:cookies` plugin was making the `Session#build_request` private.
@@ -0,0 +1,17 @@
1
+ # 1.3.1
2
+
3
+ ## Improvements
4
+
5
+ * `:request_timeout` will be applied to all HTTP interactions until the final responses returned to the caller. That includes:
6
+ * all redirect requests/responses (when using the `:follow_redirects` plugin)
7
+ * all retried requests/responses (when using the `:retries` plugin)
8
+ * intermediate requests (such as "100-continue")
9
+ * faraday adapter: allow further plugins of internal session (ex: `builder.adapter(:httpx) { |sess| sess.plugin(:follow_redirects) }...`)
10
+
11
+ ## Bugfixes
12
+
13
+ * fix connection leak on proxy auth failed (407) handling
14
+ * fix busy loop on deferred requests for the duration interval
15
+ * do not further enqueue deferred requests if they have terminated meanwhile.
16
+ * fix busy loop caused by coalescing connections when one of them is on the DNS resolution phase still.
17
+ * faraday adapter: on parallel mode, skip calling `on_complete` when not defined.
@@ -0,0 +1,6 @@
1
+ # 1.3.2
2
+
3
+ ## Bugfixes
4
+
5
+ * Prevent `NoMethodError` in an edge case when the `:proxy` plugin is autoloaded via env vars and webmock adapter are used in tandem, and a real request fails.
6
+ * raise invalid uri error if passed request uri does not contain the host part (ex: `"https:/get"`)
@@ -0,0 +1,5 @@
1
+ # 1.3.3
2
+
3
+ ## Bugfixes
4
+
5
+ * fixing a regression introduced in 1.3.2 associated with the webmock adapter, which expects matchable request bodies to be strings
@@ -0,0 +1,6 @@
1
+ # 1.3.4
2
+
3
+ ## Bugfixes
4
+
5
+ * webmock adapter: fix tempfile usage in multipart requests.
6
+ * fix: fallback to binary encoding when parsing incoming invalid charset in HTTP "content-type" header.
@@ -0,0 +1,43 @@
1
+ # 1.4.0
2
+
3
+ ## Features
4
+
5
+ ### `:content_digest` plugin
6
+
7
+ The `:content_digest` can be used to calculate the digest of request payloads and set them in the `"content-digest"` header; it can also validate the integrity of responses which declare the same `"content-digest"` header.
8
+
9
+ More info under https://honeyryderchuck.gitlab.io/httpx/wiki/Content-Digest
10
+
11
+ ## Per-session connection pools
12
+
13
+ This architectural changes moves away from per-thread shared connection pools, and into per-session (also thread-safe) connection pools. Unlike before, this enables connections from a session to be reused across threads, as well as limiting the number of connections that can be open on a given origin peer. This fixes long-standing issues, such as reusing connections under a fiber scheduler loop (such as the one from the gem `async`).
14
+
15
+ A new `:pool_options` option is introduced, which can be passed an hash with the following sub-options:
16
+
17
+ * `:max_connections_per_origin`: maximum number of connections a pool allows (unbounded by default, for backwards compatibility).
18
+ * `:pool_timeout`: the number of seconds a session will wait for a connection to be checked out (default: 5)
19
+
20
+ More info under https://honeyryderchuck.gitlab.io/httpx/wiki/Connection-Pools
21
+
22
+
23
+ ## Improvements
24
+
25
+ * `:aws_sigv4` plugin: improved digest calculation on compressed request bodies by buffering content to a tempfile.
26
+ * `HTTPX::Response#json` will parse payload from extended json MIME types (like `application/ld+json`, `application/hal+json`, ...).
27
+
28
+ ## Bugfixes
29
+
30
+ * `:aws_sigv4` plugin: do not try to rewind a request body which yields chunks.
31
+ * fixed request encoding when `:json` param is passed, and the `oj` gem is used (by using the `:compat` flag).
32
+ * native resolver: on message truncation, bubble up tcp handshake errors as resolve errors.
33
+ * allow `HTTPX::Response#json` to accept extended JSON mime types (such as responses with `content-type: application/ld+json`)
34
+
35
+ ## Chore
36
+
37
+ * default options are now fully frozen (in case anyone relies on overriding them).
38
+
39
+ ### `:xml` plugin
40
+
41
+ XML encoding/decoding (via `:xml` request param, and `HTTPX::Response#xml`) is now available via the `:xml` plugin.
42
+
43
+ Using `HTTPX::Response#xml` without the plugin will issue a deprecation warning.
@@ -0,0 +1,19 @@
1
+ # 1.4.1
2
+
3
+ ## Bugfixes
4
+
5
+ * several `datadog` integration bugfixes
6
+ * only load the `datadog` integration when the `datadog` sdk is loaded (and not other gems that may define the `Datadog` module, like `dogstatsd`)
7
+ * do not trace if datadog integration is loaded but disabled
8
+ * distributed headers are now sent along (when the configuration is enabled, which it is by default)
9
+ * fix for handling multiple `GOAWAY` frames coming from the server (node.js servers seem to send multiple frames on connection timeout)
10
+ * fix regression for when a url is used with `httpx` which is not `http://` or `https://` (should raise `HTTPX::UnsupportedSchemaError`)
11
+ * worked around `IO.copy_stream` which was emitting incorrect bytes for HTTP/2 requests which bodies larger than the maximum supported frame size.
12
+ * multipart requests: make sure that a body declared as `Pathname` is opened for reading in binary mode.
13
+ * `webmock` integration: ensure that request events are emitted (such as plugins and integrations relying in it, such as `datadog` and the OTel integration)
14
+ * native resolver: do not propagate successful name resolutions for connections which were already closed.
15
+ * native resolver: fixed name resolution stalling, in a multi-request to multi-origin scenario, when a resolution timeout would happen.
16
+
17
+ ## Chore
18
+
19
+ * refactor of the happy eyeballs and connection coalescing logic to not rely on callbacks, and instead on instance variable management (makes code more straightforward to read).
@@ -0,0 +1,20 @@
1
+ # 1.4.2
2
+
3
+ ## Bugfixes
4
+
5
+ * faraday: use default reason when none is matched by Net::HTTP::STATUS_CODES
6
+ * native resolver: keep sending DNS queries if the socket is available, to avoid busy loops on select
7
+ * native resolver fixes for Happy Eyeballs v2
8
+ * do not apply resolution delay if the IPv4 IP was not resolved via DNS
9
+ * ignore ALIAS if DNS response carries IP answers
10
+ * do not try to query for names already awaiting answer from the resolver
11
+ * make sure all types of errors are propagated to connections
12
+ * make sure next candidate is picked up if receiving NX_DOMAIN_NOT_FOUND error from resolver
13
+ * raise error happening before any request is flushed to respective connections (avoids loop on non-actionable selector termination).
14
+ * fix "NoMethodError: undefined method `after' for nil:NilClass", happening for requests flushed into persistent connections which errored, and were retried in a different connection before triggering the timeout callbacks from the previously-closed connection.
15
+
16
+
17
+ ## Chore
18
+
19
+ * Refactor of timers to allow for explicit and more performant single timer interval cancellation.
20
+ * default log message restructured to include info about process, thread and caller.
@@ -0,0 +1,11 @@
1
+ # 1.4.3
2
+
3
+ ## Bugfixes
4
+
5
+ * `webmock` adapter: reassign headers to signature after callbacks are called (these may change the headers before virtual send).
6
+ * do not close request (and its body) right after sending, instead only on response close
7
+ * prevents retries from failing under the `:retries` plugin
8
+ * fixes issue when using `faraday-multipart` request bodies
9
+ * retry request with HTTP/1 when receiving an HTTP/2 GOAWAY frame with `HTTP_1_1_REQUIRED` error code.
10
+ * fix wrong method call on HTTP/2 PING frame with unrecognized code.
11
+ * fix EOFError issues on connection termination for long running connections which may have already been terminated by peer and were wrongly trying to complete the HTTP/2 termination handshake.
@@ -0,0 +1,14 @@
1
+ # 1.4.4
2
+
3
+ ## Improvements
4
+
5
+ * `:stream` plugin: response will now be partially buffered in order to i.e. inspect response status or headers on the response body without buffering the full response
6
+ * this fixes an issue in the `down` gem integration when used with the `:max_size` option.
7
+ * do not unnecessarily probe for connection liveness if no more requests are inflight, including failed ones.
8
+ * when using persistent connections, do not probe for liveness right after reconnecting after a keep alive timeout.
9
+
10
+ ## Bugfixes
11
+
12
+ * `:persistent` plugin: do not exhaust retry attempts when probing for (and failing) connection liveness.
13
+ * since the introduction of per-session connection pools, and consequentially due to the possibility of multiple inactive connections for the same origin being in the pool, which may have been terminated by the peer server, requests would fail before being able to establish a new connection.
14
+ * prevent retrying to connect the TCP socket object when an SSLSocket object is already in place and connecting.
@@ -27,62 +27,54 @@ module Datadog::Tracing
27
27
  # Enables tracing for httpx requests.
28
28
  #
29
29
  # A span will be created for each request transaction; the span is created lazily only when
30
- # receiving a response, and it is fed the start time stored inside the tracer object.
30
+ # buffering a request, and it is fed the start time stored inside the tracer object.
31
31
  #
32
32
  module Plugin
33
- class RequestTracer
34
- include Contrib::HttpAnnotationHelper
33
+ module RequestTracer
34
+ extend Contrib::HttpAnnotationHelper
35
+
36
+ module_function
35
37
 
36
38
  SPAN_REQUEST = "httpx.request"
37
39
 
38
- # initializes the tracer object on the +request+.
39
- def initialize(request)
40
- @request = request
41
- @start_time = nil
40
+ # initializes tracing on the +request+.
41
+ def call(request)
42
+ return unless configuration(request).enabled
43
+
44
+ span = nil
42
45
 
43
46
  # request objects are reused, when already buffered requests get rerouted to a different
44
47
  # connection due to connection issues, or when they already got a response, but need to
45
48
  # be retried. In such situations, the original span needs to be extended for the former,
46
49
  # while a new is required for the latter.
47
- request.on(:idle) { reset }
50
+ request.on(:idle) do
51
+ span = nil
52
+ end
48
53
  # the span is initialized when the request is buffered in the parser, which is the closest
49
54
  # one gets to actually sending the request.
50
- request.on(:headers) { call }
51
- end
52
-
53
- # sets up the span start time, while preparing the on response callback.
54
- def call(*args)
55
- return if @start_time
56
-
57
- start(*args)
55
+ request.on(:headers) do
56
+ next if span
58
57
 
59
- @request.once(:response, &method(:finish))
60
- end
58
+ span = initialize_span(request, now)
59
+ end
61
60
 
62
- private
61
+ request.on(:response) do |response|
62
+ unless span
63
+ next unless response.is_a?(::HTTPX::ErrorResponse) && response.error.respond_to?(:connection)
63
64
 
64
- # just sets the span init time. It can be passed a +start_time+ in cases where
65
- # this is collected outside the request transaction.
66
- def start(start_time = now)
67
- @start_time = start_time
68
- end
65
+ # handles the case when the +error+ happened during name resolution, which means
66
+ # that the tracing start point hasn't been triggered yet; in such cases, the approximate
67
+ # initial resolving time is collected from the connection, and used as span start time,
68
+ # and the tracing object in inserted before the on response callback is called.
69
+ span = initialize_span(request, response.error.connection.init_time)
69
70
 
70
- # resets the start time for already finished request transactions.
71
- def reset
72
- return unless @start_time
71
+ end
73
72
 
74
- start
73
+ finish(response, span)
74
+ end
75
75
  end
76
76
 
77
- # creates the span from the collected +@start_time+ to what the +response+ state
78
- # contains. It also resets internal state to allow this object to be reused.
79
- def finish(response)
80
- return unless @start_time
81
-
82
- span = initialize_span
83
-
84
- return unless span
85
-
77
+ def finish(response, span)
86
78
  if response.is_a?(::HTTPX::ErrorResponse)
87
79
  span.set_error(response.error)
88
80
  else
@@ -92,40 +84,40 @@ module Datadog::Tracing
92
84
  end
93
85
 
94
86
  span.finish
95
- ensure
96
- @start_time = nil
97
87
  end
98
88
 
99
89
  # return a span initialized with the +@request+ state.
100
- def initialize_span
101
- verb = @request.verb
102
- uri = @request.uri
90
+ def initialize_span(request, start_time)
91
+ verb = request.verb
92
+ uri = request.uri
103
93
 
104
- span = create_span(@request)
94
+ config = configuration(request)
95
+
96
+ span = create_span(request, config, start_time)
105
97
 
106
98
  span.resource = verb
107
99
 
108
100
  # Add additional request specific tags to the span.
109
101
 
110
- span.set_tag(TAG_URL, @request.path)
102
+ span.set_tag(TAG_URL, request.path)
111
103
  span.set_tag(TAG_METHOD, verb)
112
104
 
113
105
  span.set_tag(TAG_TARGET_HOST, uri.host)
114
- span.set_tag(TAG_TARGET_PORT, uri.port.to_s)
106
+ span.set_tag(TAG_TARGET_PORT, uri.port)
115
107
 
116
108
  # Tag as an external peer service
117
109
  span.set_tag(TAG_PEER_SERVICE, span.service)
118
110
 
119
- if configuration[:distributed_tracing]
111
+ if config[:distributed_tracing]
120
112
  propagate_trace_http(
121
- Datadog::Tracing.active_trace.to_digest,
122
- @request.headers
113
+ Datadog::Tracing.active_trace,
114
+ request.headers
123
115
  )
124
116
  end
125
117
 
126
118
  # Set analytics sample rate
127
- if Contrib::Analytics.enabled?(configuration[:analytics_enabled])
128
- Contrib::Analytics.set_sample_rate(span, configuration[:analytics_sample_rate])
119
+ if Contrib::Analytics.enabled?(config[:analytics_enabled])
120
+ Contrib::Analytics.set_sample_rate(span, config[:analytics_sample_rate])
129
121
  end
130
122
 
131
123
  span
@@ -138,34 +130,34 @@ module Datadog::Tracing
138
130
  ::Datadog::Core::Utils::Time.now.utc
139
131
  end
140
132
 
141
- def configuration
142
- @configuration ||= Datadog.configuration.tracing[:httpx, @request.uri.host]
133
+ def configuration(request)
134
+ Datadog.configuration.tracing[:httpx, request.uri.host]
143
135
  end
144
136
 
145
- if Gem::Version.new(DATADOG_VERSION::STRING) >= Gem::Version.new("2.0.0.beta1")
146
- def propagate_trace_http(digest, headers)
147
- Datadog::Tracing::Contrib::HTTP.inject(digest, headers)
137
+ if Gem::Version.new(DATADOG_VERSION::STRING) >= Gem::Version.new("2.0.0")
138
+ def propagate_trace_http(trace, headers)
139
+ Datadog::Tracing::Contrib::HTTP.inject(trace, headers)
148
140
  end
149
141
 
150
- def create_span(request)
142
+ def create_span(request, configuration, start_time)
151
143
  Datadog::Tracing.trace(
152
144
  SPAN_REQUEST,
153
- service: service_name(request.uri.host, configuration, Datadog.configuration_for(self)),
145
+ service: service_name(request.uri.host, configuration),
154
146
  type: TYPE_OUTBOUND,
155
- start_time: @start_time
147
+ start_time: start_time
156
148
  )
157
149
  end
158
150
  else
159
- def propagate_trace_http(digest, headers)
160
- Datadog::Tracing::Propagation::HTTP.inject!(digest, headers)
151
+ def propagate_trace_http(trace, headers)
152
+ Datadog::Tracing::Propagation::HTTP.inject!(trace.to_digest, headers)
161
153
  end
162
154
 
163
- def create_span(request)
155
+ def create_span(request, configuration, start_time)
164
156
  Datadog::Tracing.trace(
165
157
  SPAN_REQUEST,
166
- service: service_name(request.uri.host, configuration, Datadog.configuration_for(self)),
158
+ service: service_name(request.uri.host, configuration),
167
159
  span_type: TYPE_OUTBOUND,
168
- start_time: @start_time
160
+ start_time: start_time
169
161
  )
170
162
  end
171
163
  end
@@ -178,7 +170,7 @@ module Datadog::Tracing
178
170
 
179
171
  return unless Datadog::Tracing.enabled?
180
172
 
181
- RequestTracer.new(self)
173
+ RequestTracer.call(self)
182
174
  end
183
175
  end
184
176
 
@@ -190,22 +182,6 @@ module Datadog::Tracing
190
182
 
191
183
  @init_time = ::Datadog::Core::Utils::Time.now.utc
192
184
  end
193
-
194
- # handles the case when the +error+ happened during name resolution, which meanns
195
- # that the tracing logic hasn't been injected yet; in such cases, the approximate
196
- # initial resolving time is collected from the connection, and used as span start time,
197
- # and the tracing object in inserted before the on response callback is called.
198
- def handle_error(error)
199
- return super unless Datadog::Tracing.enabled?
200
-
201
- return super unless error.respond_to?(:connection)
202
-
203
- @pending.each do |request|
204
- RequestTracer.new(request).call(error.connection.init_time)
205
- end
206
-
207
- super
208
- end
209
185
  end
210
186
  end
211
187
 
@@ -30,6 +30,7 @@ module Faraday
30
30
  end
31
31
  @connection = @connection.plugin(OnDataPlugin) if env.request.stream_response?
32
32
 
33
+ @connection = @config_block.call(@connection) || @connection if @config_block
33
34
  @connection
34
35
  end
35
36
 
@@ -107,9 +108,11 @@ module Faraday
107
108
  ssl_options
108
109
  end
109
110
  else
111
+ # :nocov:
110
112
  def ssl_options_from_env(*)
111
113
  {}
112
114
  end
115
+ # :nocov:
113
116
  end
114
117
  end
115
118
 
@@ -146,7 +149,7 @@ module Faraday
146
149
 
147
150
  module ResponseMethods
148
151
  def reason
149
- Net::HTTP::STATUS_CODES.fetch(@status)
152
+ Net::HTTP::STATUS_CODES.fetch(@status, "Non-Standard status code")
150
153
  end
151
154
  end
152
155
  end
@@ -212,7 +215,7 @@ module Faraday
212
215
  Array(responses).each_with_index do |response, index|
213
216
  handler = @handlers[index]
214
217
  handler.on_response.call(response)
215
- handler.on_complete.call(handler.env)
218
+ handler.on_complete.call(handler.env) if handler.on_complete
216
219
  end
217
220
  end
218
221
  rescue ::HTTPX::TimeoutError => e
@@ -20,7 +20,7 @@ module WebMock
20
20
  WebMock::RequestSignature.new(
21
21
  request.verb.downcase.to_sym,
22
22
  uri.to_s,
23
- body: request.body.each.to_a.join,
23
+ body: request.body.to_s,
24
24
  headers: request.headers.to_h
25
25
  )
26
26
  end
@@ -47,21 +47,27 @@ module WebMock
47
47
  end
48
48
 
49
49
  def build_error_response(request, exception)
50
- HTTPX::ErrorResponse.new(request, exception, request.options)
50
+ HTTPX::ErrorResponse.new(request, exception)
51
51
  end
52
52
  end
53
53
 
54
54
  module InstanceMethods
55
- def init_connection(*)
56
- connection = super
55
+ private
56
+
57
+ def do_init_connection(connection, selector)
58
+ super
59
+
57
60
  connection.once(:unmock_connection) do
61
+ next unless connection.current_session == self
62
+
58
63
  unless connection.addresses
59
- connection.__send__(:callbacks)[:connect_error].clear
60
- pool.__send__(:unregister_connection, connection)
64
+ # reset Happy Eyeballs, fail early
65
+ connection.sibling = nil
66
+
67
+ deselect_connection(connection, selector)
61
68
  end
62
- pool.__send__(:resolve_connection, connection)
69
+ resolve_connection(connection, selector)
63
70
  end
64
- connection
65
71
  end
66
72
  end
67
73
 
@@ -100,6 +106,10 @@ module WebMock
100
106
  super
101
107
  end
102
108
 
109
+ def terminate
110
+ force_reset
111
+ end
112
+
103
113
  def send(request)
104
114
  request_signature = Plugin.build_webmock_request_signature(request)
105
115
  WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
@@ -108,8 +118,14 @@ module WebMock
108
118
  response = Plugin.build_from_webmock_response(request, mock_response)
109
119
  WebMock::CallbackRegistry.invoke_callbacks({ lib: :httpx }, request_signature, mock_response)
110
120
  log { "mocking #{request.uri} with #{mock_response.inspect}" }
121
+ request.transition(:headers)
122
+ request.transition(:body)
123
+ request.transition(:trailers)
124
+ request.transition(:done)
111
125
  request.response = response
112
126
  request.emit(:response, response)
127
+ request_signature.headers = request.headers.to_h
128
+
113
129
  response << mock_response.body.dup unless response.is_a?(HTTPX::ErrorResponse)
114
130
  elsif WebMock.net_connect_allowed?(request_signature.uri)
115
131
  if WebMock::CallbackRegistry.any_callbacks?
@@ -4,7 +4,7 @@ module HTTPX
4
4
  module Callbacks
5
5
  def on(type, &action)
6
6
  callbacks(type) << action
7
- self
7
+ action
8
8
  end
9
9
 
10
10
  def once(type, &block)
@@ -12,15 +12,10 @@ module HTTPX
12
12
  block.call(*args, &callback)
13
13
  :delete
14
14
  end
15
- self
16
- end
17
-
18
- def only(type, &block)
19
- callbacks(type).clear
20
- on(type, &block)
21
15
  end
22
16
 
23
17
  def emit(type, *args)
18
+ log { "emit #{type.inspect} callbacks" } if respond_to?(:log)
24
19
  callbacks(type).delete_if { |pr| :delete == pr.call(*args) } # rubocop:disable Style/YodaCondition
25
20
  end
26
21
 
@@ -73,7 +73,7 @@ module HTTPX
73
73
  ].include?(callback)
74
74
 
75
75
  warn "DEPRECATION WARNING: calling `.#{meth}` on plain HTTPX sessions is deprecated. " \
76
- "Use HTTPX.plugin(:callbacks).#{meth} instead."
76
+ "Use `HTTPX.plugin(:callbacks).#{meth}` instead."
77
77
 
78
78
  plugin(:callbacks).__send__(meth, *args, **options, &blk)
79
79
  else
@@ -101,4 +101,6 @@ module HTTPX
101
101
  end
102
102
  end
103
103
  end
104
+
105
+ extend Chainable
104
106
  end
@@ -15,7 +15,7 @@ module HTTPX
15
15
  attr_accessor :max_concurrent_requests
16
16
 
17
17
  def initialize(buffer, options)
18
- @options = Options.new(options)
18
+ @options = options
19
19
  @max_concurrent_requests = @options.max_concurrent_requests || MAX_REQUESTS
20
20
  @max_requests = @options.max_requests
21
21
  @parser = Parser::HTTP1.new(self)
@@ -146,7 +146,7 @@ module HTTPX
146
146
 
147
147
  response << chunk
148
148
  rescue StandardError => e
149
- error_response = ErrorResponse.new(request, e, request.options)
149
+ error_response = ErrorResponse.new(request, e)
150
150
  request.response = error_response
151
151
  dispatch
152
152
  end
@@ -197,7 +197,7 @@ module HTTPX
197
197
  end
198
198
  end
199
199
 
200
- def handle_error(ex)
200
+ def handle_error(ex, request = nil)
201
201
  if (ex.is_a?(EOFError) || ex.is_a?(TimeoutError)) && @request && @request.response &&
202
202
  !@request.response.headers.key?("content-length") &&
203
203
  !@request.response.headers.key?("transfer-encoding")
@@ -211,11 +211,15 @@ module HTTPX
211
211
  if @pipelining
212
212
  catch(:called) { disable }
213
213
  else
214
- @requests.each do |request|
215
- emit(:error, request, ex)
214
+ @requests.each do |req|
215
+ next if request && request == req
216
+
217
+ emit(:error, req, ex)
216
218
  end
217
- @pending.each do |request|
218
- emit(:error, request, ex)
219
+ @pending.each do |req|
220
+ next if request && request == req
221
+
222
+ emit(:error, req, ex)
219
223
  end
220
224
  end
221
225
  end