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,195 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HTTPX
4
+ module Plugins
5
+ # This plugin makes a session reuse the same selector across all fibers in a given thread.
6
+ #
7
+ # This enables integration with fiber scheduler implementations such as [async](https://github.com/async).
8
+ #
9
+ # # https://gitlab.com/os85/httpx/wikis/FiberConcurrency
10
+ #
11
+ module FiberConcurrency
12
+ def self.subplugins
13
+ {
14
+ h2c: FiberConcurrencyH2C,
15
+ }
16
+ end
17
+
18
+ module InstanceMethods
19
+ private
20
+
21
+ def send_request(request, *)
22
+ request.set_context!
23
+
24
+ super
25
+ end
26
+
27
+ def get_current_selector
28
+ super(&nil) || begin
29
+ return unless block_given?
30
+
31
+ default = yield
32
+
33
+ set_current_selector(default)
34
+
35
+ default
36
+ end
37
+ end
38
+ end
39
+
40
+ module RequestMethods
41
+ # the execution context (fiber) this request was sent on.
42
+ attr_reader :context
43
+
44
+ def initialize(*)
45
+ super
46
+ @context = nil
47
+ end
48
+
49
+ # sets the execution context for this request. the default is the current fiber.
50
+ def set_context!
51
+ @context ||= Fiber.current # rubocop:disable Naming/MemoizedInstanceVariableName
52
+ end
53
+
54
+ # checks whether the current execution context is the one where the request was created.
55
+ def current_context?
56
+ @context == Fiber.current
57
+ end
58
+
59
+ def complete!(response = @response)
60
+ @context = nil
61
+ super
62
+ end
63
+ end
64
+
65
+ module ConnectionMethods
66
+ def current_context?
67
+ @pending.any?(&:current_context?) || (
68
+ @sibling && @sibling.pending.any?(&:current_context?)
69
+ )
70
+ end
71
+
72
+ def interests
73
+ return if connecting? && @pending.none?(&:current_context?)
74
+
75
+ super
76
+ end
77
+
78
+ def send(request)
79
+ # DoH requests bypass the session, so context needs to be set here.
80
+ request.set_context!
81
+
82
+ super
83
+ end
84
+ end
85
+
86
+ module HTTP1Methods
87
+ def interests
88
+ request = @request || @requests.first
89
+
90
+ return unless request
91
+
92
+ return unless request.current_context? || @requests.any?(&:current_context?) || @pending.any?(&:current_context?)
93
+
94
+ super
95
+ end
96
+ end
97
+
98
+ module HTTP2Methods
99
+ def initialize(*)
100
+ super
101
+ @contexts = Hash.new { |hs, k| hs[k] = Set.new }
102
+ end
103
+
104
+ def interests
105
+ if @connection.state == :connected && @handshake_completed && !@contexts.key?(Fiber.current)
106
+ return :w unless @pings.empty?
107
+
108
+ return
109
+ end
110
+
111
+ super
112
+ end
113
+
114
+ def send(request, *)
115
+ add_to_context(request)
116
+
117
+ super
118
+ end
119
+
120
+ private
121
+
122
+ def on_close(_, error, _)
123
+ if error == :http_1_1_required
124
+ # remove all pending requests context
125
+ @pending.each do |req|
126
+ clear_from_context(req)
127
+ end
128
+ end
129
+
130
+ super
131
+ end
132
+
133
+ def on_stream_close(_, request, error)
134
+ clear_from_context(request) if error != :stream_closed && @streams.key?(request)
135
+
136
+ super
137
+ end
138
+
139
+ def teardown(request = nil)
140
+ super
141
+
142
+ if request
143
+ clear_from_context(request)
144
+ else
145
+ @contexts.clear
146
+ end
147
+ end
148
+
149
+ def add_to_context(request)
150
+ @contexts[request.context] << request
151
+ end
152
+
153
+ def clear_from_context(request)
154
+ requests = @contexts[request.context]
155
+
156
+ requests.delete(request)
157
+
158
+ @contexts.delete(request.context) if requests.empty?
159
+ end
160
+ end
161
+
162
+ module NativeResolverMethods
163
+ private
164
+
165
+ def calculate_interests
166
+ return if @queries.empty?
167
+
168
+ return unless @queries.values.any?(&:current_context?) || @connections.any?(&:current_context?)
169
+
170
+ super
171
+ end
172
+ end
173
+
174
+ module SystemResolverMethods
175
+ def interests
176
+ return unless @queries.any? { |_, conn| conn.current_context? }
177
+
178
+ super
179
+ end
180
+ end
181
+
182
+ module FiberConcurrencyH2C
183
+ module HTTP2Methods
184
+ def upgrade(request, *)
185
+ @contexts[request.context] << request
186
+
187
+ super
188
+ end
189
+ end
190
+ end
191
+ end
192
+
193
+ register_plugin :fiber_concurrency, FiberConcurrency
194
+ end
195
+ end
@@ -0,0 +1,233 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HTTPX
4
+ InsecureRedirectError = Class.new(Error)
5
+ module Plugins
6
+ #
7
+ # This plugin adds support for automatically following redirect (status 30X) responses.
8
+ #
9
+ # It has a default upper bound of followed redirects (see *MAX_REDIRECTS* and the *max_redirects* option),
10
+ # after which it will return the last redirect response. It will **not** raise an exception.
11
+ #
12
+ # It doesn't follow insecure redirects (https -> http) by default (see *follow_insecure_redirects*).
13
+ #
14
+ # It doesn't propagate authorization related headers to requests redirecting to different origins
15
+ # (see *allow_auth_to_other_origins*) to override.
16
+ #
17
+ # It allows customization of when to redirect via the *redirect_on* callback option).
18
+ #
19
+ # https://gitlab.com/os85/httpx/wikis/Follow-Redirects
20
+ #
21
+ module FollowRedirects
22
+ MAX_REDIRECTS = 3
23
+ REDIRECT_STATUS = (300..399).freeze
24
+ REQUEST_BODY_HEADERS = %w[transfer-encoding content-encoding content-type content-length content-language content-md5 trailer].freeze
25
+
26
+ using URIExtensions
27
+
28
+ # adds support for the following options:
29
+ #
30
+ # :max_redirects :: max number of times a request will be redirected (defaults to <tt>3</tt>).
31
+ # :follow_insecure_redirects :: whether redirects to an "http://" URI, when coming from an "https//", are allowed
32
+ # (defaults to <tt>false</tt>).
33
+ # :allow_auth_to_other_origins :: whether auth-related headers, such as "Authorization", are propagated on redirection
34
+ # (defaults to <tt>false</tt>).
35
+ # :redirect_on :: optional callback which receives the redirect location and can halt the redirect chain if it returns <tt>false</tt>.
36
+ module OptionsMethods
37
+ private
38
+
39
+ def option_max_redirects(value)
40
+ num = Integer(value)
41
+ raise TypeError, ":max_redirects must be positive" if num.negative?
42
+
43
+ num
44
+ end
45
+
46
+ def option_follow_insecure_redirects(value)
47
+ value
48
+ end
49
+
50
+ def option_allow_auth_to_other_origins(value)
51
+ value
52
+ end
53
+
54
+ def option_redirect_on(value)
55
+ raise TypeError, ":redirect_on must be callable" unless value.respond_to?(:call)
56
+
57
+ value
58
+ end
59
+ end
60
+
61
+ module InstanceMethods
62
+ # returns a session with the *max_redirects* option set to +n+
63
+ def max_redirects(n)
64
+ with(max_redirects: n.to_i)
65
+ end
66
+
67
+ private
68
+
69
+ def fetch_response(request, selector, options)
70
+ redirect_request = request.redirect_request
71
+ response = super(redirect_request, selector, options)
72
+ return unless response
73
+
74
+ max_redirects = redirect_request.max_redirects
75
+
76
+ return response unless response.is_a?(Response)
77
+ return response unless REDIRECT_STATUS.include?(response.status) && response.headers.key?("location")
78
+ return response unless max_redirects.positive?
79
+
80
+ redirect_uri = __get_location_from_response(response)
81
+
82
+ if options.redirect_on
83
+ redirect_allowed = options.redirect_on.call(redirect_uri)
84
+ return response unless redirect_allowed
85
+ end
86
+
87
+ # build redirect request
88
+ request_body = redirect_request.body
89
+ redirect_method = "GET"
90
+ redirect_params = {}
91
+
92
+ if response.status == 305 && options.respond_to?(:proxy)
93
+ request_body.rewind
94
+ # The requested resource MUST be accessed through the proxy given by
95
+ # the Location field. The Location field gives the URI of the proxy.
96
+ redirect_options = options.merge(headers: redirect_request.headers,
97
+ proxy: { uri: redirect_uri },
98
+ max_redirects: max_redirects - 1)
99
+
100
+ redirect_params[:body] = request_body
101
+ redirect_uri = redirect_request.uri
102
+ options = redirect_options
103
+ else
104
+ redirect_headers = redirect_request_headers(redirect_request.uri, redirect_uri, request.headers, options)
105
+ redirect_opts = Hash[options]
106
+ redirect_params[:max_redirects] = max_redirects - 1
107
+
108
+ unless request_body.empty?
109
+ if response.status == 307
110
+ # The method and the body of the original request are reused to perform the redirected request.
111
+ redirect_method = redirect_request.verb
112
+ request_body.rewind
113
+ redirect_params[:body] = request_body
114
+ else
115
+ # redirects are **ALWAYS** GET, so remove body-related headers
116
+ REQUEST_BODY_HEADERS.each do |h|
117
+ redirect_headers.delete(h)
118
+ end
119
+ redirect_params[:body] = nil
120
+ end
121
+ end
122
+
123
+ options = options.class.new(redirect_opts.merge(headers: redirect_headers.to_h))
124
+ end
125
+
126
+ redirect_uri = Utils.to_uri(redirect_uri)
127
+
128
+ if !options.follow_insecure_redirects &&
129
+ response.uri.scheme == "https" &&
130
+ redirect_uri.scheme == "http"
131
+ error = InsecureRedirectError.new(redirect_uri.to_s)
132
+ error.set_backtrace(caller)
133
+ return ErrorResponse.new(request, error)
134
+ end
135
+
136
+ retry_request = build_request(redirect_method, redirect_uri, redirect_params, options)
137
+
138
+ request.redirect_request = retry_request
139
+
140
+ redirect_after = response.headers["retry-after"]
141
+
142
+ if redirect_after
143
+ # Servers send the "Retry-After" header field to indicate how long the
144
+ # user agent ought to wait before making a follow-up request.
145
+ # When sent with any 3xx (Redirection) response, Retry-After indicates
146
+ # the minimum time that the user agent is asked to wait before issuing
147
+ # the redirected request.
148
+ #
149
+ redirect_after = Utils.parse_retry_after(redirect_after)
150
+
151
+ retry_start = Utils.now
152
+ log { "redirecting after #{redirect_after} secs..." }
153
+ selector.after(redirect_after) do
154
+ if (response = request.response)
155
+ response.finish!
156
+ retry_request.response = response
157
+ # request has terminated abruptly meanwhile
158
+ retry_request.emit(:response, response)
159
+ else
160
+ log { "redirecting (elapsed time: #{Utils.elapsed_time(retry_start)})!!" }
161
+ send_request(retry_request, selector, options)
162
+ end
163
+ end
164
+ else
165
+ send_request(retry_request, selector, options)
166
+ end
167
+ nil
168
+ end
169
+
170
+ # :nodoc:
171
+ def redirect_request_headers(original_uri, redirect_uri, headers, options)
172
+ headers = headers.dup
173
+
174
+ return headers if options.allow_auth_to_other_origins
175
+
176
+ return headers unless headers.key?("authorization")
177
+
178
+ return headers if original_uri.origin == redirect_uri.origin
179
+
180
+ headers.delete("authorization")
181
+
182
+ headers
183
+ end
184
+
185
+ # :nodoc:
186
+ def __get_location_from_response(response)
187
+ # @type var location_uri: http_uri
188
+ location_uri = URI(response.headers["location"])
189
+ location_uri = response.uri.merge(location_uri) if location_uri.relative?
190
+ location_uri
191
+ end
192
+ end
193
+
194
+ module RequestMethods
195
+ # returns the top-most original HTTPX::Request from the redirect chain
196
+ attr_accessor :root_request
197
+
198
+ # returns the follow-up redirect request, or itself
199
+ def redirect_request
200
+ @redirect_request || self
201
+ end
202
+
203
+ # sets the follow-up redirect request
204
+ def redirect_request=(req)
205
+ @redirect_request = req
206
+ req.root_request = @root_request || self
207
+ @response = nil
208
+ end
209
+
210
+ def response
211
+ return super unless @redirect_request && @response.nil?
212
+
213
+ @redirect_request.response
214
+ end
215
+
216
+ def max_redirects
217
+ @options.max_redirects || MAX_REDIRECTS
218
+ end
219
+ end
220
+
221
+ module ConnectionMethods
222
+ private
223
+
224
+ def set_request_request_timeout(request)
225
+ return unless request.root_request.nil?
226
+
227
+ super
228
+ end
229
+ end
230
+ end
231
+ register_plugin :follow_redirects, FollowRedirects
232
+ end
233
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HTTPX
4
+ module Plugins
5
+ module GRPC
6
+ # Encapsulates call information
7
+ class Call
8
+ attr_writer :decoder
9
+
10
+ def initialize(response)
11
+ @response = response
12
+ @decoder = ->(z) { z }
13
+ @consumed = false
14
+ @grpc_response = nil
15
+ end
16
+
17
+ def inspect
18
+ "#{self.class}(#{grpc_response})"
19
+ end
20
+
21
+ def to_s
22
+ grpc_response.to_s
23
+ end
24
+
25
+ def metadata
26
+ response.headers
27
+ end
28
+
29
+ def trailing_metadata
30
+ return unless @consumed
31
+
32
+ @response.trailing_metadata
33
+ end
34
+
35
+ private
36
+
37
+ def grpc_response
38
+ @grpc_response ||= if @response.respond_to?(:each)
39
+ Enumerator.new do |y|
40
+ Message.stream(@response).each do |message|
41
+ y << @decoder.call(message)
42
+ end
43
+ @consumed = true
44
+ end
45
+ else
46
+ @consumed = true
47
+ @decoder.call(Message.unary(@response))
48
+ end
49
+ end
50
+
51
+ def respond_to_missing?(meth, *args, &blk)
52
+ grpc_response.respond_to?(meth, *args) || super
53
+ end
54
+
55
+ def method_missing(meth, *args, &blk)
56
+ return grpc_response.__send__(meth, *args, &blk) if grpc_response.respond_to?(meth)
57
+
58
+ super
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HTTPX
4
+ module Transcoder
5
+ module GRPCEncoding
6
+ class Deflater
7
+ extend Forwardable
8
+
9
+ attr_reader :content_type
10
+
11
+ def initialize(body, compressed:)
12
+ @content_type = body.content_type
13
+ @body = BodyReader.new(body)
14
+ @compressed = compressed
15
+ end
16
+
17
+ def bytesize
18
+ return @body.bytesize if @body.respond_to?(:bytesize)
19
+
20
+ Float::INFINITY
21
+ end
22
+
23
+ def read(length = nil, outbuf = nil)
24
+ buf = @body.read(length, outbuf)
25
+
26
+ return unless buf
27
+
28
+ compressed_flag = @compressed ? 1 : 0
29
+
30
+ buf = outbuf if outbuf
31
+
32
+ buf = buf.b if buf.frozen?
33
+
34
+ buf.prepend([compressed_flag, buf.bytesize].pack("CL>"))
35
+ buf
36
+ end
37
+ end
38
+
39
+ class Inflater
40
+ def initialize(response)
41
+ @response = response
42
+ @grpc_encodings = nil
43
+ end
44
+
45
+ def call(message, &blk)
46
+ data = "".b
47
+
48
+ until message.empty?
49
+ compressed, size = message.unpack("CL>")
50
+
51
+ encoded_data = message.byteslice(5..size + 5 - 1)
52
+
53
+ if compressed == 1
54
+ grpc_encodings.reverse_each do |encoding|
55
+ decoder = @response.body.class.initialize_inflater_by_encoding(encoding, @response, bytesize: encoded_data.bytesize)
56
+ encoded_data = decoder.call(encoded_data)
57
+
58
+ blk.call(encoded_data) if blk
59
+
60
+ data << encoded_data
61
+ end
62
+ else
63
+ blk.call(encoded_data) if blk
64
+
65
+ data << encoded_data
66
+ end
67
+
68
+ message = message.byteslice((size + 5)..-1)
69
+ end
70
+
71
+ data
72
+ end
73
+
74
+ private
75
+
76
+ def grpc_encodings
77
+ @grpc_encodings ||= @response.headers.get("grpc-encoding")
78
+ end
79
+ end
80
+
81
+ def self.encode(*args, **kwargs)
82
+ Deflater.new(*args, **kwargs)
83
+ end
84
+
85
+ def self.decode(response)
86
+ Inflater.new(response)
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HTTPX
4
+ module Plugins
5
+ module GRPC
6
+ # Encoding module for GRPC responses
7
+ #
8
+ # Can encode and decode grpc messages.
9
+ module Message
10
+ module_function
11
+
12
+ # decodes a unary grpc response
13
+ def unary(response)
14
+ verify_status(response)
15
+
16
+ decoder = Transcoder::GRPCEncoding.decode(response)
17
+
18
+ decoder.call(response.to_s)
19
+ end
20
+
21
+ # lazy decodes a grpc stream response
22
+ def stream(response, &block)
23
+ return enum_for(__method__, response) unless block
24
+
25
+ decoder = Transcoder::GRPCEncoding.decode(response)
26
+
27
+ response.each do |frame|
28
+ decoder.call(frame, &block)
29
+ end
30
+
31
+ verify_status(response)
32
+ end
33
+
34
+ def cancel(request)
35
+ request.emit(:refuse, :client_cancellation)
36
+ end
37
+
38
+ # interprets the grpc call trailing metadata, and raises an
39
+ # exception in case of error code
40
+ def verify_status(response)
41
+ # return standard errors if need be
42
+ response.raise_for_status
43
+
44
+ status = Integer(response.headers["grpc-status"])
45
+ message = response.headers["grpc-message"]
46
+
47
+ return if status.zero?
48
+
49
+ response.close
50
+ raise GRPCError.new(status, message, response.trailing_metadata)
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end