httpx 1.2.3 → 1.2.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.
- checksums.yaml +4 -4
- data/doc/release_notes/1_2_4.md +8 -0
- data/lib/httpx/adapters/datadog.rb +140 -45
- data/lib/httpx/altsvc.rb +2 -2
- data/lib/httpx/connection/http1.rb +1 -1
- data/lib/httpx/connection.rb +1 -1
- data/lib/httpx/plugins/auth/digest.rb +2 -1
- data/lib/httpx/plugins/aws_sigv4.rb +2 -2
- data/lib/httpx/response.rb +5 -0
- data/lib/httpx/version.rb +1 -1
- data/sig/response.rbs +1 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7d5abc65b9f6377dbcefbe9170c7c47ef3555b4286c2d9c5e6e521467a75d57e
|
4
|
+
data.tar.gz: 7dfac2d6aa4ed5ecba31479ec0750de9d310657c39e12efd57f62d1544d9d1b7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 720fe0c6f0883d0755122ae8009da116f7b06b0f009b56480cf3f1f80ef998e4671d6f53ce039e6d52f502c596e22fa524d6292a3372c8bd3a7f88616f6aaffc
|
7
|
+
data.tar.gz: 75fdb8eee5568a3be2fdd19a4750b18166d2eb25749a0a1cde672b0deab76d1e64c8d573665488b7d2db99d4de73f387583a75ad5a957be9529dfef4b36f11ac
|
@@ -0,0 +1,8 @@
|
|
1
|
+
# 1.2.4
|
2
|
+
|
3
|
+
## Bugfixes
|
4
|
+
|
5
|
+
* fixed issue related to inability to buffer payload to error responses (which may happen on certain error handling situations).
|
6
|
+
* fixed recovery from a lost persistent connection leaving process due to ping being sent while still marked as inactive.
|
7
|
+
* fixed datadog integration, which was not generating new spans on retried requests (when `:retries` plugin is enabled).
|
8
|
+
* fixed splitting strings into key value pairs in cases where the value would contain a "=", such as in certain base64 payloads.
|
@@ -7,6 +7,8 @@ require "datadog/tracing/contrib/patcher"
|
|
7
7
|
module Datadog::Tracing
|
8
8
|
module Contrib
|
9
9
|
module HTTPX
|
10
|
+
DATADOG_VERSION = defined?(::DDTrace) ? ::DDTrace::VERSION : ::Datadog::VERSION
|
11
|
+
|
10
12
|
METADATA_MODULE = Datadog::Tracing::Metadata
|
11
13
|
|
12
14
|
TYPE_OUTBOUND = Datadog::Tracing::Metadata::Ext::HTTP::TYPE_OUTBOUND
|
@@ -22,9 +24,10 @@ module Datadog::Tracing
|
|
22
24
|
|
23
25
|
# HTTPX Datadog Plugin
|
24
26
|
#
|
25
|
-
# Enables tracing for httpx requests.
|
26
|
-
#
|
27
|
-
#
|
27
|
+
# Enables tracing for httpx requests.
|
28
|
+
#
|
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.
|
28
31
|
#
|
29
32
|
module Plugin
|
30
33
|
class RequestTracer
|
@@ -32,82 +35,174 @@ module Datadog::Tracing
|
|
32
35
|
|
33
36
|
SPAN_REQUEST = "httpx.request"
|
34
37
|
|
38
|
+
# initializes the tracer object on the +request+.
|
35
39
|
def initialize(request)
|
36
40
|
@request = request
|
41
|
+
@start_time = nil
|
42
|
+
|
43
|
+
# request objects are reused, when already buffered requests get rerouted to a different
|
44
|
+
# connection due to connection issues, or when they already got a response, but need to
|
45
|
+
# be retried. In such situations, the original span needs to be extended for the former,
|
46
|
+
# while a new is required for the latter.
|
47
|
+
request.on(:idle) { reset }
|
48
|
+
# the span is initialized when the request is buffered in the parser, which is the closest
|
49
|
+
# one gets to actually sending the request.
|
50
|
+
request.on(:headers) { call }
|
37
51
|
end
|
38
52
|
|
39
|
-
|
40
|
-
|
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)
|
58
|
+
|
59
|
+
@request.once(:response, &method(:finish))
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
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
|
69
|
+
|
70
|
+
# resets the start time for already finished request transactions.
|
71
|
+
def reset
|
72
|
+
return unless @start_time
|
73
|
+
|
74
|
+
start
|
75
|
+
end
|
41
76
|
|
42
|
-
|
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
|
43
83
|
|
84
|
+
return unless span
|
85
|
+
|
86
|
+
if response.is_a?(::HTTPX::ErrorResponse)
|
87
|
+
span.set_error(response.error)
|
88
|
+
else
|
89
|
+
span.set_tag(TAG_STATUS_CODE, response.status.to_s)
|
90
|
+
|
91
|
+
span.set_error(::HTTPX::HTTPError.new(response)) if response.status >= 400 && response.status <= 599
|
92
|
+
end
|
93
|
+
|
94
|
+
span.finish
|
95
|
+
ensure
|
96
|
+
@start_time = nil
|
97
|
+
end
|
98
|
+
|
99
|
+
# return a span initialized with the +@request+ state.
|
100
|
+
def initialize_span
|
44
101
|
verb = @request.verb
|
45
102
|
uri = @request.uri
|
46
103
|
|
47
|
-
|
48
|
-
SPAN_REQUEST,
|
49
|
-
service: service_name(@request.uri.host, configuration, Datadog.configuration_for(self)),
|
50
|
-
span_type: TYPE_OUTBOUND
|
51
|
-
)
|
104
|
+
span = create_span(@request)
|
52
105
|
|
53
|
-
|
106
|
+
span.resource = verb
|
54
107
|
|
55
108
|
# Add additional request specific tags to the span.
|
56
109
|
|
57
|
-
|
58
|
-
|
110
|
+
span.set_tag(TAG_URL, @request.path)
|
111
|
+
span.set_tag(TAG_METHOD, verb)
|
59
112
|
|
60
|
-
|
61
|
-
|
113
|
+
span.set_tag(TAG_TARGET_HOST, uri.host)
|
114
|
+
span.set_tag(TAG_TARGET_PORT, uri.port.to_s)
|
62
115
|
|
63
116
|
# Tag as an external peer service
|
64
|
-
|
117
|
+
span.set_tag(TAG_PEER_SERVICE, span.service)
|
65
118
|
|
66
|
-
|
67
|
-
|
119
|
+
if configuration[:distributed_tracing]
|
120
|
+
propagate_trace_http(
|
121
|
+
Datadog::Tracing.active_trace.to_digest,
|
122
|
+
@request.headers
|
123
|
+
)
|
124
|
+
end
|
68
125
|
|
69
126
|
# Set analytics sample rate
|
70
|
-
if Contrib::Analytics.enabled?(
|
71
|
-
Contrib::Analytics.set_sample_rate(
|
127
|
+
if Contrib::Analytics.enabled?(configuration[:analytics_enabled])
|
128
|
+
Contrib::Analytics.set_sample_rate(span, configuration[:analytics_sample_rate])
|
72
129
|
end
|
130
|
+
|
131
|
+
span
|
73
132
|
rescue StandardError => e
|
74
133
|
Datadog.logger.error("error preparing span for http request: #{e}")
|
75
134
|
Datadog.logger.error(e.backtrace)
|
76
135
|
end
|
77
136
|
|
78
|
-
def
|
79
|
-
|
137
|
+
def now
|
138
|
+
::Datadog::Core::Utils::Time.now.utc
|
139
|
+
end
|
80
140
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
@span.set_tag(TAG_STATUS_CODE, response.status.to_s)
|
141
|
+
def configuration
|
142
|
+
@configuration ||= Datadog.configuration.tracing[:httpx, @request.uri.host]
|
143
|
+
end
|
85
144
|
|
86
|
-
|
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)
|
87
148
|
end
|
88
149
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
150
|
+
def create_span(request)
|
151
|
+
Datadog::Tracing.trace(
|
152
|
+
SPAN_REQUEST,
|
153
|
+
service: service_name(request.uri.host, configuration, Datadog.configuration_for(self)),
|
154
|
+
type: TYPE_OUTBOUND,
|
155
|
+
start_time: @start_time
|
156
|
+
)
|
157
|
+
end
|
158
|
+
else
|
159
|
+
def propagate_trace_http(digest, headers)
|
160
|
+
Datadog::Tracing::Propagation::HTTP.inject!(digest, headers)
|
161
|
+
end
|
93
162
|
|
94
|
-
|
95
|
-
|
163
|
+
def create_span(request)
|
164
|
+
Datadog::Tracing.trace(
|
165
|
+
SPAN_REQUEST,
|
166
|
+
service: service_name(request.uri.host, configuration, Datadog.configuration_for(self)),
|
167
|
+
span_type: TYPE_OUTBOUND,
|
168
|
+
start_time: @start_time
|
169
|
+
)
|
170
|
+
end
|
96
171
|
end
|
97
172
|
end
|
98
173
|
|
99
174
|
module RequestMethods
|
100
|
-
|
101
|
-
|
175
|
+
# intercepts request initialization to inject the tracing logic.
|
176
|
+
def initialize(*)
|
177
|
+
super
|
102
178
|
|
103
|
-
|
104
|
-
|
179
|
+
return unless Datadog::Tracing.enabled?
|
180
|
+
|
181
|
+
RequestTracer.new(self)
|
105
182
|
end
|
106
183
|
end
|
107
184
|
|
108
185
|
module ConnectionMethods
|
109
|
-
|
110
|
-
|
186
|
+
attr_reader :init_time
|
187
|
+
|
188
|
+
def initialize(*)
|
189
|
+
super
|
190
|
+
|
191
|
+
@init_time = ::Datadog::Core::Utils::Time.now.utc
|
192
|
+
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
|
111
206
|
|
112
207
|
super
|
113
208
|
end
|
@@ -126,7 +221,7 @@ module Datadog::Tracing
|
|
126
221
|
option :distributed_tracing, default: true
|
127
222
|
option :split_by_domain, default: false
|
128
223
|
|
129
|
-
if Gem::Version.new(
|
224
|
+
if Gem::Version.new(DATADOG_VERSION::STRING) >= Gem::Version.new("1.13.0")
|
130
225
|
option :enabled do |o|
|
131
226
|
o.type :bool
|
132
227
|
o.env "DD_TRACE_HTTPX_ENABLED"
|
@@ -169,25 +264,25 @@ module Datadog::Tracing
|
|
169
264
|
"httpx"
|
170
265
|
)
|
171
266
|
end
|
172
|
-
o.lazy unless Gem::Version.new(
|
267
|
+
o.lazy unless Gem::Version.new(DATADOG_VERSION::STRING) >= Gem::Version.new("1.13.0")
|
173
268
|
end
|
174
269
|
else
|
175
270
|
option :service_name do |o|
|
176
271
|
o.default do
|
177
272
|
ENV.fetch("DD_TRACE_HTTPX_SERVICE_NAME", "httpx")
|
178
273
|
end
|
179
|
-
o.lazy unless Gem::Version.new(
|
274
|
+
o.lazy unless Gem::Version.new(DATADOG_VERSION::STRING) >= Gem::Version.new("1.13.0")
|
180
275
|
end
|
181
276
|
end
|
182
277
|
|
183
278
|
option :distributed_tracing, default: true
|
184
279
|
|
185
|
-
if Gem::Version.new(
|
280
|
+
if Gem::Version.new(DATADOG_VERSION::STRING) >= Gem::Version.new("1.15.0")
|
186
281
|
option :error_handler do |o|
|
187
282
|
o.type :proc
|
188
283
|
o.default_proc(&DEFAULT_ERROR_HANDLER)
|
189
284
|
end
|
190
|
-
elsif Gem::Version.new(
|
285
|
+
elsif Gem::Version.new(DATADOG_VERSION::STRING) >= Gem::Version.new("1.13.0")
|
191
286
|
option :error_handler do |o|
|
192
287
|
o.type :proc
|
193
288
|
o.experimental_default_proc(&DEFAULT_ERROR_HANDLER)
|
data/lib/httpx/altsvc.rb
CHANGED
@@ -131,9 +131,9 @@ module HTTPX
|
|
131
131
|
scanner.skip(/;/)
|
132
132
|
break if scanner.eos? || scanner.scan(/ *, */)
|
133
133
|
end
|
134
|
-
alt_params = Hash[alt_params.map { |field| field.split("=") }]
|
134
|
+
alt_params = Hash[alt_params.map { |field| field.split("=", 2) }]
|
135
135
|
|
136
|
-
alt_proto, alt_authority = alt_service.split("=")
|
136
|
+
alt_proto, alt_authority = alt_service.split("=", 2)
|
137
137
|
alt_origin = parse_altsvc_origin(alt_proto, alt_authority)
|
138
138
|
return unless alt_origin
|
139
139
|
|
data/lib/httpx/connection.rb
CHANGED
@@ -241,8 +241,8 @@ module HTTPX
|
|
241
241
|
# for such cases, we want to ping for availability before deciding to shovel requests.
|
242
242
|
log(level: 3) { "keep alive timeout expired, pinging connection..." }
|
243
243
|
@pending << request
|
244
|
-
parser.ping
|
245
244
|
transition(:active) if @state == :inactive
|
245
|
+
parser.ping
|
246
246
|
return
|
247
247
|
end
|
248
248
|
|
@@ -30,7 +30,8 @@ module HTTPX
|
|
30
30
|
auth_info = authenticate[/^(\w+) (.*)/, 2]
|
31
31
|
|
32
32
|
params = auth_info.split(/ *, */)
|
33
|
-
.to_h { |val| val.split("="
|
33
|
+
.to_h { |val| val.split("=", 2) }
|
34
|
+
.transform_values { |v| v.delete("\"") }
|
34
35
|
nonce = params["nonce"]
|
35
36
|
nc = next_nonce
|
36
37
|
|
@@ -197,8 +197,8 @@ module HTTPX
|
|
197
197
|
params.each.with_index.sort do |a, b|
|
198
198
|
a, a_offset = a
|
199
199
|
b, b_offset = b
|
200
|
-
a_name, a_value = a.split("=")
|
201
|
-
b_name, b_value = b.split("=")
|
200
|
+
a_name, a_value = a.split("=", 2)
|
201
|
+
b_name, b_value = b.split("=", 2)
|
202
202
|
if a_name == b_name
|
203
203
|
if a_value == b_value
|
204
204
|
a_offset <=> b_offset
|
data/lib/httpx/response.rb
CHANGED
data/lib/httpx/version.rb
CHANGED
data/sig/response.rbs
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: httpx
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tiago Cardoso
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-04-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: http-2-next
|
@@ -141,6 +141,7 @@ extra_rdoc_files:
|
|
141
141
|
- doc/release_notes/1_2_1.md
|
142
142
|
- doc/release_notes/1_2_2.md
|
143
143
|
- doc/release_notes/1_2_3.md
|
144
|
+
- doc/release_notes/1_2_4.md
|
144
145
|
files:
|
145
146
|
- LICENSE.txt
|
146
147
|
- README.md
|
@@ -253,6 +254,7 @@ files:
|
|
253
254
|
- doc/release_notes/1_2_1.md
|
254
255
|
- doc/release_notes/1_2_2.md
|
255
256
|
- doc/release_notes/1_2_3.md
|
257
|
+
- doc/release_notes/1_2_4.md
|
256
258
|
- lib/httpx.rb
|
257
259
|
- lib/httpx/adapters/datadog.rb
|
258
260
|
- lib/httpx/adapters/faraday.rb
|