httpx-patched 1.6.2.1

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 (336) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +191 -0
  3. data/README.md +162 -0
  4. data/doc/release_notes/0_0_1.md +7 -0
  5. data/doc/release_notes/0_0_2.md +9 -0
  6. data/doc/release_notes/0_0_3.md +9 -0
  7. data/doc/release_notes/0_0_4.md +7 -0
  8. data/doc/release_notes/0_0_5.md +5 -0
  9. data/doc/release_notes/0_10_0.md +66 -0
  10. data/doc/release_notes/0_10_1.md +37 -0
  11. data/doc/release_notes/0_10_2.md +5 -0
  12. data/doc/release_notes/0_11_0.md +74 -0
  13. data/doc/release_notes/0_11_1.md +5 -0
  14. data/doc/release_notes/0_11_2.md +5 -0
  15. data/doc/release_notes/0_11_3.md +5 -0
  16. data/doc/release_notes/0_12_0.md +55 -0
  17. data/doc/release_notes/0_13_0.md +58 -0
  18. data/doc/release_notes/0_13_1.md +5 -0
  19. data/doc/release_notes/0_13_2.md +9 -0
  20. data/doc/release_notes/0_14_0.md +79 -0
  21. data/doc/release_notes/0_14_1.md +7 -0
  22. data/doc/release_notes/0_14_2.md +6 -0
  23. data/doc/release_notes/0_14_3.md +5 -0
  24. data/doc/release_notes/0_14_4.md +5 -0
  25. data/doc/release_notes/0_14_5.md +11 -0
  26. data/doc/release_notes/0_15_0.md +53 -0
  27. data/doc/release_notes/0_15_1.md +8 -0
  28. data/doc/release_notes/0_15_2.md +9 -0
  29. data/doc/release_notes/0_15_3.md +5 -0
  30. data/doc/release_notes/0_15_4.md +5 -0
  31. data/doc/release_notes/0_16_0.md +93 -0
  32. data/doc/release_notes/0_16_1.md +5 -0
  33. data/doc/release_notes/0_17_0.md +49 -0
  34. data/doc/release_notes/0_18_0.md +69 -0
  35. data/doc/release_notes/0_18_1.md +12 -0
  36. data/doc/release_notes/0_18_2.md +10 -0
  37. data/doc/release_notes/0_18_3.md +7 -0
  38. data/doc/release_notes/0_18_4.md +14 -0
  39. data/doc/release_notes/0_18_5.md +10 -0
  40. data/doc/release_notes/0_18_6.md +5 -0
  41. data/doc/release_notes/0_18_7.md +5 -0
  42. data/doc/release_notes/0_19_0.md +39 -0
  43. data/doc/release_notes/0_19_1.md +5 -0
  44. data/doc/release_notes/0_19_2.md +7 -0
  45. data/doc/release_notes/0_19_3.md +6 -0
  46. data/doc/release_notes/0_19_4.md +14 -0
  47. data/doc/release_notes/0_19_5.md +13 -0
  48. data/doc/release_notes/0_19_6.md +5 -0
  49. data/doc/release_notes/0_19_7.md +5 -0
  50. data/doc/release_notes/0_19_8.md +5 -0
  51. data/doc/release_notes/0_1_0.md +9 -0
  52. data/doc/release_notes/0_20_0.md +36 -0
  53. data/doc/release_notes/0_20_1.md +5 -0
  54. data/doc/release_notes/0_20_2.md +7 -0
  55. data/doc/release_notes/0_20_3.md +6 -0
  56. data/doc/release_notes/0_20_4.md +17 -0
  57. data/doc/release_notes/0_20_5.md +3 -0
  58. data/doc/release_notes/0_21_0.md +96 -0
  59. data/doc/release_notes/0_21_1.md +12 -0
  60. data/doc/release_notes/0_22_0.md +13 -0
  61. data/doc/release_notes/0_22_1.md +11 -0
  62. data/doc/release_notes/0_22_2.md +5 -0
  63. data/doc/release_notes/0_22_3.md +55 -0
  64. data/doc/release_notes/0_22_4.md +6 -0
  65. data/doc/release_notes/0_22_5.md +6 -0
  66. data/doc/release_notes/0_23_0.md +42 -0
  67. data/doc/release_notes/0_23_1.md +5 -0
  68. data/doc/release_notes/0_23_2.md +5 -0
  69. data/doc/release_notes/0_23_3.md +6 -0
  70. data/doc/release_notes/0_23_4.md +5 -0
  71. data/doc/release_notes/0_24_0.md +48 -0
  72. data/doc/release_notes/0_24_1.md +12 -0
  73. data/doc/release_notes/0_24_2.md +12 -0
  74. data/doc/release_notes/0_24_3.md +12 -0
  75. data/doc/release_notes/0_24_4.md +18 -0
  76. data/doc/release_notes/0_24_5.md +6 -0
  77. data/doc/release_notes/0_24_6.md +5 -0
  78. data/doc/release_notes/0_24_7.md +10 -0
  79. data/doc/release_notes/0_2_0.md +5 -0
  80. data/doc/release_notes/0_2_1.md +16 -0
  81. data/doc/release_notes/0_3_0.md +12 -0
  82. data/doc/release_notes/0_3_1.md +6 -0
  83. data/doc/release_notes/0_4_0.md +51 -0
  84. data/doc/release_notes/0_4_1.md +3 -0
  85. data/doc/release_notes/0_5_0.md +15 -0
  86. data/doc/release_notes/0_5_1.md +14 -0
  87. data/doc/release_notes/0_6_0.md +5 -0
  88. data/doc/release_notes/0_6_1.md +6 -0
  89. data/doc/release_notes/0_6_2.md +6 -0
  90. data/doc/release_notes/0_6_3.md +13 -0
  91. data/doc/release_notes/0_6_4.md +21 -0
  92. data/doc/release_notes/0_6_5.md +22 -0
  93. data/doc/release_notes/0_6_6.md +19 -0
  94. data/doc/release_notes/0_6_7.md +5 -0
  95. data/doc/release_notes/0_7_0.md +46 -0
  96. data/doc/release_notes/0_8_0.md +27 -0
  97. data/doc/release_notes/0_8_1.md +8 -0
  98. data/doc/release_notes/0_8_2.md +7 -0
  99. data/doc/release_notes/0_9_0.md +38 -0
  100. data/doc/release_notes/1_0_0.md +60 -0
  101. data/doc/release_notes/1_0_1.md +5 -0
  102. data/doc/release_notes/1_0_2.md +7 -0
  103. data/doc/release_notes/1_1_0.md +32 -0
  104. data/doc/release_notes/1_1_1.md +17 -0
  105. data/doc/release_notes/1_1_2.md +12 -0
  106. data/doc/release_notes/1_1_3.md +18 -0
  107. data/doc/release_notes/1_1_4.md +6 -0
  108. data/doc/release_notes/1_1_5.md +12 -0
  109. data/doc/release_notes/1_2_0.md +49 -0
  110. data/doc/release_notes/1_2_1.md +6 -0
  111. data/doc/release_notes/1_2_2.md +10 -0
  112. data/doc/release_notes/1_2_3.md +16 -0
  113. data/doc/release_notes/1_2_4.md +8 -0
  114. data/doc/release_notes/1_2_5.md +7 -0
  115. data/doc/release_notes/1_2_6.md +13 -0
  116. data/doc/release_notes/1_3_0.md +18 -0
  117. data/doc/release_notes/1_3_1.md +17 -0
  118. data/doc/release_notes/1_3_2.md +6 -0
  119. data/doc/release_notes/1_3_3.md +5 -0
  120. data/doc/release_notes/1_3_4.md +6 -0
  121. data/doc/release_notes/1_4_0.md +43 -0
  122. data/doc/release_notes/1_4_1.md +19 -0
  123. data/doc/release_notes/1_4_2.md +20 -0
  124. data/doc/release_notes/1_4_3.md +11 -0
  125. data/doc/release_notes/1_4_4.md +14 -0
  126. data/doc/release_notes/1_5_0.md +126 -0
  127. data/doc/release_notes/1_5_1.md +6 -0
  128. data/doc/release_notes/1_6_0.md +50 -0
  129. data/doc/release_notes/1_6_1.md +17 -0
  130. data/doc/release_notes/1_6_2.md +11 -0
  131. data/lib/httpx/adapters/datadog.rb +359 -0
  132. data/lib/httpx/adapters/faraday.rb +303 -0
  133. data/lib/httpx/adapters/sentry.rb +121 -0
  134. data/lib/httpx/adapters/webmock.rb +175 -0
  135. data/lib/httpx/altsvc.rb +163 -0
  136. data/lib/httpx/base64.rb +27 -0
  137. data/lib/httpx/buffer.rb +61 -0
  138. data/lib/httpx/callbacks.rb +35 -0
  139. data/lib/httpx/chainable.rb +106 -0
  140. data/lib/httpx/connection/http1.rb +399 -0
  141. data/lib/httpx/connection/http2.rb +468 -0
  142. data/lib/httpx/connection.rb +954 -0
  143. data/lib/httpx/domain_name.rb +145 -0
  144. data/lib/httpx/errors.rb +111 -0
  145. data/lib/httpx/extensions.rb +59 -0
  146. data/lib/httpx/headers.rb +176 -0
  147. data/lib/httpx/io/ssl.rb +163 -0
  148. data/lib/httpx/io/tcp.rb +239 -0
  149. data/lib/httpx/io/udp.rb +62 -0
  150. data/lib/httpx/io/unix.rb +71 -0
  151. data/lib/httpx/io.rb +11 -0
  152. data/lib/httpx/loggable.rb +56 -0
  153. data/lib/httpx/options.rb +463 -0
  154. data/lib/httpx/parser/http1.rb +186 -0
  155. data/lib/httpx/plugins/auth/basic.rb +20 -0
  156. data/lib/httpx/plugins/auth/digest.rb +102 -0
  157. data/lib/httpx/plugins/auth/ntlm.rb +35 -0
  158. data/lib/httpx/plugins/auth/socks5.rb +22 -0
  159. data/lib/httpx/plugins/auth.rb +25 -0
  160. data/lib/httpx/plugins/aws_sdk_authentication.rb +111 -0
  161. data/lib/httpx/plugins/aws_sigv4.rb +239 -0
  162. data/lib/httpx/plugins/basic_auth.rb +29 -0
  163. data/lib/httpx/plugins/brotli.rb +50 -0
  164. data/lib/httpx/plugins/callbacks.rb +127 -0
  165. data/lib/httpx/plugins/circuit_breaker/circuit.rb +100 -0
  166. data/lib/httpx/plugins/circuit_breaker/circuit_store.rb +53 -0
  167. data/lib/httpx/plugins/circuit_breaker.rb +147 -0
  168. data/lib/httpx/plugins/content_digest.rb +204 -0
  169. data/lib/httpx/plugins/cookies/cookie.rb +174 -0
  170. data/lib/httpx/plugins/cookies/jar.rb +95 -0
  171. data/lib/httpx/plugins/cookies/set_cookie_parser.rb +143 -0
  172. data/lib/httpx/plugins/cookies.rb +107 -0
  173. data/lib/httpx/plugins/digest_auth.rb +67 -0
  174. data/lib/httpx/plugins/expect.rb +120 -0
  175. data/lib/httpx/plugins/fiber_concurrency.rb +195 -0
  176. data/lib/httpx/plugins/follow_redirects.rb +233 -0
  177. data/lib/httpx/plugins/grpc/call.rb +63 -0
  178. data/lib/httpx/plugins/grpc/grpc_encoding.rb +90 -0
  179. data/lib/httpx/plugins/grpc/message.rb +55 -0
  180. data/lib/httpx/plugins/grpc.rb +282 -0
  181. data/lib/httpx/plugins/h2c.rb +127 -0
  182. data/lib/httpx/plugins/internal_telemetry.rb +107 -0
  183. data/lib/httpx/plugins/ntlm_auth.rb +62 -0
  184. data/lib/httpx/plugins/oauth.rb +183 -0
  185. data/lib/httpx/plugins/persistent.rb +82 -0
  186. data/lib/httpx/plugins/proxy/http.rb +184 -0
  187. data/lib/httpx/plugins/proxy/socks4.rb +135 -0
  188. data/lib/httpx/plugins/proxy/socks5.rb +194 -0
  189. data/lib/httpx/plugins/proxy/ssh.rb +94 -0
  190. data/lib/httpx/plugins/proxy.rb +349 -0
  191. data/lib/httpx/plugins/push_promise.rb +81 -0
  192. data/lib/httpx/plugins/query.rb +35 -0
  193. data/lib/httpx/plugins/rate_limiter.rb +55 -0
  194. data/lib/httpx/plugins/response_cache/file_store.rb +140 -0
  195. data/lib/httpx/plugins/response_cache/store.rb +33 -0
  196. data/lib/httpx/plugins/response_cache.rb +333 -0
  197. data/lib/httpx/plugins/retries.rb +230 -0
  198. data/lib/httpx/plugins/ssrf_filter.rb +145 -0
  199. data/lib/httpx/plugins/stream.rb +183 -0
  200. data/lib/httpx/plugins/stream_bidi.rb +315 -0
  201. data/lib/httpx/plugins/upgrade/h2.rb +64 -0
  202. data/lib/httpx/plugins/upgrade.rb +86 -0
  203. data/lib/httpx/plugins/webdav.rb +86 -0
  204. data/lib/httpx/plugins/xml.rb +76 -0
  205. data/lib/httpx/pmatch_extensions.rb +33 -0
  206. data/lib/httpx/pool.rb +190 -0
  207. data/lib/httpx/punycode.rb +22 -0
  208. data/lib/httpx/request/body.rb +158 -0
  209. data/lib/httpx/request.rb +328 -0
  210. data/lib/httpx/resolver/entry.rb +30 -0
  211. data/lib/httpx/resolver/https.rb +256 -0
  212. data/lib/httpx/resolver/multi.rb +102 -0
  213. data/lib/httpx/resolver/native.rb +547 -0
  214. data/lib/httpx/resolver/resolver.rb +173 -0
  215. data/lib/httpx/resolver/system.rb +255 -0
  216. data/lib/httpx/resolver.rb +189 -0
  217. data/lib/httpx/response/body.rb +242 -0
  218. data/lib/httpx/response/buffer.rb +115 -0
  219. data/lib/httpx/response.rb +304 -0
  220. data/lib/httpx/selector.rb +282 -0
  221. data/lib/httpx/session.rb +612 -0
  222. data/lib/httpx/session_extensions.rb +30 -0
  223. data/lib/httpx/timers.rb +133 -0
  224. data/lib/httpx/transcoder/body.rb +43 -0
  225. data/lib/httpx/transcoder/chunker.rb +115 -0
  226. data/lib/httpx/transcoder/deflate.rb +37 -0
  227. data/lib/httpx/transcoder/form.rb +68 -0
  228. data/lib/httpx/transcoder/gzip.rb +71 -0
  229. data/lib/httpx/transcoder/json.rb +71 -0
  230. data/lib/httpx/transcoder/multipart/decoder.rb +141 -0
  231. data/lib/httpx/transcoder/multipart/encoder.rb +120 -0
  232. data/lib/httpx/transcoder/multipart/mime_type_detector.rb +78 -0
  233. data/lib/httpx/transcoder/multipart/part.rb +35 -0
  234. data/lib/httpx/transcoder/multipart.rb +31 -0
  235. data/lib/httpx/transcoder/utils/body_reader.rb +46 -0
  236. data/lib/httpx/transcoder/utils/deflater.rb +75 -0
  237. data/lib/httpx/transcoder.rb +91 -0
  238. data/lib/httpx/utils.rb +75 -0
  239. data/lib/httpx/version.rb +5 -0
  240. data/lib/httpx.rb +66 -0
  241. data/sig/altsvc.rbs +33 -0
  242. data/sig/buffer.rbs +27 -0
  243. data/sig/callbacks.rbs +15 -0
  244. data/sig/chainable.rbs +55 -0
  245. data/sig/connection/http1.rbs +85 -0
  246. data/sig/connection/http2.rbs +116 -0
  247. data/sig/connection.rbs +169 -0
  248. data/sig/domain_name.rbs +17 -0
  249. data/sig/errors.rbs +69 -0
  250. data/sig/headers.rbs +49 -0
  251. data/sig/httpx.rbs +27 -0
  252. data/sig/io/ssl.rbs +27 -0
  253. data/sig/io/tcp.rbs +72 -0
  254. data/sig/io/udp.rbs +25 -0
  255. data/sig/io/unix.rbs +26 -0
  256. data/sig/io.rbs +3 -0
  257. data/sig/loggable.rbs +17 -0
  258. data/sig/options.rbs +202 -0
  259. data/sig/parser/http1.rbs +59 -0
  260. data/sig/plugins/auth/basic.rbs +17 -0
  261. data/sig/plugins/auth/digest.rbs +25 -0
  262. data/sig/plugins/auth/ntlm.rbs +20 -0
  263. data/sig/plugins/auth/socks5.rbs +18 -0
  264. data/sig/plugins/auth.rbs +13 -0
  265. data/sig/plugins/aws_sdk_authentication.rbs +43 -0
  266. data/sig/plugins/aws_sigv4.rbs +78 -0
  267. data/sig/plugins/basic_auth.rbs +15 -0
  268. data/sig/plugins/brotli.rbs +22 -0
  269. data/sig/plugins/callbacks.rbs +38 -0
  270. data/sig/plugins/circuit_breaker.rbs +71 -0
  271. data/sig/plugins/compression.rbs +57 -0
  272. data/sig/plugins/content_digest.rbs +51 -0
  273. data/sig/plugins/cookies/cookie.rbs +55 -0
  274. data/sig/plugins/cookies/jar.rbs +26 -0
  275. data/sig/plugins/cookies/set_cookie_parser.rbs +22 -0
  276. data/sig/plugins/cookies.rbs +28 -0
  277. data/sig/plugins/digest_auth.rbs +21 -0
  278. data/sig/plugins/expect.rbs +15 -0
  279. data/sig/plugins/fiber_concurrency.rbs +51 -0
  280. data/sig/plugins/follow_redirects.rbs +47 -0
  281. data/sig/plugins/grpc/call.rbs +23 -0
  282. data/sig/plugins/grpc/grpc_encoding.rbs +37 -0
  283. data/sig/plugins/grpc/message.rbs +17 -0
  284. data/sig/plugins/grpc.rbs +65 -0
  285. data/sig/plugins/h2c.rbs +27 -0
  286. data/sig/plugins/ntlm_auth.rbs +21 -0
  287. data/sig/plugins/oauth.rbs +68 -0
  288. data/sig/plugins/persistent.rbs +14 -0
  289. data/sig/plugins/proxy/http.rbs +30 -0
  290. data/sig/plugins/proxy/socks4.rbs +37 -0
  291. data/sig/plugins/proxy/socks5.rbs +49 -0
  292. data/sig/plugins/proxy/ssh.rbs +18 -0
  293. data/sig/plugins/proxy.rbs +70 -0
  294. data/sig/plugins/push_promise.rbs +23 -0
  295. data/sig/plugins/query.rbs +18 -0
  296. data/sig/plugins/rate_limiter.rbs +13 -0
  297. data/sig/plugins/response_cache/file_store.rbs +19 -0
  298. data/sig/plugins/response_cache/store.rbs +13 -0
  299. data/sig/plugins/response_cache.rbs +86 -0
  300. data/sig/plugins/retries.rbs +66 -0
  301. data/sig/plugins/ssrf_filter.rbs +26 -0
  302. data/sig/plugins/stream.rbs +54 -0
  303. data/sig/plugins/stream_bidi.rbs +68 -0
  304. data/sig/plugins/upgrade/h2.rbs +9 -0
  305. data/sig/plugins/upgrade.rbs +29 -0
  306. data/sig/plugins/webdav.rbs +23 -0
  307. data/sig/plugins/xml.rbs +37 -0
  308. data/sig/pool.rbs +51 -0
  309. data/sig/punycode.rbs +5 -0
  310. data/sig/request/body.rbs +34 -0
  311. data/sig/request.rbs +88 -0
  312. data/sig/resolver/entry.rbs +13 -0
  313. data/sig/resolver/https.rbs +45 -0
  314. data/sig/resolver/multi.rbs +32 -0
  315. data/sig/resolver/native.rbs +74 -0
  316. data/sig/resolver/resolver.rbs +64 -0
  317. data/sig/resolver/system.rbs +34 -0
  318. data/sig/resolver.rbs +48 -0
  319. data/sig/response/body.rbs +52 -0
  320. data/sig/response/buffer.rbs +23 -0
  321. data/sig/response.rbs +103 -0
  322. data/sig/selector.rbs +68 -0
  323. data/sig/session.rbs +104 -0
  324. data/sig/timers.rbs +54 -0
  325. data/sig/transcoder/body.rbs +24 -0
  326. data/sig/transcoder/chunker.rbs +49 -0
  327. data/sig/transcoder/deflate.rbs +12 -0
  328. data/sig/transcoder/form.rbs +34 -0
  329. data/sig/transcoder/gzip.rbs +27 -0
  330. data/sig/transcoder/json.rbs +28 -0
  331. data/sig/transcoder/multipart.rbs +103 -0
  332. data/sig/transcoder/utils/body_reader.rbs +15 -0
  333. data/sig/transcoder/utils/deflater.rbs +28 -0
  334. data/sig/transcoder.rbs +43 -0
  335. data/sig/utils.rbs +19 -0
  336. metadata +518 -0
@@ -0,0 +1,359 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "datadog/tracing/contrib/integration"
4
+ require "datadog/tracing/contrib/configuration/settings"
5
+ require "datadog/tracing/contrib/patcher"
6
+
7
+ module Datadog::Tracing
8
+ module Contrib
9
+ module HTTPX
10
+ DATADOG_VERSION = defined?(::DDTrace) ? ::DDTrace::VERSION : ::Datadog::VERSION
11
+
12
+ METADATA_MODULE = Datadog::Tracing::Metadata
13
+
14
+ TYPE_OUTBOUND = Datadog::Tracing::Metadata::Ext::HTTP::TYPE_OUTBOUND
15
+
16
+ TAG_BASE_SERVICE = if Gem::Version.new(DATADOG_VERSION::STRING) < Gem::Version.new("1.15.0")
17
+ "_dd.base_service"
18
+ else
19
+ Datadog::Tracing::Contrib::Ext::Metadata::TAG_BASE_SERVICE
20
+ end
21
+ TAG_PEER_HOSTNAME = Datadog::Tracing::Metadata::Ext::TAG_PEER_HOSTNAME
22
+
23
+ TAG_KIND = Datadog::Tracing::Metadata::Ext::TAG_KIND
24
+ TAG_CLIENT = Datadog::Tracing::Metadata::Ext::SpanKind::TAG_CLIENT
25
+ TAG_COMPONENT = Datadog::Tracing::Metadata::Ext::TAG_COMPONENT
26
+ TAG_OPERATION = Datadog::Tracing::Metadata::Ext::TAG_OPERATION
27
+ TAG_URL = Datadog::Tracing::Metadata::Ext::HTTP::TAG_URL
28
+ TAG_METHOD = Datadog::Tracing::Metadata::Ext::HTTP::TAG_METHOD
29
+ TAG_TARGET_HOST = Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_HOST
30
+ TAG_TARGET_PORT = Datadog::Tracing::Metadata::Ext::NET::TAG_TARGET_PORT
31
+
32
+ TAG_STATUS_CODE = Datadog::Tracing::Metadata::Ext::HTTP::TAG_STATUS_CODE
33
+
34
+ # HTTPX Datadog Plugin
35
+ #
36
+ # Enables tracing for httpx requests.
37
+ #
38
+ # A span will be created for each request transaction; the span is created lazily only when
39
+ # buffering a request, and it is fed the start time stored inside the tracer object.
40
+ #
41
+ module Plugin
42
+ module RequestTracer
43
+ extend Contrib::HttpAnnotationHelper
44
+
45
+ module_function
46
+
47
+ SPAN_REQUEST = "httpx.request"
48
+
49
+ # initializes tracing on the +request+.
50
+ def call(request)
51
+ return unless configuration(request).enabled
52
+
53
+ span = nil
54
+
55
+ # request objects are reused, when already buffered requests get rerouted to a different
56
+ # connection due to connection issues, or when they already got a response, but need to
57
+ # be retried. In such situations, the original span needs to be extended for the former,
58
+ # while a new is required for the latter.
59
+ request.on(:idle) do
60
+ span = nil
61
+ end
62
+ # the span is initialized when the request is buffered in the parser, which is the closest
63
+ # one gets to actually sending the request.
64
+ request.on(:headers) do
65
+ next if span
66
+
67
+ span = initialize_span(request, now)
68
+ end
69
+
70
+ request.on(:response) do |response|
71
+ span = initialize_span(request, request.init_time) if !span && request.init_time
72
+
73
+ finish(response, span)
74
+ end
75
+ end
76
+
77
+ def finish(response, span)
78
+ if response.is_a?(::HTTPX::ErrorResponse)
79
+ span.set_error(response.error)
80
+ else
81
+ span.set_tag(TAG_STATUS_CODE, response.status.to_s)
82
+
83
+ span.set_error(::HTTPX::HTTPError.new(response)) if response.status >= 400 && response.status <= 599
84
+
85
+ span.set_tags(
86
+ Datadog.configuration.tracing.header_tags.response_tags(response.headers.to_h)
87
+ ) if Datadog.configuration.tracing.respond_to?(:header_tags)
88
+ end
89
+
90
+ span.finish
91
+ end
92
+
93
+ # return a span initialized with the +@request+ state.
94
+ def initialize_span(request, start_time)
95
+ verb = request.verb
96
+ uri = request.uri
97
+
98
+ config = configuration(request)
99
+
100
+ span = create_span(request, config, start_time)
101
+
102
+ span.resource = verb
103
+
104
+ # Tag original global service name if not used
105
+ span.set_tag(TAG_BASE_SERVICE, Datadog.configuration.service) if span.service != Datadog.configuration.service
106
+
107
+ span.set_tag(TAG_KIND, TAG_CLIENT)
108
+
109
+ span.set_tag(TAG_COMPONENT, "httpx")
110
+ span.set_tag(TAG_OPERATION, "request")
111
+
112
+ span.set_tag(TAG_URL, request.path)
113
+ span.set_tag(TAG_METHOD, verb)
114
+
115
+ span.set_tag(TAG_TARGET_HOST, uri.host)
116
+ span.set_tag(TAG_TARGET_PORT, uri.port)
117
+
118
+ span.set_tag(TAG_PEER_HOSTNAME, uri.host)
119
+
120
+ # Tag as an external peer service
121
+ # span.set_tag(TAG_PEER_SERVICE, span.service)
122
+
123
+ if config[:distributed_tracing]
124
+ propagate_trace_http(
125
+ Datadog::Tracing.active_trace,
126
+ request.headers
127
+ )
128
+ end
129
+
130
+ # Set analytics sample rate
131
+ if Contrib::Analytics.enabled?(config[:analytics_enabled])
132
+ Contrib::Analytics.set_sample_rate(span, config[:analytics_sample_rate])
133
+ end
134
+
135
+ span.set_tags(
136
+ Datadog.configuration.tracing.header_tags.request_tags(request.headers.to_h)
137
+ ) if Datadog.configuration.tracing.respond_to?(:header_tags)
138
+
139
+ span
140
+ rescue StandardError => e
141
+ Datadog.logger.error("error preparing span for http request: #{e}")
142
+ Datadog.logger.error(e.backtrace)
143
+ end
144
+
145
+ def now
146
+ ::Datadog::Core::Utils::Time.now.utc
147
+ end
148
+
149
+ def configuration(request)
150
+ Datadog.configuration.tracing[:httpx, request.uri.host]
151
+ end
152
+
153
+ if Gem::Version.new(DATADOG_VERSION::STRING) >= Gem::Version.new("2.0.0")
154
+ def propagate_trace_http(trace, headers)
155
+ Datadog::Tracing::Contrib::HTTP.inject(trace, headers)
156
+ end
157
+
158
+ def create_span(request, configuration, start_time)
159
+ Datadog::Tracing.trace(
160
+ SPAN_REQUEST,
161
+ service: service_name(request.uri.host, configuration),
162
+ type: TYPE_OUTBOUND,
163
+ start_time: start_time
164
+ )
165
+ end
166
+ else
167
+ def propagate_trace_http(trace, headers)
168
+ Datadog::Tracing::Propagation::HTTP.inject!(trace.to_digest, headers)
169
+ end
170
+
171
+ def create_span(request, configuration, start_time)
172
+ Datadog::Tracing.trace(
173
+ SPAN_REQUEST,
174
+ service: service_name(request.uri.host, configuration),
175
+ span_type: TYPE_OUTBOUND,
176
+ start_time: start_time
177
+ )
178
+ end
179
+ end
180
+ end
181
+
182
+ module RequestMethods
183
+ attr_accessor :init_time
184
+
185
+ # intercepts request initialization to inject the tracing logic.
186
+ def initialize(*)
187
+ super
188
+
189
+ @init_time = nil
190
+
191
+ return unless Datadog::Tracing.enabled?
192
+
193
+ RequestTracer.call(self)
194
+ end
195
+
196
+ def response=(*)
197
+ # init_time should be set when it's send to a connection.
198
+ # However, there are situations where connection initialization fails.
199
+ # Example is the :ssrf_filter plugin, which raises an error on
200
+ # initialize if the host is an IP which matches against the known set.
201
+ # in such cases, we'll just set here right here.
202
+ @init_time ||= ::Datadog::Core::Utils::Time.now.utc
203
+
204
+ super
205
+ end
206
+ end
207
+
208
+ module ConnectionMethods
209
+ def initialize(*)
210
+ super
211
+
212
+ @init_time = ::Datadog::Core::Utils::Time.now.utc
213
+ end
214
+
215
+ def send(request)
216
+ request.init_time ||= @init_time
217
+
218
+ super
219
+ end
220
+ end
221
+ end
222
+
223
+ module Configuration
224
+ # Default settings for httpx
225
+ #
226
+ class Settings < Datadog::Tracing::Contrib::Configuration::Settings
227
+ DEFAULT_ERROR_HANDLER = lambda do |response|
228
+ Datadog::Ext::HTTP::ERROR_RANGE.cover?(response.status)
229
+ end
230
+
231
+ option :service_name, default: "httpx"
232
+ option :distributed_tracing, default: true
233
+ option :split_by_domain, default: false
234
+
235
+ if Gem::Version.new(DATADOG_VERSION::STRING) >= Gem::Version.new("1.13.0")
236
+ option :enabled do |o|
237
+ o.type :bool
238
+ o.env "DD_TRACE_HTTPX_ENABLED"
239
+ o.default true
240
+ end
241
+
242
+ option :analytics_enabled do |o|
243
+ o.type :bool
244
+ o.env "DD_TRACE_HTTPX_ANALYTICS_ENABLED"
245
+ o.default false
246
+ end
247
+
248
+ option :analytics_sample_rate do |o|
249
+ o.type :float
250
+ o.env "DD_TRACE_HTTPX_ANALYTICS_SAMPLE_RATE"
251
+ o.default 1.0
252
+ end
253
+ else
254
+ option :enabled do |o|
255
+ o.default { env_to_bool("DD_TRACE_HTTPX_ENABLED", true) }
256
+ o.lazy
257
+ end
258
+
259
+ option :analytics_enabled do |o|
260
+ o.default { env_to_bool(%w[DD_TRACE_HTTPX_ANALYTICS_ENABLED DD_HTTPX_ANALYTICS_ENABLED], false) }
261
+ o.lazy
262
+ end
263
+
264
+ option :analytics_sample_rate do |o|
265
+ o.default { env_to_float(%w[DD_TRACE_HTTPX_ANALYTICS_SAMPLE_RATE DD_HTTPX_ANALYTICS_SAMPLE_RATE], 1.0) }
266
+ o.lazy
267
+ end
268
+ end
269
+
270
+ if defined?(Datadog::Tracing::Contrib::SpanAttributeSchema)
271
+ option :service_name do |o|
272
+ o.default do
273
+ Datadog::Tracing::Contrib::SpanAttributeSchema.fetch_service_name(
274
+ "DD_TRACE_HTTPX_SERVICE_NAME",
275
+ "httpx"
276
+ )
277
+ end
278
+ o.lazy unless Gem::Version.new(DATADOG_VERSION::STRING) >= Gem::Version.new("1.13.0")
279
+ end
280
+ else
281
+ option :service_name do |o|
282
+ o.default do
283
+ ENV.fetch("DD_TRACE_HTTPX_SERVICE_NAME", "httpx")
284
+ end
285
+ o.lazy unless Gem::Version.new(DATADOG_VERSION::STRING) >= Gem::Version.new("1.13.0")
286
+ end
287
+ end
288
+
289
+ option :distributed_tracing, default: true
290
+
291
+ if Gem::Version.new(DATADOG_VERSION::STRING) >= Gem::Version.new("1.15.0")
292
+ option :error_handler do |o|
293
+ o.type :proc
294
+ o.default_proc(&DEFAULT_ERROR_HANDLER)
295
+ end
296
+ elsif Gem::Version.new(DATADOG_VERSION::STRING) >= Gem::Version.new("1.13.0")
297
+ option :error_handler do |o|
298
+ o.type :proc
299
+ o.experimental_default_proc(&DEFAULT_ERROR_HANDLER)
300
+ end
301
+ else
302
+ option :error_handler, default: DEFAULT_ERROR_HANDLER
303
+ end
304
+ end
305
+ end
306
+
307
+ # Patcher enables patching of 'httpx' with datadog components.
308
+ #
309
+ module Patcher
310
+ include Datadog::Tracing::Contrib::Patcher
311
+
312
+ module_function
313
+
314
+ def target_version
315
+ Integration.version
316
+ end
317
+
318
+ # loads a session instannce with the datadog plugin, and replaces the
319
+ # base HTTPX::Session with the patched session class.
320
+ def patch
321
+ datadog_session = ::HTTPX.plugin(Plugin)
322
+
323
+ ::HTTPX.send(:remove_const, :Session)
324
+ ::HTTPX.send(:const_set, :Session, datadog_session.class)
325
+ end
326
+ end
327
+
328
+ # Datadog Integration for HTTPX.
329
+ #
330
+ class Integration
331
+ include Contrib::Integration
332
+
333
+ MINIMUM_VERSION = Gem::Version.new("0.10.2")
334
+
335
+ register_as :httpx
336
+
337
+ def self.version
338
+ Gem.loaded_specs["httpx"] && Gem.loaded_specs["httpx"].version
339
+ end
340
+
341
+ def self.loaded?
342
+ defined?(::HTTPX::Request)
343
+ end
344
+
345
+ def self.compatible?
346
+ super && version >= MINIMUM_VERSION
347
+ end
348
+
349
+ def new_configuration
350
+ Configuration::Settings.new
351
+ end
352
+
353
+ def patcher
354
+ Patcher
355
+ end
356
+ end
357
+ end
358
+ end
359
+ end
@@ -0,0 +1,303 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "delegate"
4
+ require "httpx"
5
+ require "faraday"
6
+
7
+ module Faraday
8
+ class Adapter
9
+ class HTTPX < Faraday::Adapter
10
+ def initialize(app = nil, opts = {}, &block)
11
+ @connection = @bind = nil
12
+ super(app, opts, &block)
13
+ end
14
+
15
+ module RequestMixin
16
+ def build_connection(env)
17
+ return @connection if @connection
18
+
19
+ @connection = ::HTTPX.plugin(:persistent).plugin(ReasonPlugin)
20
+ @connection = @connection.with(@connection_options) unless @connection_options.empty?
21
+ connection_opts = options_from_env(env)
22
+
23
+ if (bind = env.request.bind)
24
+ @bind = TCPSocket.new(bind[:host], bind[:port])
25
+ connection_opts[:io] = @bind
26
+ end
27
+ @connection = @connection.with(connection_opts)
28
+
29
+ if (proxy = env.request.proxy)
30
+ proxy_options = { uri: proxy.uri }
31
+ proxy_options[:username] = proxy.user if proxy.user
32
+ proxy_options[:password] = proxy.password if proxy.password
33
+
34
+ @connection = @connection.plugin(:proxy).with(proxy: proxy_options)
35
+ end
36
+ @connection = @connection.plugin(OnDataPlugin) if env.request.stream_response?
37
+
38
+ @connection = @config_block.call(@connection) || @connection if @config_block
39
+ @connection
40
+ end
41
+
42
+ def close
43
+ @connection.close if @connection
44
+ @bind.close if @bind
45
+ end
46
+
47
+ private
48
+
49
+ def connect(env, &blk)
50
+ connection(env, &blk)
51
+ rescue ::HTTPX::TLSError => e
52
+ raise Faraday::SSLError, e
53
+ rescue Errno::ECONNABORTED,
54
+ Errno::ECONNREFUSED,
55
+ Errno::ECONNRESET,
56
+ Errno::EHOSTUNREACH,
57
+ Errno::EINVAL,
58
+ Errno::ENETUNREACH,
59
+ Errno::EPIPE,
60
+ ::HTTPX::ConnectionError => e
61
+ raise Faraday::ConnectionFailed, e
62
+ rescue ::HTTPX::TimeoutError => e
63
+ raise Faraday::TimeoutError, e
64
+ end
65
+
66
+ def build_request(env)
67
+ meth = env[:method]
68
+
69
+ request_options = {
70
+ headers: env.request_headers,
71
+ body: env.body,
72
+ **options_from_env(env),
73
+ }
74
+ [meth.to_s.upcase, env.url, request_options]
75
+ end
76
+
77
+ def options_from_env(env)
78
+ timeout_options = {}
79
+ req_opts = env.request
80
+ if (sec = request_timeout(:read, req_opts))
81
+ timeout_options[:read_timeout] = sec
82
+ end
83
+
84
+ if (sec = request_timeout(:write, req_opts))
85
+ timeout_options[:write_timeout] = sec
86
+ end
87
+
88
+ if (sec = request_timeout(:open, req_opts))
89
+ timeout_options[:connect_timeout] = sec
90
+ end
91
+
92
+ {
93
+ ssl: ssl_options_from_env(env),
94
+ timeout: timeout_options,
95
+ }
96
+ end
97
+
98
+ if defined?(::OpenSSL)
99
+ def ssl_options_from_env(env)
100
+ ssl_options = {}
101
+
102
+ unless env.ssl.verify.nil?
103
+ ssl_options[:verify_mode] = env.ssl.verify ? OpenSSL::SSL::VERIFY_PEER : OpenSSL::SSL::VERIFY_NONE
104
+ end
105
+
106
+ ssl_options[:ca_file] = env.ssl.ca_file if env.ssl.ca_file
107
+ ssl_options[:ca_path] = env.ssl.ca_path if env.ssl.ca_path
108
+ ssl_options[:cert_store] = env.ssl.cert_store if env.ssl.cert_store
109
+ ssl_options[:cert] = env.ssl.client_cert if env.ssl.client_cert
110
+ ssl_options[:key] = env.ssl.client_key if env.ssl.client_key
111
+ ssl_options[:ssl_version] = env.ssl.version if env.ssl.version
112
+ ssl_options[:verify_depth] = env.ssl.verify_depth if env.ssl.verify_depth
113
+ ssl_options[:min_version] = env.ssl.min_version if env.ssl.min_version
114
+ ssl_options[:max_version] = env.ssl.max_version if env.ssl.max_version
115
+ ssl_options
116
+ end
117
+ else
118
+ # :nocov:
119
+ def ssl_options_from_env(*)
120
+ {}
121
+ end
122
+ # :nocov:
123
+ end
124
+ end
125
+
126
+ include RequestMixin
127
+
128
+ module OnDataPlugin
129
+ module RequestMethods
130
+ attr_writer :response_on_data
131
+
132
+ def response=(response)
133
+ super
134
+
135
+ return unless @response
136
+
137
+ return if @response.is_a?(::HTTPX::ErrorResponse)
138
+
139
+ @response.body.on_data = @response_on_data
140
+ end
141
+ end
142
+
143
+ module ResponseBodyMethods
144
+ attr_writer :on_data
145
+
146
+ def write(chunk)
147
+ return super unless @on_data
148
+
149
+ @on_data.call(chunk, chunk.bytesize)
150
+ end
151
+ end
152
+ end
153
+
154
+ module ReasonPlugin
155
+ def self.load_dependencies(*)
156
+ require "net/http/status"
157
+ end
158
+
159
+ module ResponseMethods
160
+ def reason
161
+ Net::HTTP::STATUS_CODES.fetch(@status, "Non-Standard status code")
162
+ end
163
+ end
164
+ end
165
+
166
+ class ParallelManager
167
+ class ResponseHandler < SimpleDelegator
168
+ attr_reader :env
169
+
170
+ def initialize(env)
171
+ @env = env
172
+ super
173
+ end
174
+
175
+ def on_response(&blk)
176
+ if blk
177
+ @on_response = ->(response) do
178
+ blk.call(response)
179
+ end
180
+ self
181
+ else
182
+ @on_response
183
+ end
184
+ end
185
+
186
+ def on_complete(&blk)
187
+ if blk
188
+ @on_complete = blk
189
+ self
190
+ else
191
+ @on_complete
192
+ end
193
+ end
194
+ end
195
+
196
+ include RequestMixin
197
+
198
+ def initialize(options)
199
+ @handlers = []
200
+ @connection_options = options
201
+ end
202
+
203
+ def enqueue(request)
204
+ handler = ResponseHandler.new(request)
205
+ @handlers << handler
206
+ handler
207
+ end
208
+
209
+ def run
210
+ return unless @handlers.last
211
+
212
+ env = @handlers.last.env
213
+
214
+ connect(env) do |session|
215
+ requests = @handlers.map { |handler| session.build_request(*build_request(handler.env)) }
216
+
217
+ if env.request.stream_response?
218
+ requests.each do |request|
219
+ request.response_on_data = env.request.on_data
220
+ end
221
+ end
222
+
223
+ responses = session.request(*requests)
224
+ Array(responses).each_with_index do |response, index|
225
+ handler = @handlers[index]
226
+ handler.on_response.call(response)
227
+ handler.on_complete.call(handler.env) if handler.on_complete
228
+ end
229
+ end
230
+ end
231
+
232
+ private
233
+
234
+ # from Faraday::Adapter#connection
235
+ def connection(env)
236
+ conn = build_connection(env)
237
+ return conn unless block_given?
238
+
239
+ yield conn
240
+ end
241
+
242
+ # from Faraday::Adapter#request_timeout
243
+ def request_timeout(type, options)
244
+ key = Faraday::Adapter::TIMEOUT_KEYS[type]
245
+ options[key] || options[:timeout]
246
+ end
247
+ end
248
+
249
+ self.supports_parallel = true
250
+
251
+ class << self
252
+ def setup_parallel_manager(options = {})
253
+ ParallelManager.new(options)
254
+ end
255
+ end
256
+
257
+ def call(env)
258
+ super
259
+ if parallel?(env)
260
+ handler = env[:parallel_manager].enqueue(env)
261
+ handler.on_response do |response|
262
+ if response.is_a?(::HTTPX::Response)
263
+ save_response(env, response.status, response.body.to_s, response.headers, response.reason) do |response_headers|
264
+ response_headers.merge!(response.headers)
265
+ end
266
+ else
267
+ env[:error] = response.error
268
+ save_response(env, 0, "", {}, nil)
269
+ end
270
+ end
271
+ return handler
272
+ end
273
+
274
+ response = connect_and_request(env)
275
+ save_response(env, response.status, response.body.to_s, response.headers, response.reason) do |response_headers|
276
+ response_headers.merge!(response.headers)
277
+ end
278
+ @app.call(env)
279
+ end
280
+
281
+ private
282
+
283
+ def connect_and_request(env)
284
+ connect(env) do |session|
285
+ request = session.build_request(*build_request(env))
286
+
287
+ request.response_on_data = env.request.on_data if env.request.stream_response?
288
+
289
+ response = session.request(request)
290
+ # do not call #raise_for_status for HTTP 4xx or 5xx, as faraday has a middleware for that.
291
+ response.raise_for_status unless response.is_a?(::HTTPX::Response)
292
+ response
293
+ end
294
+ end
295
+
296
+ def parallel?(env)
297
+ env[:parallel_manager]
298
+ end
299
+ end
300
+
301
+ register_middleware httpx: HTTPX
302
+ end
303
+ end