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,463 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HTTPX
4
+ # Contains a set of options which are passed and shared across from session to its requests or
5
+ # responses.
6
+ class Options
7
+ BUFFER_SIZE = 1 << 14
8
+ WINDOW_SIZE = 1 << 14 # 16K
9
+ MAX_BODY_THRESHOLD_SIZE = (1 << 10) * 112 # 112K
10
+ KEEP_ALIVE_TIMEOUT = 20
11
+ SETTINGS_TIMEOUT = 10
12
+ CLOSE_HANDSHAKE_TIMEOUT = 10
13
+ CONNECT_TIMEOUT = READ_TIMEOUT = WRITE_TIMEOUT = 60
14
+ REQUEST_TIMEOUT = OPERATION_TIMEOUT = nil
15
+
16
+ @options_names = []
17
+
18
+ class << self
19
+ attr_reader :options_names
20
+
21
+ def inherited(klass)
22
+ super
23
+ klass.instance_variable_set(:@options_names, @options_names.dup)
24
+ end
25
+
26
+ def new(options = {})
27
+ # let enhanced options go through
28
+ return options if self == Options && options.class < self
29
+ return options if options.is_a?(self)
30
+
31
+ super
32
+ end
33
+
34
+ def freeze
35
+ @options_names.freeze
36
+ super
37
+ end
38
+
39
+ def method_added(meth)
40
+ super
41
+
42
+ return unless meth =~ /^option_(.+)$/
43
+
44
+ optname = Regexp.last_match(1)
45
+
46
+ if optname =~ /^(.+[^_])_+with/
47
+ # ignore alias method chain generated methods.
48
+ # this is the case with RBS runtime tests.
49
+ # it relies on the "_with/_without" separator, which is the most used convention,
50
+ # however it shouldn't be used in practice in httpx given the plugin architecture
51
+ # as the main extension API.
52
+ orig_name = Regexp.last_match(1)
53
+
54
+ return if @options_names.include?(orig_name.to_sym)
55
+ end
56
+
57
+ optname = optname.to_sym
58
+
59
+ attr_reader(optname)
60
+
61
+ @options_names << optname unless @options_names.include?(optname)
62
+ end
63
+ end
64
+
65
+ # creates a new options instance from a given hash, which optionally define the following:
66
+ #
67
+ # :debug :: an object which log messages are written to (must respond to <tt><<</tt>)
68
+ # :debug_level :: the log level of messages (can be 1, 2, or 3).
69
+ # :debug_redact :: whether header/body payload should be redacted (defaults to <tt>false</tt>).
70
+ # :ssl :: a hash of options which can be set as params of OpenSSL::SSL::SSLContext (see HTTPX::SSL)
71
+ # :http2_settings :: a hash of options to be passed to a HTTP2::Connection (ex: <tt>{ max_concurrent_streams: 2 }</tt>)
72
+ # :fallback_protocol :: version of HTTP protocol to use by default in the absence of protocol negotiation
73
+ # like ALPN (defaults to <tt>"http/1.1"</tt>)
74
+ # :supported_compression_formats :: list of compressions supported by the transcoder layer (defaults to <tt>%w[gzip deflate]</tt>).
75
+ # :decompress_response_body :: whether to auto-decompress response body (defaults to <tt>true</tt>).
76
+ # :compress_request_body :: whether to auto-decompress response body (defaults to <tt>true</tt>)
77
+ # :timeout :: hash of timeout configurations (supports <tt>:connect_timeout</tt>, <tt>:settings_timeout</tt>,
78
+ # <tt>:operation_timeout</tt>, <tt>:keep_alive_timeout</tt>, <tt>:read_timeout</tt>, <tt>:write_timeout</tt>
79
+ # and <tt>:request_timeout</tt>
80
+ # :headers :: hash of HTTP headers (ex: <tt>{ "x-custom-foo" => "bar" }</tt>)
81
+ # :window_size :: number of bytes to read from a socket
82
+ # :buffer_size :: internal read and write buffer size in bytes
83
+ # :body_threshold_size :: maximum size in bytes of response payload that is buffered in memory.
84
+ # :request_class :: class used to instantiate a request
85
+ # :response_class :: class used to instantiate a response
86
+ # :headers_class :: class used to instantiate headers
87
+ # :request_body_class :: class used to instantiate a request body
88
+ # :response_body_class :: class used to instantiate a response body
89
+ # :connection_class :: class used to instantiate connections
90
+ # :http1_class :: class used to manage HTTP1 sessions
91
+ # :http2_class :: class used to imanage HTTP2 sessions
92
+ # :resolver_native_class :: class used to resolve names using pure ruby DNS implementation
93
+ # :resolver_system_class :: class used to resolve names using system-based (getaddrinfo) name resolution
94
+ # :resolver_https_class :: class used to resolve names using DoH
95
+ # :pool_class :: class used to instantiate the session connection pool
96
+ # :options_class :: class used to instantiate options
97
+ # :transport :: type of transport to use (set to "unix" for UNIX sockets)
98
+ # :addresses :: bucket of peer addresses (can be a list of IP addresses, a hash of domain to list of adddresses;
99
+ # paths should be used for UNIX sockets instead)
100
+ # :io :: open socket, or domain/ip-to-socket hash, which requests should be sent to
101
+ # :persistent :: whether to persist connections in between requests (defaults to <tt>true</tt>)
102
+ # :resolver_class :: which resolver to use (defaults to <tt>:native</tt>, can also be <tt>:system<tt> for
103
+ # using getaddrinfo or <tt>:https</tt> for DoH resolver, or a custom class)
104
+ # :resolver_options :: hash of options passed to the resolver. Accepted keys depend on the resolver type.
105
+ # :pool_options :: hash of options passed to the connection pool (See Pool#initialize).
106
+ # :ip_families :: which socket families are supported (system-dependent)
107
+ # :origin :: HTTP origin to set on requests with relative path (ex: "https://api.serv.com")
108
+ # :base_path :: path to prefix given relative paths with (ex: "/v2")
109
+ # :max_concurrent_requests :: max number of requests which can be set concurrently
110
+ # :max_requests :: max number of requests which can be made on socket before it reconnects.
111
+ # :close_on_fork :: whether the session automatically closes when the process is fork (defaults to <tt>false</tt>).
112
+ # it only works if the session is persistent (and ruby 3.1 or higher is used).
113
+ #
114
+ # This list of options are enhanced with each loaded plugin, see the plugin docs for details.
115
+ def initialize(options = EMPTY_HASH)
116
+ options_names = self.class.options_names
117
+
118
+ defaults =
119
+ case options
120
+ when Options
121
+ unknown_options = options.class.options_names - options_names
122
+
123
+ raise Error, "unknown option: #{unknown_options.first}" unless unknown_options.empty?
124
+
125
+ DEFAULT_OPTIONS.merge(options)
126
+ else
127
+ options.each_key do |k|
128
+ raise Error, "unknown option: #{k}" unless options_names.include?(k)
129
+ end
130
+
131
+ options.empty? ? DEFAULT_OPTIONS : DEFAULT_OPTIONS.merge(options)
132
+ end
133
+
134
+ options_names.each do |k|
135
+ v = defaults[k]
136
+
137
+ if v.nil?
138
+ instance_variable_set(:"@#{k}", v)
139
+
140
+ next
141
+ end
142
+
143
+ value = __send__(:"option_#{k}", v)
144
+ instance_variable_set(:"@#{k}", value)
145
+ end
146
+
147
+ freeze
148
+ end
149
+
150
+ def freeze
151
+ self.class.options_names.each do |ivar|
152
+ # avoid freezing debug option, as when it's set, it's usually an
153
+ # object which cannot be frozen, like stderr or stdout. It's a
154
+ # documented exception then, and still does not defeat the purpose
155
+ # here, which is to make option objects shareable across ractors,
156
+ # and in most cases debug should be nil, or one of the objects
157
+ # which will eventually be shareable, like STDOUT or STDERR.
158
+ next if ivar == :debug
159
+
160
+ instance_variable_get(:"@#{ivar}").freeze
161
+ end
162
+ super
163
+ end
164
+
165
+ REQUEST_BODY_IVARS = %i[@headers].freeze
166
+
167
+ def ==(other)
168
+ super || options_equals?(other)
169
+ end
170
+
171
+ def options_equals?(other, ignore_ivars = REQUEST_BODY_IVARS)
172
+ # headers and other request options do not play a role, as they are
173
+ # relevant only for the request.
174
+ ivars = instance_variables - ignore_ivars
175
+ other_ivars = other.instance_variables - ignore_ivars
176
+
177
+ return false if ivars.size != other_ivars.size
178
+
179
+ return false if ivars.sort != other_ivars.sort
180
+
181
+ ivars.all? do |ivar|
182
+ instance_variable_get(ivar) == other.instance_variable_get(ivar)
183
+ end
184
+ end
185
+
186
+ def merge(other)
187
+ ivar_map = nil
188
+ other_ivars = case other
189
+ when Options
190
+ other.instance_variables
191
+ else
192
+ other = Hash[other] unless other.is_a?(Hash)
193
+ ivar_map = other.keys.to_h { |k| [:"@#{k}", k] }
194
+ ivar_map.keys
195
+ end
196
+
197
+ return self if other_ivars.empty?
198
+
199
+ return self if other_ivars.all? { |ivar| instance_variable_get(ivar) == access_option(other, ivar, ivar_map) }
200
+
201
+ opts = dup
202
+
203
+ other_ivars.each do |ivar|
204
+ v = access_option(other, ivar, ivar_map)
205
+
206
+ unless v
207
+ opts.instance_variable_set(ivar, v)
208
+ next
209
+ end
210
+
211
+ v = opts.__send__(:"option_#{ivar[1..-1]}", v)
212
+
213
+ orig_v = instance_variable_get(ivar)
214
+
215
+ v = orig_v.merge(v) if orig_v.respond_to?(:merge) && v.respond_to?(:merge)
216
+
217
+ opts.instance_variable_set(ivar, v)
218
+ end
219
+
220
+ opts
221
+ end
222
+
223
+ def to_hash
224
+ instance_variables.each_with_object({}) do |ivar, hs|
225
+ val = instance_variable_get(ivar)
226
+
227
+ next if val.nil?
228
+
229
+ hs[ivar[1..-1].to_sym] = val
230
+ end
231
+ end
232
+
233
+ def extend_with_plugin_classes(pl)
234
+ # extend request class
235
+ if defined?(pl::RequestMethods) || defined?(pl::RequestClassMethods)
236
+ @request_class = @request_class.dup
237
+ SET_TEMPORARY_NAME[@request_class, pl]
238
+ @request_class.__send__(:include, pl::RequestMethods) if defined?(pl::RequestMethods)
239
+ @request_class.extend(pl::RequestClassMethods) if defined?(pl::RequestClassMethods)
240
+ end
241
+ # extend response class
242
+ if defined?(pl::ResponseMethods) || defined?(pl::ResponseClassMethods)
243
+ @response_class = @response_class.dup
244
+ SET_TEMPORARY_NAME[@response_class, pl]
245
+ @response_class.__send__(:include, pl::ResponseMethods) if defined?(pl::ResponseMethods)
246
+ @response_class.extend(pl::ResponseClassMethods) if defined?(pl::ResponseClassMethods)
247
+ end
248
+ # extend headers class
249
+ if defined?(pl::HeadersMethods) || defined?(pl::HeadersClassMethods)
250
+ @headers_class = @headers_class.dup
251
+ SET_TEMPORARY_NAME[@headers_class, pl]
252
+ @headers_class.__send__(:include, pl::HeadersMethods) if defined?(pl::HeadersMethods)
253
+ @headers_class.extend(pl::HeadersClassMethods) if defined?(pl::HeadersClassMethods)
254
+ end
255
+ # extend request body class
256
+ if defined?(pl::RequestBodyMethods) || defined?(pl::RequestBodyClassMethods)
257
+ @request_body_class = @request_body_class.dup
258
+ SET_TEMPORARY_NAME[@request_body_class, pl]
259
+ @request_body_class.__send__(:include, pl::RequestBodyMethods) if defined?(pl::RequestBodyMethods)
260
+ @request_body_class.extend(pl::RequestBodyClassMethods) if defined?(pl::RequestBodyClassMethods)
261
+ end
262
+ # extend response body class
263
+ if defined?(pl::ResponseBodyMethods) || defined?(pl::ResponseBodyClassMethods)
264
+ @response_body_class = @response_body_class.dup
265
+ SET_TEMPORARY_NAME[@response_body_class, pl]
266
+ @response_body_class.__send__(:include, pl::ResponseBodyMethods) if defined?(pl::ResponseBodyMethods)
267
+ @response_body_class.extend(pl::ResponseBodyClassMethods) if defined?(pl::ResponseBodyClassMethods)
268
+ end
269
+ # extend connection pool class
270
+ if defined?(pl::PoolMethods)
271
+ @pool_class = @pool_class.dup
272
+ SET_TEMPORARY_NAME[@pool_class, pl]
273
+ @pool_class.__send__(:include, pl::PoolMethods)
274
+ end
275
+ # extend connection class
276
+ if defined?(pl::ConnectionMethods)
277
+ @connection_class = @connection_class.dup
278
+ SET_TEMPORARY_NAME[@connection_class, pl]
279
+ @connection_class.__send__(:include, pl::ConnectionMethods)
280
+ end
281
+ # extend http1 class
282
+ if defined?(pl::HTTP1Methods)
283
+ @http1_class = @http1_class.dup
284
+ SET_TEMPORARY_NAME[@http1_class, pl]
285
+ @http1_class.__send__(:include, pl::HTTP1Methods)
286
+ end
287
+ # extend http2 class
288
+ if defined?(pl::HTTP2Methods)
289
+ @http2_class = @http2_class.dup
290
+ SET_TEMPORARY_NAME[@http2_class, pl]
291
+ @http2_class.__send__(:include, pl::HTTP2Methods)
292
+ end
293
+ # extend native resolver class
294
+ if defined?(pl::ResolverNativeMethods)
295
+ @resolver_native_class = @resolver_native_class.dup
296
+ SET_TEMPORARY_NAME[@resolver_native_class, pl]
297
+ @resolver_native_class.__send__(:include, pl::ResolverNativeMethods)
298
+ end
299
+ # extend system resolver class
300
+ if defined?(pl::ResolverSystemMethods)
301
+ @resolver_system_class = @resolver_system_class.dup
302
+ SET_TEMPORARY_NAME[@resolver_system_class, pl]
303
+ @resolver_system_class.__send__(:include, pl::ResolverSystemMethods)
304
+ end
305
+ # extend https resolver class
306
+ if defined?(pl::ResolverHTTPSMethods)
307
+ @resolver_https_class = @resolver_https_class.dup
308
+ SET_TEMPORARY_NAME[@resolver_https_class, pl]
309
+ @resolver_https_class.__send__(:include, pl::ResolverHTTPSMethods)
310
+ end
311
+
312
+ return unless defined?(pl::OptionsMethods)
313
+
314
+ # extend option class
315
+ # works around lack of initialize_dup callback
316
+ @options_class = @options_class.dup
317
+ # (self.class.options_names)
318
+ @options_class.__send__(:include, pl::OptionsMethods)
319
+ end
320
+
321
+ private
322
+
323
+ # number options
324
+ %i[
325
+ max_concurrent_requests max_requests window_size buffer_size
326
+ body_threshold_size debug_level
327
+ ].each do |option|
328
+ class_eval(<<-OUT, __FILE__, __LINE__ + 1)
329
+ # converts +v+ into an Integer before setting the +#{option}+ option.
330
+ private def option_#{option}(value) # private def option_max_requests(v)
331
+ value = Integer(value) unless value.respond_to?(:infinite?) && value.infinite?
332
+ raise TypeError, ":#{option} must be positive" unless value.positive? # raise TypeError, ":max_requests must be positive" unless value.positive?
333
+
334
+ value
335
+ end
336
+ OUT
337
+ end
338
+
339
+ # hashable options
340
+ %i[ssl http2_settings resolver_options pool_options].each do |option|
341
+ class_eval(<<-OUT, __FILE__, __LINE__ + 1)
342
+ # converts +v+ into an Hash before setting the +#{option}+ option.
343
+ private def option_#{option}(value) # def option_ssl(v)
344
+ Hash[value]
345
+ end
346
+ OUT
347
+ end
348
+
349
+ %i[
350
+ request_class response_class headers_class request_body_class
351
+ response_body_class connection_class http1_class http2_class
352
+ resolver_native_class resolver_system_class resolver_https_class options_class pool_class
353
+ io fallback_protocol debug debug_redact resolver_class
354
+ compress_request_body decompress_response_body
355
+ persistent close_on_fork
356
+ ].each do |method_name|
357
+ class_eval(<<-OUT, __FILE__, __LINE__ + 1)
358
+ # sets +v+ as the value of the +#{method_name}+ option
359
+ private def option_#{method_name}(v); v; end # private def option_smth(v); v; end
360
+ OUT
361
+ end
362
+
363
+ def option_origin(value)
364
+ URI(value)
365
+ end
366
+
367
+ def option_base_path(value)
368
+ String(value)
369
+ end
370
+
371
+ def option_headers(value)
372
+ headers_class.new(value)
373
+ end
374
+
375
+ def option_timeout(value)
376
+ Hash[value]
377
+ end
378
+
379
+ def option_supported_compression_formats(value)
380
+ Array(value).map(&:to_s)
381
+ end
382
+
383
+ def option_transport(value)
384
+ transport = value.to_s
385
+ raise TypeError, "#{transport} is an unsupported transport type" unless %w[unix].include?(transport)
386
+
387
+ transport
388
+ end
389
+
390
+ def option_addresses(value)
391
+ Array(value).map { |entry| Resolver::Entry.convert(entry) }
392
+ end
393
+
394
+ def option_ip_families(value)
395
+ Array(value)
396
+ end
397
+
398
+ def access_option(obj, k, ivar_map)
399
+ case obj
400
+ when Hash
401
+ obj[ivar_map[k]]
402
+ else
403
+ obj.instance_variable_get(k)
404
+ end
405
+ end
406
+
407
+ SET_TEMPORARY_NAME = ->(klass, pl = nil) do
408
+ if klass.respond_to?(:set_temporary_name) # ruby 3.4 only
409
+ name = klass.name || "#{klass.superclass.name}(plugin)"
410
+ name = "#{name}/#{pl}" if pl
411
+ klass.set_temporary_name(name)
412
+ end
413
+ end
414
+
415
+ DEFAULT_OPTIONS = {
416
+ :max_requests => Float::INFINITY,
417
+ :debug => nil,
418
+ :debug_level => (ENV["HTTPX_DEBUG"] || 1).to_i,
419
+ :debug_redact => ENV.key?("HTTPX_DEBUG_REDACT"),
420
+ :ssl => EMPTY_HASH,
421
+ :http2_settings => { settings_enable_push: 0 }.freeze,
422
+ :fallback_protocol => "http/1.1",
423
+ :supported_compression_formats => %w[gzip deflate],
424
+ :decompress_response_body => true,
425
+ :compress_request_body => true,
426
+ :timeout => {
427
+ connect_timeout: CONNECT_TIMEOUT,
428
+ settings_timeout: SETTINGS_TIMEOUT,
429
+ close_handshake_timeout: CLOSE_HANDSHAKE_TIMEOUT,
430
+ operation_timeout: OPERATION_TIMEOUT,
431
+ keep_alive_timeout: KEEP_ALIVE_TIMEOUT,
432
+ read_timeout: READ_TIMEOUT,
433
+ write_timeout: WRITE_TIMEOUT,
434
+ request_timeout: REQUEST_TIMEOUT,
435
+ }.freeze,
436
+ :headers_class => Class.new(Headers, &SET_TEMPORARY_NAME),
437
+ :headers => EMPTY_HASH,
438
+ :window_size => WINDOW_SIZE,
439
+ :buffer_size => BUFFER_SIZE,
440
+ :body_threshold_size => MAX_BODY_THRESHOLD_SIZE,
441
+ :request_class => Class.new(Request, &SET_TEMPORARY_NAME),
442
+ :response_class => Class.new(Response, &SET_TEMPORARY_NAME),
443
+ :request_body_class => Class.new(Request::Body, &SET_TEMPORARY_NAME),
444
+ :response_body_class => Class.new(Response::Body, &SET_TEMPORARY_NAME),
445
+ :pool_class => Class.new(Pool, &SET_TEMPORARY_NAME),
446
+ :connection_class => Class.new(Connection, &SET_TEMPORARY_NAME),
447
+ :http1_class => Class.new(Connection::HTTP1, &SET_TEMPORARY_NAME),
448
+ :http2_class => Class.new(Connection::HTTP2, &SET_TEMPORARY_NAME),
449
+ :resolver_native_class => Class.new(Resolver::Native, &SET_TEMPORARY_NAME),
450
+ :resolver_system_class => Class.new(Resolver::System, &SET_TEMPORARY_NAME),
451
+ :resolver_https_class => Class.new(Resolver::HTTPS, &SET_TEMPORARY_NAME),
452
+ :options_class => Class.new(self, &SET_TEMPORARY_NAME),
453
+ :transport => nil,
454
+ :addresses => nil,
455
+ :persistent => false,
456
+ :resolver_class => (ENV["HTTPX_RESOLVER"] || :native).to_sym,
457
+ :resolver_options => { cache: true }.freeze,
458
+ :pool_options => EMPTY_HASH,
459
+ :ip_families => nil,
460
+ :close_on_fork => false,
461
+ }.freeze
462
+ end
463
+ end
@@ -0,0 +1,186 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HTTPX
4
+ module Parser
5
+ class Error < Error; end
6
+
7
+ class HTTP1
8
+ VERSIONS = %w[1.0 1.1].freeze
9
+
10
+ attr_reader :status_code, :http_version, :headers
11
+
12
+ def initialize(observer)
13
+ @observer = observer
14
+ @state = :idle
15
+ @buffer = "".b
16
+ @headers = {}
17
+ end
18
+
19
+ def <<(chunk)
20
+ @buffer << chunk
21
+ parse
22
+ end
23
+
24
+ def reset!
25
+ @state = :idle
26
+ @headers = {}
27
+ @content_length = nil
28
+ @_has_trailers = nil
29
+ end
30
+
31
+ def upgrade?
32
+ @upgrade
33
+ end
34
+
35
+ def upgrade_data
36
+ @buffer
37
+ end
38
+
39
+ private
40
+
41
+ def parse
42
+ loop do
43
+ state = @state
44
+ case @state
45
+ when :idle
46
+ parse_headline
47
+ when :headers, :trailers
48
+ parse_headers
49
+ when :data
50
+ parse_data
51
+ end
52
+ return if @buffer.empty? || state == @state
53
+ end
54
+ end
55
+
56
+ def parse_headline
57
+ idx = @buffer.index("\n")
58
+ return unless idx
59
+
60
+ (m = %r{\AHTTP(?:/(\d+\.\d+))?\s+(\d\d\d)(?:\s+(.*))?}in.match(@buffer)) ||
61
+ raise(Error, "wrong head line format")
62
+ version, code, _ = m.captures
63
+ raise(Error, "unsupported HTTP version (HTTP/#{version})") unless version && VERSIONS.include?(version)
64
+
65
+ @http_version = version.split(".").map(&:to_i)
66
+ @status_code = code.to_i
67
+ raise(Error, "wrong status code (#{@status_code})") unless (100..599).cover?(@status_code)
68
+
69
+ @buffer = @buffer.byteslice((idx + 1)..-1)
70
+ nextstate(:headers)
71
+ end
72
+
73
+ def parse_headers
74
+ headers = @headers
75
+ buffer = @buffer
76
+
77
+ while (idx = buffer.index("\n"))
78
+ # @type var line: String
79
+ line = buffer.byteslice(0..idx)
80
+ raise Error, "wrong header format" if line.start_with?("\s", "\t")
81
+
82
+ line.lstrip!
83
+ buffer = @buffer = buffer.byteslice((idx + 1)..-1)
84
+ if line.empty?
85
+ case @state
86
+ when :headers
87
+ prepare_data(headers)
88
+ @observer.on_headers(headers)
89
+ return unless @state == :headers
90
+
91
+ # state might have been reset
92
+ # in the :headers callback
93
+ nextstate(:data)
94
+ headers.clear
95
+ when :trailers
96
+ @observer.on_trailers(headers)
97
+ headers.clear
98
+ nextstate(:complete)
99
+ end
100
+ return
101
+ end
102
+ separator_index = line.index(":")
103
+ raise Error, "wrong header format" unless separator_index
104
+
105
+ # @type var key: String
106
+ key = line.byteslice(0..(separator_index - 1))
107
+
108
+ key.rstrip! # was lstripped previously!
109
+ # @type var value: String
110
+ value = line.byteslice((separator_index + 1)..-1)
111
+ value.strip!
112
+ raise Error, "wrong header format" if value.nil?
113
+
114
+ (headers[key.downcase] ||= []) << value
115
+ end
116
+ end
117
+
118
+ def parse_data
119
+ if @buffer.respond_to?(:each)
120
+ @buffer.each do |chunk|
121
+ @observer.on_data(chunk)
122
+ end
123
+ elsif @content_length
124
+ # @type var data: String
125
+ data = @buffer.byteslice(0, @content_length)
126
+ @buffer = @buffer.byteslice(@content_length..-1) || "".b
127
+ @content_length -= data.bytesize
128
+ @observer.on_data(data)
129
+ data.clear
130
+ else
131
+ @observer.on_data(@buffer)
132
+ @buffer.clear
133
+ end
134
+ return unless no_more_data?
135
+
136
+ @buffer = @buffer.to_s
137
+ if @_has_trailers
138
+ nextstate(:trailers)
139
+ else
140
+ nextstate(:complete)
141
+ end
142
+ end
143
+
144
+ def prepare_data(headers)
145
+ @upgrade = headers.key?("upgrade")
146
+
147
+ @_has_trailers = headers.key?("trailer")
148
+
149
+ if (tr_encodings = headers["transfer-encoding"])
150
+ tr_encodings.reverse_each do |tr_encoding|
151
+ tr_encoding.split(/ *, */).each do |encoding|
152
+ case encoding
153
+ when "chunked"
154
+ @buffer = Transcoder::Chunker::Decoder.new(@buffer, @_has_trailers)
155
+ end
156
+ end
157
+ end
158
+ else
159
+ @content_length = headers["content-length"][0].to_i if headers.key?("content-length")
160
+ end
161
+ end
162
+
163
+ def no_more_data?
164
+ if @content_length
165
+ @content_length <= 0
166
+ elsif @buffer.respond_to?(:finished?)
167
+ @buffer.finished?
168
+ else
169
+ false
170
+ end
171
+ end
172
+
173
+ def nextstate(state)
174
+ @state = state
175
+ case state
176
+ when :headers
177
+ @observer.on_start
178
+ when :complete
179
+ @observer.on_complete
180
+ reset!
181
+ nextstate(:idle) unless @buffer.empty?
182
+ end
183
+ end
184
+ end
185
+ end
186
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "httpx/base64"
4
+
5
+ module HTTPX
6
+ module Plugins
7
+ module Authentication
8
+ class Basic
9
+ def initialize(user, password, **)
10
+ @user = user
11
+ @password = password
12
+ end
13
+
14
+ def authenticate(*)
15
+ "Basic #{Base64.strict_encode64("#{@user}:#{@password}")}"
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end