httpx 0.21.0 → 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (229) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +0 -48
  3. data/README.md +54 -45
  4. data/doc/release_notes/0_10_0.md +2 -2
  5. data/doc/release_notes/0_11_0.md +3 -5
  6. data/doc/release_notes/0_12_0.md +5 -5
  7. data/doc/release_notes/0_13_0.md +4 -4
  8. data/doc/release_notes/0_14_0.md +2 -2
  9. data/doc/release_notes/0_16_0.md +3 -3
  10. data/doc/release_notes/0_17_0.md +1 -1
  11. data/doc/release_notes/0_18_0.md +4 -4
  12. data/doc/release_notes/0_18_2.md +1 -1
  13. data/doc/release_notes/0_19_0.md +1 -1
  14. data/doc/release_notes/0_20_0.md +1 -1
  15. data/doc/release_notes/0_21_0.md +7 -5
  16. data/doc/release_notes/0_21_1.md +12 -0
  17. data/doc/release_notes/0_22_0.md +13 -0
  18. data/doc/release_notes/0_22_1.md +11 -0
  19. data/doc/release_notes/0_22_2.md +5 -0
  20. data/doc/release_notes/0_22_3.md +55 -0
  21. data/doc/release_notes/0_22_4.md +6 -0
  22. data/doc/release_notes/0_22_5.md +6 -0
  23. data/doc/release_notes/0_23_0.md +42 -0
  24. data/doc/release_notes/0_23_1.md +5 -0
  25. data/doc/release_notes/0_23_2.md +5 -0
  26. data/doc/release_notes/0_23_3.md +6 -0
  27. data/doc/release_notes/0_23_4.md +5 -0
  28. data/doc/release_notes/0_24_0.md +48 -0
  29. data/doc/release_notes/0_24_1.md +12 -0
  30. data/doc/release_notes/0_24_2.md +12 -0
  31. data/doc/release_notes/0_24_3.md +12 -0
  32. data/doc/release_notes/0_24_4.md +18 -0
  33. data/doc/release_notes/0_24_5.md +6 -0
  34. data/doc/release_notes/0_24_6.md +5 -0
  35. data/doc/release_notes/0_24_7.md +10 -0
  36. data/doc/release_notes/1_0_0.md +60 -0
  37. data/doc/release_notes/1_0_1.md +5 -0
  38. data/doc/release_notes/1_0_2.md +7 -0
  39. data/doc/release_notes/1_1_0.md +32 -0
  40. data/doc/release_notes/1_1_1.md +17 -0
  41. data/doc/release_notes/1_1_2.md +12 -0
  42. data/doc/release_notes/1_1_3.md +18 -0
  43. data/doc/release_notes/1_1_4.md +6 -0
  44. data/doc/release_notes/1_1_5.md +12 -0
  45. data/doc/release_notes/1_2_0.md +49 -0
  46. data/doc/release_notes/1_2_1.md +6 -0
  47. data/lib/httpx/adapters/datadog.rb +100 -106
  48. data/lib/httpx/adapters/faraday.rb +143 -107
  49. data/lib/httpx/adapters/sentry.rb +26 -7
  50. data/lib/httpx/adapters/webmock.rb +33 -17
  51. data/lib/httpx/altsvc.rb +61 -24
  52. data/lib/httpx/base64.rb +27 -0
  53. data/lib/httpx/buffer.rb +12 -0
  54. data/lib/httpx/callbacks.rb +5 -3
  55. data/lib/httpx/chainable.rb +54 -39
  56. data/lib/httpx/connection/http1.rb +62 -37
  57. data/lib/httpx/connection/http2.rb +16 -27
  58. data/lib/httpx/connection.rb +213 -120
  59. data/lib/httpx/domain_name.rb +10 -13
  60. data/lib/httpx/errors.rb +34 -2
  61. data/lib/httpx/extensions.rb +4 -134
  62. data/lib/httpx/io/ssl.rb +77 -71
  63. data/lib/httpx/io/tcp.rb +46 -70
  64. data/lib/httpx/io/udp.rb +18 -52
  65. data/lib/httpx/io/unix.rb +6 -13
  66. data/lib/httpx/io.rb +3 -9
  67. data/lib/httpx/loggable.rb +4 -19
  68. data/lib/httpx/options.rb +168 -110
  69. data/lib/httpx/plugins/{authentication → auth}/basic.rb +1 -5
  70. data/lib/httpx/plugins/{authentication → auth}/digest.rb +13 -14
  71. data/lib/httpx/plugins/{authentication → auth}/ntlm.rb +1 -3
  72. data/lib/httpx/plugins/{authentication → auth}/socks5.rb +0 -2
  73. data/lib/httpx/plugins/auth.rb +25 -0
  74. data/lib/httpx/plugins/aws_sdk_authentication.rb +1 -3
  75. data/lib/httpx/plugins/aws_sigv4.rb +5 -6
  76. data/lib/httpx/plugins/basic_auth.rb +29 -0
  77. data/lib/httpx/plugins/brotli.rb +50 -0
  78. data/lib/httpx/plugins/callbacks.rb +91 -0
  79. data/lib/httpx/plugins/circuit_breaker/circuit.rb +40 -16
  80. data/lib/httpx/plugins/circuit_breaker/circuit_store.rb +14 -5
  81. data/lib/httpx/plugins/circuit_breaker.rb +30 -7
  82. data/lib/httpx/plugins/cookies/set_cookie_parser.rb +0 -2
  83. data/lib/httpx/plugins/cookies.rb +20 -10
  84. data/lib/httpx/plugins/{digest_authentication.rb → digest_auth.rb} +11 -12
  85. data/lib/httpx/plugins/expect.rb +15 -13
  86. data/lib/httpx/plugins/follow_redirects.rb +71 -29
  87. data/lib/httpx/plugins/grpc/call.rb +2 -3
  88. data/lib/httpx/plugins/grpc/grpc_encoding.rb +88 -0
  89. data/lib/httpx/plugins/grpc/message.rb +7 -37
  90. data/lib/httpx/plugins/grpc.rb +35 -29
  91. data/lib/httpx/plugins/h2c.rb +25 -18
  92. data/lib/httpx/plugins/internal_telemetry.rb +16 -0
  93. data/lib/httpx/plugins/{ntlm_authentication.rb → ntlm_auth.rb} +7 -5
  94. data/lib/httpx/plugins/oauth.rb +170 -0
  95. data/lib/httpx/plugins/persistent.rb +1 -1
  96. data/lib/httpx/plugins/proxy/http.rb +15 -10
  97. data/lib/httpx/plugins/proxy/socks4.rb +8 -6
  98. data/lib/httpx/plugins/proxy/socks5.rb +10 -8
  99. data/lib/httpx/plugins/proxy.rb +69 -67
  100. data/lib/httpx/plugins/push_promise.rb +1 -1
  101. data/lib/httpx/plugins/rate_limiter.rb +3 -1
  102. data/lib/httpx/plugins/response_cache/file_store.rb +40 -0
  103. data/lib/httpx/plugins/response_cache/store.rb +34 -17
  104. data/lib/httpx/plugins/response_cache.rb +6 -6
  105. data/lib/httpx/plugins/retries.rb +61 -12
  106. data/lib/httpx/plugins/ssrf_filter.rb +142 -0
  107. data/lib/httpx/plugins/stream.rb +27 -32
  108. data/lib/httpx/plugins/upgrade/h2.rb +4 -4
  109. data/lib/httpx/plugins/upgrade.rb +8 -10
  110. data/lib/httpx/plugins/webdav.rb +10 -8
  111. data/lib/httpx/pool.rb +85 -23
  112. data/lib/httpx/punycode.rb +9 -291
  113. data/lib/httpx/request/body.rb +158 -0
  114. data/lib/httpx/request.rb +86 -121
  115. data/lib/httpx/resolver/https.rb +54 -17
  116. data/lib/httpx/resolver/multi.rb +8 -12
  117. data/lib/httpx/resolver/native.rb +163 -70
  118. data/lib/httpx/resolver/resolver.rb +28 -13
  119. data/lib/httpx/resolver/system.rb +15 -10
  120. data/lib/httpx/resolver.rb +38 -16
  121. data/lib/httpx/response/body.rb +242 -0
  122. data/lib/httpx/response/buffer.rb +96 -0
  123. data/lib/httpx/response.rb +113 -211
  124. data/lib/httpx/selector.rb +2 -4
  125. data/lib/httpx/session.rb +91 -64
  126. data/lib/httpx/session_extensions.rb +4 -1
  127. data/lib/httpx/timers.rb +28 -8
  128. data/lib/httpx/transcoder/body.rb +0 -2
  129. data/lib/httpx/transcoder/chunker.rb +0 -1
  130. data/lib/httpx/transcoder/deflate.rb +37 -0
  131. data/lib/httpx/transcoder/form.rb +52 -33
  132. data/lib/httpx/transcoder/gzip.rb +74 -0
  133. data/lib/httpx/transcoder/json.rb +2 -5
  134. data/lib/httpx/transcoder/multipart/decoder.rb +139 -0
  135. data/lib/httpx/{plugins → transcoder}/multipart/encoder.rb +3 -3
  136. data/lib/httpx/{plugins → transcoder}/multipart/mime_type_detector.rb +1 -1
  137. data/lib/httpx/{plugins → transcoder}/multipart/part.rb +3 -2
  138. data/lib/httpx/transcoder/multipart.rb +17 -0
  139. data/lib/httpx/transcoder/utils/body_reader.rb +46 -0
  140. data/lib/httpx/transcoder/utils/deflater.rb +72 -0
  141. data/lib/httpx/transcoder/utils/inflater.rb +19 -0
  142. data/lib/httpx/transcoder/xml.rb +0 -5
  143. data/lib/httpx/transcoder.rb +4 -6
  144. data/lib/httpx/utils.rb +36 -16
  145. data/lib/httpx/version.rb +1 -1
  146. data/lib/httpx.rb +12 -14
  147. data/sig/altsvc.rbs +33 -0
  148. data/sig/buffer.rbs +1 -0
  149. data/sig/callbacks.rbs +3 -3
  150. data/sig/chainable.rbs +10 -9
  151. data/sig/connection/http1.rbs +5 -4
  152. data/sig/connection/http2.rbs +1 -1
  153. data/sig/connection.rbs +46 -24
  154. data/sig/errors.rbs +9 -3
  155. data/sig/httpx.rbs +5 -4
  156. data/sig/io/ssl.rbs +26 -0
  157. data/sig/io/tcp.rbs +60 -0
  158. data/sig/io/udp.rbs +20 -0
  159. data/sig/io/unix.rbs +10 -0
  160. data/sig/options.rbs +28 -12
  161. data/sig/plugins/{authentication → auth}/basic.rbs +0 -2
  162. data/sig/plugins/{authentication → auth}/digest.rbs +2 -1
  163. data/sig/plugins/auth.rbs +13 -0
  164. data/sig/plugins/{basic_authentication.rbs → basic_auth.rbs} +2 -2
  165. data/sig/plugins/brotli.rbs +22 -0
  166. data/sig/plugins/callbacks.rbs +38 -0
  167. data/sig/plugins/circuit_breaker.rbs +13 -3
  168. data/sig/plugins/compression.rbs +6 -4
  169. data/sig/plugins/cookies/jar.rbs +2 -2
  170. data/sig/plugins/cookies.rbs +2 -0
  171. data/sig/plugins/{digest_authentication.rbs → digest_auth.rbs} +2 -2
  172. data/sig/plugins/follow_redirects.rbs +11 -2
  173. data/sig/plugins/grpc/call.rbs +19 -0
  174. data/sig/plugins/grpc/grpc_encoding.rbs +37 -0
  175. data/sig/plugins/grpc/message.rbs +17 -0
  176. data/sig/plugins/grpc.rbs +2 -32
  177. data/sig/plugins/h2c.rbs +1 -1
  178. data/sig/plugins/{ntlm_authentication.rbs → ntlm_auth.rbs} +2 -2
  179. data/sig/plugins/oauth.rbs +54 -0
  180. data/sig/plugins/proxy/socks4.rbs +4 -4
  181. data/sig/plugins/proxy/socks5.rbs +2 -2
  182. data/sig/plugins/proxy/ssh.rbs +1 -1
  183. data/sig/plugins/proxy.rbs +10 -4
  184. data/sig/plugins/response_cache.rbs +12 -3
  185. data/sig/plugins/retries.rbs +28 -8
  186. data/sig/plugins/stream.rbs +24 -17
  187. data/sig/plugins/upgrade.rbs +5 -3
  188. data/sig/pool.rbs +5 -4
  189. data/sig/request/body.rbs +40 -0
  190. data/sig/request.rbs +12 -28
  191. data/sig/resolver/https.rbs +7 -2
  192. data/sig/resolver/native.rbs +10 -4
  193. data/sig/resolver/resolver.rbs +6 -4
  194. data/sig/resolver/system.rbs +2 -0
  195. data/sig/resolver.rbs +9 -5
  196. data/sig/response/body.rbs +53 -0
  197. data/sig/response/buffer.rbs +24 -0
  198. data/sig/response.rbs +17 -38
  199. data/sig/session.rbs +24 -18
  200. data/sig/timers.rbs +17 -7
  201. data/sig/transcoder/body.rbs +4 -3
  202. data/sig/transcoder/deflate.rbs +11 -0
  203. data/sig/transcoder/form.rbs +5 -3
  204. data/sig/transcoder/gzip.rbs +24 -0
  205. data/sig/transcoder/json.rbs +4 -2
  206. data/sig/{plugins → transcoder}/multipart.rbs +3 -12
  207. data/sig/transcoder/utils/body_reader.rbs +15 -0
  208. data/sig/transcoder/utils/deflater.rbs +29 -0
  209. data/sig/transcoder/utils/inflater.rbs +12 -0
  210. data/sig/transcoder/xml.rbs +1 -1
  211. data/sig/transcoder.rbs +22 -7
  212. data/sig/utils.rbs +2 -0
  213. metadata +127 -40
  214. data/lib/httpx/plugins/authentication.rb +0 -20
  215. data/lib/httpx/plugins/basic_authentication.rb +0 -30
  216. data/lib/httpx/plugins/compression/brotli.rb +0 -54
  217. data/lib/httpx/plugins/compression/deflate.rb +0 -49
  218. data/lib/httpx/plugins/compression/gzip.rb +0 -88
  219. data/lib/httpx/plugins/compression.rb +0 -164
  220. data/lib/httpx/plugins/multipart/decoder.rb +0 -187
  221. data/lib/httpx/plugins/multipart.rb +0 -84
  222. data/lib/httpx/registry.rb +0 -85
  223. data/sig/plugins/authentication.rbs +0 -11
  224. data/sig/plugins/compression/brotli.rbs +0 -21
  225. data/sig/plugins/compression/deflate.rbs +0 -17
  226. data/sig/plugins/compression/gzip.rbs +0 -29
  227. data/sig/registry.rbs +0 -13
  228. /data/sig/plugins/{authentication → auth}/ntlm.rbs +0 -0
  229. /data/sig/plugins/{authentication → auth}/socks5.rbs +0 -0
@@ -1,51 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- if defined?(::DDTrace) && ::DDTrace::VERSION::STRING >= "1.0.0"
4
- require "datadog/tracing/contrib/integration"
5
- require "datadog/tracing/contrib/configuration/settings"
6
- require "datadog/tracing/contrib/patcher"
3
+ require "datadog/tracing/contrib/integration"
4
+ require "datadog/tracing/contrib/configuration/settings"
5
+ require "datadog/tracing/contrib/patcher"
7
6
 
8
- TRACING_MODULE = Datadog::Tracing
9
- else
10
-
11
- require "ddtrace/contrib/integration"
12
- require "ddtrace/contrib/configuration/settings"
13
- require "ddtrace/contrib/patcher"
14
-
15
- TRACING_MODULE = Datadog
16
- end
17
-
18
- module TRACING_MODULE # rubocop:disable Naming/ClassAndModuleCamelCase
7
+ module Datadog::Tracing
19
8
  module Contrib
20
9
  module HTTPX
21
- if defined?(::DDTrace) && ::DDTrace::VERSION::STRING >= "1.0.0"
22
- METADATA_MODULE = TRACING_MODULE::Metadata
23
-
24
- TYPE_OUTBOUND = TRACING_MODULE::Metadata::Ext::HTTP::TYPE_OUTBOUND
25
-
26
- TAG_PEER_SERVICE = TRACING_MODULE::Metadata::Ext::TAG_PEER_SERVICE
10
+ METADATA_MODULE = Datadog::Tracing::Metadata
27
11
 
28
- TAG_URL = TRACING_MODULE::Metadata::Ext::HTTP::TAG_URL
29
- TAG_METHOD = TRACING_MODULE::Metadata::Ext::HTTP::TAG_METHOD
30
- TAG_TARGET_HOST = TRACING_MODULE::Metadata::Ext::NET::TAG_TARGET_HOST
31
- TAG_TARGET_PORT = TRACING_MODULE::Metadata::Ext::NET::TAG_TARGET_PORT
12
+ TYPE_OUTBOUND = Datadog::Tracing::Metadata::Ext::HTTP::TYPE_OUTBOUND
32
13
 
33
- TAG_STATUS_CODE = TRACING_MODULE::Metadata::Ext::HTTP::TAG_STATUS_CODE
14
+ TAG_PEER_SERVICE = Datadog::Tracing::Metadata::Ext::TAG_PEER_SERVICE
34
15
 
35
- else
16
+ TAG_URL = Datadog::Tracing::Metadata::Ext::HTTP::TAG_URL
17
+ TAG_METHOD = Datadog::Tracing::Metadata::Ext::HTTP::TAG_METHOD
18
+ TAG_TARGET_HOST = Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_HOST
19
+ TAG_TARGET_PORT = Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_PORT
36
20
 
37
- METADATA_MODULE = Datadog
38
-
39
- TYPE_OUTBOUND = TRACING_MODULE::Ext::HTTP::TYPE_OUTBOUND
40
- TAG_PEER_SERVICE = TRACING_MODULE::Ext::Integration::TAG_PEER_SERVICE
41
- TAG_URL = TRACING_MODULE::Ext::HTTP::URL
42
- TAG_METHOD = TRACING_MODULE::Ext::HTTP::METHOD
43
- TAG_TARGET_HOST = TRACING_MODULE::Ext::NET::TARGET_HOST
44
- TAG_TARGET_PORT = TRACING_MODULE::Ext::NET::TARGET_PORT
45
- TAG_STATUS_CODE = Datadog::Ext::HTTP::STATUS_CODE
46
- PROPAGATOR = TRACING_MODULE::HTTPPropagator
47
-
48
- end
21
+ TAG_STATUS_CODE = Datadog::Tracing::Metadata::Ext::HTTP::TAG_STATUS_CODE
49
22
 
50
23
  # HTTPX Datadog Plugin
51
24
  #
@@ -64,14 +37,18 @@ module TRACING_MODULE # rubocop:disable Naming/ClassAndModuleCamelCase
64
37
  end
65
38
 
66
39
  def call
67
- return unless tracing_enabled?
40
+ return unless Datadog::Tracing.enabled?
68
41
 
69
42
  @request.on(:response, &method(:finish))
70
43
 
71
- verb = @request.verb.to_s.upcase
44
+ verb = @request.verb
72
45
  uri = @request.uri
73
46
 
74
- @span = build_span
47
+ @span = Datadog::Tracing.trace(
48
+ SPAN_REQUEST,
49
+ service: service_name(@request.uri.host, configuration, Datadog.configuration_for(self)),
50
+ span_type: TYPE_OUTBOUND
51
+ )
75
52
 
76
53
  @span.resource = verb
77
54
 
@@ -86,7 +63,8 @@ module TRACING_MODULE # rubocop:disable Naming/ClassAndModuleCamelCase
86
63
  # Tag as an external peer service
87
64
  @span.set_tag(TAG_PEER_SERVICE, @span.service)
88
65
 
89
- propagate_headers if @configuration[:distributed_tracing]
66
+ Datadog::Tracing::Propagation::HTTP.inject!(Datadog::Tracing.active_trace,
67
+ @request.headers) if @configuration[:distributed_tracing]
90
68
 
91
69
  # Set analytics sample rate
92
70
  if Contrib::Analytics.enabled?(@configuration[:analytics_enabled])
@@ -113,54 +91,24 @@ module TRACING_MODULE # rubocop:disable Naming/ClassAndModuleCamelCase
113
91
 
114
92
  private
115
93
 
116
- if defined?(::DDTrace) && ::DDTrace::VERSION::STRING >= "1.0.0"
117
-
118
- def build_span
119
- TRACING_MODULE.trace(
120
- SPAN_REQUEST,
121
- service: service_name(@request.uri.host, configuration, Datadog.configuration_for(self)),
122
- span_type: TYPE_OUTBOUND
123
- )
124
- end
125
-
126
- def propagate_headers
127
- TRACING_MODULE::Propagation::HTTP.inject!(TRACING_MODULE.active_trace, @request.headers)
128
- end
129
-
130
- def configuration
131
- @configuration ||= Datadog.configuration.tracing[:httpx, @request.uri.host]
132
- end
133
-
134
- def tracing_enabled?
135
- TRACING_MODULE.enabled?
136
- end
137
- else
138
- def build_span
139
- service_name = configuration[:split_by_domain] ? @request.uri.host : configuration[:service_name]
140
- configuration[:tracer].trace(
141
- SPAN_REQUEST,
142
- service: service_name,
143
- span_type: TYPE_OUTBOUND
144
- )
145
- end
146
-
147
- def propagate_headers
148
- Datadog::HTTPPropagator.inject!(@span.context, @request.headers)
149
- end
94
+ def configuration
95
+ @configuration ||= Datadog.configuration.tracing[:httpx, @request.uri.host]
96
+ end
97
+ end
150
98
 
151
- def configuration
152
- @configuration ||= Datadog.configuration[:httpx, @request.uri.host]
153
- end
99
+ module RequestMethods
100
+ def __datadog_enable_trace!
101
+ return if @__datadog_enable_trace
154
102
 
155
- def tracing_enabled?
156
- configuration[:tracer].enabled
157
- end
103
+ RequestTracer.new(self).call
104
+ @__datadog_enable_trace = true
158
105
  end
159
106
  end
160
107
 
161
108
  module ConnectionMethods
162
109
  def send(request)
163
- RequestTracer.new(request).call
110
+ request.__datadog_enable_trace!
111
+
164
112
  super
165
113
  end
166
114
  end
@@ -169,7 +117,7 @@ module TRACING_MODULE # rubocop:disable Naming/ClassAndModuleCamelCase
169
117
  module Configuration
170
118
  # Default settings for httpx
171
119
  #
172
- class Settings < TRACING_MODULE::Contrib::Configuration::Settings
120
+ class Settings < Datadog::Tracing::Contrib::Configuration::Settings
173
121
  DEFAULT_ERROR_HANDLER = lambda do |response|
174
122
  Datadog::Ext::HTTP::ERROR_RANGE.cover?(response.status)
175
123
  end
@@ -178,29 +126,82 @@ module TRACING_MODULE # rubocop:disable Naming/ClassAndModuleCamelCase
178
126
  option :distributed_tracing, default: true
179
127
  option :split_by_domain, default: false
180
128
 
181
- option :enabled do |o|
182
- o.default { env_to_bool("DD_TRACE_HTTPX_ENABLED", true) }
183
- o.lazy
184
- end
129
+ if Gem::Version.new(DDTrace::VERSION::STRING) >= Gem::Version.new("1.13.0")
130
+ option :enabled do |o|
131
+ o.type :bool
132
+ o.env "DD_TRACE_HTTPX_ENABLED"
133
+ o.default true
134
+ end
135
+
136
+ option :analytics_enabled do |o|
137
+ o.type :bool
138
+ o.env "DD_TRACE_HTTPX_ANALYTICS_ENABLED"
139
+ o.default false
140
+ end
141
+
142
+ option :analytics_sample_rate do |o|
143
+ o.type :float
144
+ o.env "DD_TRACE_HTTPX_ANALYTICS_SAMPLE_RATE"
145
+ o.default 1.0
146
+ end
147
+ else
148
+ option :enabled do |o|
149
+ o.default { env_to_bool("DD_TRACE_HTTPX_ENABLED", true) }
150
+ o.lazy
151
+ end
152
+
153
+ option :analytics_enabled do |o|
154
+ o.default { env_to_bool(%w[DD_TRACE_HTTPX_ANALYTICS_ENABLED DD_HTTPX_ANALYTICS_ENABLED], false) }
155
+ o.lazy
156
+ end
185
157
 
186
- option :analytics_enabled do |o|
187
- o.default { env_to_bool(%w[DD_TRACE_HTTPX_ANALYTICS_ENABLED DD_HTTPX_ANALYTICS_ENABLED], false) }
188
- o.lazy
158
+ option :analytics_sample_rate do |o|
159
+ o.default { env_to_float(%w[DD_TRACE_HTTPX_ANALYTICS_SAMPLE_RATE DD_HTTPX_ANALYTICS_SAMPLE_RATE], 1.0) }
160
+ o.lazy
161
+ end
189
162
  end
190
163
 
191
- option :analytics_sample_rate do |o|
192
- o.default { env_to_float(%w[DD_TRACE_HTTPX_ANALYTICS_SAMPLE_RATE DD_HTTPX_ANALYTICS_SAMPLE_RATE], 1.0) }
193
- o.lazy
164
+ if defined?(Datadog::Tracing::Contrib::SpanAttributeSchema)
165
+ option :service_name do |o|
166
+ o.default do
167
+ Datadog::Tracing::Contrib::SpanAttributeSchema.fetch_service_name(
168
+ "DD_TRACE_HTTPX_SERVICE_NAME",
169
+ "httpx"
170
+ )
171
+ end
172
+ o.lazy
173
+ end
174
+ else
175
+ option :service_name do |o|
176
+ o.default do
177
+ ENV.fetch("DD_TRACE_HTTPX_SERVICE_NAME", "httpx")
178
+ end
179
+ o.lazy
180
+ end
194
181
  end
195
182
 
196
- option :error_handler, default: DEFAULT_ERROR_HANDLER
183
+ option :distributed_tracing, default: true
184
+
185
+ if Gem::Version.new(DDTrace::VERSION::STRING) >= Gem::Version.new("1.15.0")
186
+ option :error_handler do |o|
187
+ o.type :proc
188
+ o.default_proc(&DEFAULT_ERROR_HANDLER)
189
+ end
190
+ elsif Gem::Version.new(DDTrace::VERSION::STRING) >= Gem::Version.new("1.13.0")
191
+ option :error_handler do |o|
192
+ o.type :proc
193
+ o.experimental_default_proc(&DEFAULT_ERROR_HANDLER)
194
+ end
195
+ else
196
+ option :error_handler, default: DEFAULT_ERROR_HANDLER
197
+ end
197
198
  end
198
199
  end
199
200
 
200
201
  # Patcher enables patching of 'httpx' with datadog components.
201
202
  #
202
203
  module Patcher
203
- include TRACING_MODULE::Contrib::Patcher
204
+ include Datadog::Tracing::Contrib::Patcher
204
205
 
205
206
  module_function
206
207
 
@@ -223,7 +224,6 @@ module TRACING_MODULE # rubocop:disable Naming/ClassAndModuleCamelCase
223
224
  class Integration
224
225
  include Contrib::Integration
225
226
 
226
- # MINIMUM_VERSION = Gem::Version.new('0.11.0')
227
227
  MINIMUM_VERSION = Gem::Version.new("0.10.2")
228
228
 
229
229
  register_as :httpx
@@ -240,14 +240,8 @@ module TRACING_MODULE # rubocop:disable Naming/ClassAndModuleCamelCase
240
240
  super && version >= MINIMUM_VERSION
241
241
  end
242
242
 
243
- if defined?(::DDTrace) && ::DDTrace::VERSION::STRING >= "1.0.0"
244
- def new_configuration
245
- Configuration::Settings.new
246
- end
247
- else
248
- def default_configuration
249
- Configuration::Settings.new
250
- end
243
+ def new_configuration
244
+ Configuration::Settings.new
251
245
  end
252
246
 
253
247
  def patcher
@@ -7,36 +7,54 @@ require "faraday"
7
7
  module Faraday
8
8
  class Adapter
9
9
  class HTTPX < Faraday::Adapter
10
- # :nocov:
11
- SSL_ERROR = if defined?(Faraday::SSLError)
12
- Faraday::SSLError
13
- else
14
- Faraday::Error::SSLError
15
- end
10
+ module RequestMixin
11
+ def build_connection(env)
12
+ return @connection if defined?(@connection)
16
13
 
17
- CONNECTION_FAILED_ERROR = if defined?(Faraday::ConnectionFailed)
18
- Faraday::ConnectionFailed
19
- else
20
- Faraday::Error::ConnectionFailed
21
- end
22
- # :nocov:
14
+ @connection = ::HTTPX.plugin(:persistent).plugin(ReasonPlugin)
15
+ @connection = @connection.with(@connection_options) unless @connection_options.empty?
16
+ connection_opts = options_from_env(env)
23
17
 
24
- unless Faraday::RequestOptions.method_defined?(:stream_response?)
25
- module RequestOptionsExtensions
26
- refine Faraday::RequestOptions do
27
- def stream_response?
28
- false
29
- end
18
+ if (bind = env.request.bind)
19
+ @bind = TCPSocket.new(bind[:host], bind[:port])
20
+ connection_opts[:io] = @bind
21
+ end
22
+ @connection = @connection.with(connection_opts)
23
+
24
+ if (proxy = env.request.proxy)
25
+ proxy_options = { uri: proxy.uri }
26
+ proxy_options[:username] = proxy.user if proxy.user
27
+ proxy_options[:password] = proxy.password if proxy.password
28
+
29
+ @connection = @connection.plugin(:proxy).with(proxy: proxy_options)
30
30
  end
31
+ @connection = @connection.plugin(OnDataPlugin) if env.request.stream_response?
32
+
33
+ @connection
31
34
  end
32
- using RequestOptionsExtensions
33
- end
34
35
 
35
- module RequestMixin
36
- using ::HTTPX::HashExtensions
36
+ def close
37
+ @connection.close if @connection
38
+ @bind.close if @bind
39
+ end
37
40
 
38
41
  private
39
42
 
43
+ def connect(env, &blk)
44
+ connection(env, &blk)
45
+ rescue ::HTTPX::TLSError => e
46
+ raise Faraday::SSLError, e
47
+ rescue Errno::ECONNABORTED,
48
+ Errno::ECONNREFUSED,
49
+ Errno::ECONNRESET,
50
+ Errno::EHOSTUNREACH,
51
+ Errno::EINVAL,
52
+ Errno::ENETUNREACH,
53
+ Errno::EPIPE,
54
+ ::HTTPX::ConnectionError => e
55
+ raise Faraday::ConnectionFailed, e
56
+ end
57
+
40
58
  def build_request(env)
41
59
  meth = env[:method]
42
60
 
@@ -44,32 +62,53 @@ module Faraday
44
62
  headers: env.request_headers,
45
63
  body: env.body,
46
64
  }
47
- [meth, env.url, request_options]
65
+ [meth.to_s.upcase, env.url, request_options]
48
66
  end
49
67
 
50
68
  def options_from_env(env)
51
- timeout_options = {
52
- connect_timeout: env.request.open_timeout,
53
- operation_timeout: env.request.timeout,
54
- }.compact
69
+ timeout_options = {}
70
+ req_opts = env.request
71
+ if (sec = request_timeout(:read, req_opts))
72
+ timeout_options[:read_timeout] = sec
73
+ end
55
74
 
56
- options = {
57
- ssl: {},
75
+ if (sec = request_timeout(:write, req_opts))
76
+ timeout_options[:write_timeout] = sec
77
+ end
78
+
79
+ if (sec = request_timeout(:open, req_opts))
80
+ timeout_options[:connect_timeout] = sec
81
+ end
82
+
83
+ {
84
+ ssl: ssl_options_from_env(env),
58
85
  timeout: timeout_options,
59
86
  }
87
+ end
88
+
89
+ if defined?(::OpenSSL)
90
+ def ssl_options_from_env(env)
91
+ ssl_options = {}
92
+
93
+ unless env.ssl.verify.nil?
94
+ ssl_options[:verify_mode] = env.ssl.verify ? OpenSSL::SSL::VERIFY_PEER : OpenSSL::SSL::VERIFY_NONE
95
+ end
60
96
 
61
- options[:ssl][:verify_mode] = OpenSSL::SSL::VERIFY_PEER if env.ssl.verify
62
- options[:ssl][:ca_file] = env.ssl.ca_file if env.ssl.ca_file
63
- options[:ssl][:ca_path] = env.ssl.ca_path if env.ssl.ca_path
64
- options[:ssl][:cert_store] = env.ssl.cert_store if env.ssl.cert_store
65
- options[:ssl][:cert] = env.ssl.client_cert if env.ssl.client_cert
66
- options[:ssl][:key] = env.ssl.client_key if env.ssl.client_key
67
- options[:ssl][:ssl_version] = env.ssl.version if env.ssl.version
68
- options[:ssl][:verify_depth] = env.ssl.verify_depth if env.ssl.verify_depth
69
- options[:ssl][:min_version] = env.ssl.min_version if env.ssl.min_version
70
- options[:ssl][:max_version] = env.ssl.max_version if env.ssl.max_version
71
-
72
- options
97
+ ssl_options[:ca_file] = env.ssl.ca_file if env.ssl.ca_file
98
+ ssl_options[:ca_path] = env.ssl.ca_path if env.ssl.ca_path
99
+ ssl_options[:cert_store] = env.ssl.cert_store if env.ssl.cert_store
100
+ ssl_options[:cert] = env.ssl.client_cert if env.ssl.client_cert
101
+ ssl_options[:key] = env.ssl.client_key if env.ssl.client_key
102
+ ssl_options[:ssl_version] = env.ssl.version if env.ssl.version
103
+ ssl_options[:verify_depth] = env.ssl.verify_depth if env.ssl.verify_depth
104
+ ssl_options[:min_version] = env.ssl.min_version if env.ssl.min_version
105
+ ssl_options[:max_version] = env.ssl.max_version if env.ssl.max_version
106
+ ssl_options
107
+ end
108
+ else
109
+ def ssl_options_from_env(*)
110
+ {}
111
+ end
73
112
  end
74
113
  end
75
114
 
@@ -100,32 +139,17 @@ module Faraday
100
139
  end
101
140
 
102
141
  module ReasonPlugin
103
- if RUBY_VERSION < "2.5"
104
- def self.load_dependencies(*)
105
- require "webrick"
106
- end
107
- else
108
- def self.load_dependencies(*)
109
- require "net/http/status"
110
- end
142
+ def self.load_dependencies(*)
143
+ require "net/http/status"
111
144
  end
145
+
112
146
  module ResponseMethods
113
- if RUBY_VERSION < "2.5"
114
- def reason
115
- WEBrick::HTTPStatus::StatusMessage.fetch(@status)
116
- end
117
- else
118
- def reason
119
- Net::HTTP::STATUS_CODES.fetch(@status)
120
- end
147
+ def reason
148
+ Net::HTTP::STATUS_CODES.fetch(@status)
121
149
  end
122
150
  end
123
151
  end
124
152
 
125
- def self.session
126
- @session ||= ::HTTPX.plugin(:compression).plugin(:persistent).plugin(ReasonPlugin)
127
- end
128
-
129
153
  class ParallelManager
130
154
  class ResponseHandler < SimpleDelegator
131
155
  attr_reader :env
@@ -158,8 +182,9 @@ module Faraday
158
182
 
159
183
  include RequestMixin
160
184
 
161
- def initialize
185
+ def initialize(options)
162
186
  @handlers = []
187
+ @connection_options = options
163
188
  end
164
189
 
165
190
  def enqueue(request)
@@ -169,85 +194,96 @@ module Faraday
169
194
  end
170
195
 
171
196
  def run
197
+ return unless @handlers.last
198
+
172
199
  env = @handlers.last.env
173
200
 
174
- session = HTTPX.session.with(options_from_env(env))
175
- session = session.plugin(:proxy).with(proxy: { uri: env.request.proxy }) if env.request.proxy
176
- session = session.plugin(OnDataPlugin) if env.request.stream_response?
201
+ connect(env) do |session|
202
+ requests = @handlers.map { |handler| session.build_request(*build_request(handler.env)) }
177
203
 
178
- requests = @handlers.map { |handler| session.build_request(*build_request(handler.env)) }
204
+ if env.request.stream_response?
205
+ requests.each do |request|
206
+ request.response_on_data = env.request.on_data
207
+ end
208
+ end
179
209
 
180
- if env.request.stream_response?
181
- requests.each do |request|
182
- request.response_on_data = env.request.on_data
210
+ responses = session.request(*requests)
211
+ Array(responses).each_with_index do |response, index|
212
+ handler = @handlers[index]
213
+ handler.on_response.call(response)
214
+ handler.on_complete.call(handler.env)
183
215
  end
184
216
  end
217
+ rescue ::HTTPX::TimeoutError => e
218
+ raise Faraday::TimeoutError, e
219
+ end
185
220
 
186
- responses = session.request(*requests)
187
- Array(responses).each_with_index do |response, index|
188
- handler = @handlers[index]
189
- handler.on_response.call(response)
190
- handler.on_complete.call(handler.env)
191
- end
221
+ # from Faraday::Adapter#connection
222
+ def connection(env)
223
+ conn = build_connection(env)
224
+ return conn unless block_given?
225
+
226
+ yield conn
227
+ end
228
+
229
+ private
230
+
231
+ # from Faraday::Adapter#request_timeout
232
+ def request_timeout(type, options)
233
+ key = Faraday::Adapter::TIMEOUT_KEYS[type]
234
+ options[key] || options[:timeout]
192
235
  end
193
236
  end
194
237
 
195
238
  self.supports_parallel = true
196
239
 
197
240
  class << self
198
- def setup_parallel_manager
199
- ParallelManager.new
241
+ def setup_parallel_manager(options = {})
242
+ ParallelManager.new(options)
200
243
  end
201
244
  end
202
245
 
203
- def initialize(app, options = {})
204
- super(app)
205
- @session_options = options
206
- end
207
-
208
246
  def call(env)
209
247
  super
210
248
  if parallel?(env)
211
249
  handler = env[:parallel_manager].enqueue(env)
212
250
  handler.on_response do |response|
213
- response.raise_for_status
214
- save_response(env, response.status, response.body.to_s, response.headers, response.reason) do |response_headers|
215
- response_headers.merge!(response.headers)
251
+ if response.is_a?(::HTTPX::Response)
252
+ save_response(env, response.status, response.body.to_s, response.headers, response.reason) do |response_headers|
253
+ response_headers.merge!(response.headers)
254
+ end
255
+ else
256
+ env[:error] = response.error
257
+ save_response(env, 0, "", {}, nil)
216
258
  end
217
259
  end
218
260
  return handler
219
261
  end
220
262
 
221
- session = HTTPX.session
222
- session = session.with(@session_options) unless @session_options.empty?
223
- session = session.with(options_from_env(env))
224
- session = session.plugin(:proxy).with(proxy: { uri: env.request.proxy }) if env.request.proxy
225
- session = session.plugin(OnDataPlugin) if env.request.stream_response?
226
-
227
- request = session.build_request(*build_request(env))
228
-
229
- request.response_on_data = env.request.on_data if env.request.stream_response?
230
-
231
- response = session.request(request)
232
- response.raise_for_status unless response.is_a?(::HTTPX::Response)
263
+ response = connect_and_request(env)
233
264
  save_response(env, response.status, response.body.to_s, response.headers, response.reason) do |response_headers|
234
265
  response_headers.merge!(response.headers)
235
266
  end
236
267
  @app.call(env)
237
- rescue ::HTTPX::TLSError => e
238
- raise SSL_ERROR, e
239
- rescue Errno::ECONNABORTED,
240
- Errno::ECONNREFUSED,
241
- Errno::ECONNRESET,
242
- Errno::EHOSTUNREACH,
243
- Errno::EINVAL,
244
- Errno::ENETUNREACH,
245
- Errno::EPIPE => e
246
- raise CONNECTION_FAILED_ERROR, e
247
268
  end
248
269
 
249
270
  private
250
271
 
272
+ def connect_and_request(env)
273
+ connect(env) do |session|
274
+ request = session.build_request(*build_request(env))
275
+
276
+ request.response_on_data = env.request.on_data if env.request.stream_response?
277
+
278
+ response = session.request(request)
279
+ # do not call #raise_for_status for HTTP 4xx or 5xx, as faraday has a middleware for that.
280
+ response.raise_for_status unless response.is_a?(::HTTPX::Response)
281
+ response
282
+ end
283
+ rescue ::HTTPX::TimeoutError => e
284
+ raise Faraday::TimeoutError, e
285
+ end
286
+
251
287
  def parallel?(env)
252
288
  env[:parallel_manager]
253
289
  end