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,145 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # domain_name.rb - Domain Name manipulation library for Ruby
5
+ #
6
+ # Copyright (C) 2011-2017 Akinori MUSHA, All rights reserved.
7
+ #
8
+ # Redistribution and use in source and binary forms, with or without
9
+ # modification, are permitted provided that the following conditions
10
+ # are met:
11
+ # 1. Redistributions of source code must retain the above copyright
12
+ # notice, this list of conditions and the following disclaimer.
13
+ # 2. Redistributions in binary form must reproduce the above copyright
14
+ # notice, this list of conditions and the following disclaimer in the
15
+ # documentation and/or other materials provided with the distribution.
16
+ #
17
+ # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
+ # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
+ # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
+ # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
+ # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
+ # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
+ # SUCH DAMAGE.
28
+
29
+ require "ipaddr"
30
+
31
+ module HTTPX
32
+ # Represents a domain name ready for extracting its registered domain
33
+ # and TLD.
34
+ class DomainName
35
+ include Comparable
36
+
37
+ # The full host name normalized, ASCII-ized and downcased using the
38
+ # Unicode NFC rules and the Punycode algorithm. If initialized with
39
+ # an IP address, the string representation of the IP address
40
+ # suitable for opening a connection to.
41
+ attr_reader :hostname
42
+
43
+ # The Unicode representation of the #hostname property.
44
+ #
45
+ # :attr_reader: hostname_idn
46
+
47
+ # The least "universally original" domain part of this domain name.
48
+ # For example, "example.co.uk" for "www.sub.example.co.uk". This
49
+ # may be nil if the hostname does not have one, like when it is an
50
+ # IP address, an effective TLD or higher itself, or of a
51
+ # non-canonical domain.
52
+ attr_reader :domain
53
+
54
+ class << self
55
+ def new(domain)
56
+ return domain if domain.is_a?(self)
57
+
58
+ super(domain)
59
+ end
60
+
61
+ # Normalizes a _domain_ using the Punycode algorithm as necessary.
62
+ # The result will be a downcased, ASCII-only string.
63
+ def normalize(domain)
64
+ unless domain.ascii_only?
65
+ domain = domain.chomp(".").unicode_normalize(:nfc)
66
+ domain = Punycode.encode_hostname(domain)
67
+ end
68
+
69
+ domain.downcase
70
+ end
71
+ end
72
+
73
+ # Parses _hostname_ into a DomainName object. An IP address is also
74
+ # accepted. An IPv6 address may be enclosed in square brackets.
75
+ def initialize(hostname)
76
+ hostname = String(hostname)
77
+
78
+ raise ArgumentError, "domain name must not start with a dot: #{hostname}" if hostname.start_with?(".")
79
+
80
+ begin
81
+ @ipaddr = IPAddr.new(hostname)
82
+ @hostname = @ipaddr.to_s
83
+ return
84
+ rescue IPAddr::Error
85
+ nil
86
+ end
87
+
88
+ @hostname = DomainName.normalize(hostname)
89
+ tld = if (last_dot = @hostname.rindex("."))
90
+ @hostname[(last_dot + 1)..-1]
91
+ else
92
+ @hostname
93
+ end
94
+
95
+ # unknown/local TLD
96
+ @domain = if last_dot
97
+ # fallback - accept cookies down to second level
98
+ # cf. http://www.dkim-reputation.org/regdom-libs/
99
+ if (penultimate_dot = @hostname.rindex(".", last_dot - 1))
100
+ @hostname[(penultimate_dot + 1)..-1]
101
+ else
102
+ @hostname
103
+ end
104
+ else
105
+ # no domain part - must be a local hostname
106
+ tld
107
+ end
108
+ end
109
+
110
+ # Checks if the server represented by this domain is qualified to
111
+ # send and receive cookies with a domain attribute value of
112
+ # _domain_. A true value given as the second argument represents
113
+ # cookies without a domain attribute value, in which case only
114
+ # hostname equality is checked.
115
+ def cookie_domain?(domain, host_only = false)
116
+ # RFC 6265 #5.3
117
+ # When the user agent "receives a cookie":
118
+ return self == @domain if host_only
119
+
120
+ domain = DomainName.new(domain)
121
+
122
+ # RFC 6265 #5.1.3
123
+ # Do not perform subdomain matching against IP addresses.
124
+ @hostname == domain.hostname if @ipaddr
125
+
126
+ # RFC 6265 #4.1.1
127
+ # Domain-value must be a subdomain.
128
+ @domain && self <= domain && domain <= @domain
129
+ end
130
+
131
+ def <=>(other)
132
+ other = DomainName.new(other)
133
+ othername = other.hostname
134
+ if othername == @hostname
135
+ 0
136
+ elsif @hostname.end_with?(othername) && @hostname[-othername.size - 1, 1] == "."
137
+ # The other is higher
138
+ -1
139
+ else
140
+ # The other is lower
141
+ 1
142
+ end
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HTTPX
4
+ # the default exception class for exceptions raised by HTTPX.
5
+ class Error < StandardError; end
6
+
7
+ class UnsupportedSchemeError < Error; end
8
+
9
+ class ConnectionError < Error; end
10
+
11
+ # Error raised when there was a timeout. Its subclasses allow for finer-grained
12
+ # control of which timeout happened.
13
+ class TimeoutError < Error
14
+ # The timeout value which caused this error to be raised.
15
+ attr_reader :timeout
16
+
17
+ # initializes the timeout exception with the +timeout+ causing the error, and the
18
+ # error +message+ for it.
19
+ def initialize(timeout, message)
20
+ @timeout = timeout
21
+ super(message)
22
+ end
23
+
24
+ # clones this error into a HTTPX::ConnectionTimeoutError.
25
+ def to_connection_error
26
+ ex = ConnectTimeoutError.new(@timeout, message)
27
+ ex.set_backtrace(backtrace)
28
+ ex
29
+ end
30
+ end
31
+
32
+ # Raise when it can't acquire a connection from the pool.
33
+ class PoolTimeoutError < TimeoutError; end
34
+
35
+ # Error raised when there was a timeout establishing the connection to a server.
36
+ # This may be raised due to timeouts during TCP and TLS (when applicable) connection
37
+ # establishment.
38
+ class ConnectTimeoutError < TimeoutError; end
39
+
40
+ # Error raised when there was a timeout while sending a request, or receiving a response
41
+ # from the server.
42
+ class RequestTimeoutError < TimeoutError
43
+ # The HTTPX::Request request object this exception refers to.
44
+ attr_reader :request
45
+
46
+ # initializes the exception with the +request+ and +response+ it refers to, and the
47
+ # +timeout+ causing the error, and the
48
+ def initialize(request, response, timeout)
49
+ @request = request
50
+ @response = response
51
+ super(timeout, "Timed out after #{timeout} seconds")
52
+ end
53
+
54
+ def marshal_dump
55
+ [message]
56
+ end
57
+ end
58
+
59
+ # Error raised when there was a timeout while receiving a response from the server.
60
+ class ReadTimeoutError < RequestTimeoutError; end
61
+
62
+ # Error raised when there was a timeout while sending a request from the server.
63
+ class WriteTimeoutError < RequestTimeoutError; end
64
+
65
+ # Error raised when there was a timeout while waiting for the HTTP/2 settings frame from the server.
66
+ class SettingsTimeoutError < TimeoutError; end
67
+
68
+ # Error raised when there was a timeout while resolving a domain to an IP.
69
+ class ResolveTimeoutError < TimeoutError; end
70
+
71
+ # Error raise when there was a timeout waiting for readiness of the socket the request is related to.
72
+ class OperationTimeoutError < TimeoutError; end
73
+
74
+ # Error raised when there was an error while resolving a domain to an IP.
75
+ class ResolveError < Error; end
76
+
77
+ # Error raised when there was an error while resolving a domain to an IP
78
+ # using a HTTPX::Resolver::Native resolver.
79
+ class NativeResolveError < ResolveError
80
+ attr_reader :host
81
+
82
+ attr_accessor :connection
83
+
84
+ # initializes the exception with the +connection+ it refers to, the +host+ domain
85
+ # which failed to resolve, and the error +message+.
86
+ def initialize(connection, host, message = "Can't resolve #{host}")
87
+ @connection = connection
88
+ @host = host
89
+ super(message)
90
+ end
91
+ end
92
+
93
+ # The exception class for HTTP responses with 4xx or 5xx status.
94
+ class HTTPError < Error
95
+ # The HTTPX::Response response object this exception refers to.
96
+ attr_reader :response
97
+
98
+ # Creates the instance and assigns the HTTPX::Response +response+.
99
+ def initialize(response)
100
+ @response = response
101
+ super("HTTP Error: #{@response.status} #{@response.headers}\n#{@response.body}")
102
+ end
103
+
104
+ # The HTTP response status.
105
+ #
106
+ # error.status #=> 404
107
+ def status
108
+ @response.status
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "uri"
4
+
5
+ module HTTPX
6
+ module ArrayExtensions
7
+ module FilterMap
8
+ refine Array do
9
+ # Ruby 2.7 backport
10
+ def filter_map
11
+ return to_enum(:filter_map) unless block_given?
12
+
13
+ each_with_object([]) do |item, res|
14
+ processed = yield(item)
15
+ res << processed if processed
16
+ end
17
+ end
18
+ end unless Array.method_defined?(:filter_map)
19
+ end
20
+
21
+ module Intersect
22
+ refine Array do
23
+ # Ruby 3.1 backport
24
+ def intersect?(arr)
25
+ if size < arr.size
26
+ smaller = self
27
+ else
28
+ smaller, arr = arr, self
29
+ end
30
+ (arr & smaller).size > 0
31
+ end
32
+ end unless Array.method_defined?(:intersect?)
33
+ end
34
+ end
35
+
36
+ module URIExtensions
37
+ # uri 0.11 backport, ships with ruby 3.1
38
+ refine URI::Generic do
39
+
40
+ def non_ascii_hostname
41
+ @non_ascii_hostname
42
+ end
43
+
44
+ def non_ascii_hostname=(hostname)
45
+ @non_ascii_hostname = hostname
46
+ end
47
+
48
+ def authority
49
+ return host if port == default_port
50
+
51
+ "#{host}:#{port}"
52
+ end unless URI::HTTP.method_defined?(:authority)
53
+
54
+ def origin
55
+ "#{scheme}://#{authority}"
56
+ end unless URI::HTTP.method_defined?(:origin)
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,176 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HTTPX
4
+ class Headers
5
+ class << self
6
+ def new(headers = nil)
7
+ return headers if headers.is_a?(self)
8
+
9
+ super
10
+ end
11
+ end
12
+
13
+ def initialize(headers = nil)
14
+ if headers.nil? || headers.empty?
15
+ @headers = headers.to_h
16
+ return
17
+ end
18
+
19
+ @headers = {}
20
+
21
+ headers.each do |field, value|
22
+ field = downcased(field)
23
+
24
+ value = array_value(value)
25
+
26
+ current = @headers[field]
27
+
28
+ if current.nil?
29
+ @headers[field] = value
30
+ else
31
+ current.concat(value)
32
+ end
33
+ end
34
+ end
35
+
36
+ # cloned initialization
37
+ def initialize_clone(orig, **kwargs)
38
+ super
39
+ @headers = orig.instance_variable_get(:@headers).clone(**kwargs)
40
+ end
41
+
42
+ # dupped initialization
43
+ def initialize_dup(orig)
44
+ super
45
+ @headers = orig.instance_variable_get(:@headers).dup
46
+ end
47
+
48
+ # freezes the headers hash
49
+ def freeze
50
+ @headers.freeze
51
+ super
52
+ end
53
+
54
+ # merges headers with another header-quack.
55
+ # the merge rule is, if the header already exists,
56
+ # ignore what the +other+ headers has. Otherwise, set
57
+ #
58
+ def merge(other)
59
+ headers = dup
60
+ other.each do |field, value|
61
+ headers[downcased(field)] = value
62
+ end
63
+ headers
64
+ end
65
+
66
+ # returns the comma-separated values of the header field
67
+ # identified by +field+, or nil otherwise.
68
+ #
69
+ def [](field)
70
+ a = @headers[downcased(field)] || return
71
+ a.join(", ")
72
+ end
73
+
74
+ # sets +value+ (if not nil) as single value for the +field+ header.
75
+ #
76
+ def []=(field, value)
77
+ return unless value
78
+
79
+ @headers[downcased(field)] = array_value(value)
80
+ end
81
+
82
+ # deletes all values associated with +field+ header.
83
+ #
84
+ def delete(field)
85
+ canonical = downcased(field)
86
+ @headers.delete(canonical) if @headers.key?(canonical)
87
+ end
88
+
89
+ # adds additional +value+ to the existing, for header +field+.
90
+ #
91
+ def add(field, value)
92
+ (@headers[downcased(field)] ||= []) << String(value)
93
+ end
94
+
95
+ # helper to be used when adding an header field as a value to another field
96
+ #
97
+ # h2_headers.add_header("vary", "accept-encoding")
98
+ # h2_headers["vary"] #=> "accept-encoding"
99
+ # h1_headers.add_header("vary", "accept-encoding")
100
+ # h1_headers["vary"] #=> "Accept-Encoding"
101
+ #
102
+ alias_method :add_header, :add
103
+
104
+ # returns the enumerable headers store in pairs of header field + the values in
105
+ # the comma-separated string format
106
+ #
107
+ def each(extra_headers = nil)
108
+ return enum_for(__method__, extra_headers) { @headers.size } unless block_given?
109
+
110
+ @headers.each do |field, value|
111
+ yield(field, value.join(", ")) unless value.empty?
112
+ end
113
+
114
+ extra_headers.each do |field, value|
115
+ yield(field, value) unless value.empty?
116
+ end if extra_headers
117
+ end
118
+
119
+ def ==(other)
120
+ other == to_hash
121
+ end
122
+
123
+ def empty?
124
+ @headers.empty?
125
+ end
126
+
127
+ # the headers store in Hash format
128
+ def to_hash
129
+ Hash[to_a]
130
+ end
131
+ alias_method :to_h, :to_hash
132
+
133
+ # the headers store in array of pairs format
134
+ def to_a
135
+ Array(each)
136
+ end
137
+
138
+ # headers as string
139
+ def to_s
140
+ @headers.to_s
141
+ end
142
+
143
+ # :nocov:
144
+ def inspect
145
+ "#<#{self.class}:#{object_id} " \
146
+ "#{to_hash.inspect}>"
147
+ end
148
+ # :nocov:
149
+
150
+ # this is internal API and doesn't abide to other public API
151
+ # guarantees, like downcasing strings.
152
+ # Please do not use this outside of core!
153
+ #
154
+ def key?(downcased_key)
155
+ @headers.key?(downcased_key)
156
+ end
157
+
158
+ # returns the values for the +field+ header in array format.
159
+ # This method is more internal, and for this reason doesn't try
160
+ # to "correct" the user input, i.e. it doesn't downcase the key.
161
+ #
162
+ def get(field)
163
+ @headers[field] || EMPTY
164
+ end
165
+
166
+ private
167
+
168
+ def array_value(value)
169
+ Array(value)
170
+ end
171
+
172
+ def downcased(field)
173
+ String(field).downcase
174
+ end
175
+ end
176
+ end
@@ -0,0 +1,163 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "openssl"
4
+
5
+ module HTTPX
6
+ TLSError = OpenSSL::SSL::SSLError
7
+
8
+ class SSL < TCP
9
+ # rubocop:disable Style/MutableConstant
10
+ TLS_OPTIONS = { alpn_protocols: %w[h2 http/1.1].freeze }
11
+ # https://github.com/jruby/jruby-openssl/issues/284
12
+ # TODO: remove when dropping support for jruby-openssl < 0.15.4
13
+ TLS_OPTIONS[:verify_hostname] = true if RUBY_ENGINE == "jruby" && JOpenSSL::VERSION < "0.15.4"
14
+ # rubocop:enable Style/MutableConstant
15
+ TLS_OPTIONS.freeze
16
+
17
+ attr_writer :ssl_session
18
+
19
+ def initialize(_, _, options)
20
+ super
21
+
22
+ @ssl_session = nil
23
+ ctx_options = TLS_OPTIONS.merge(options.ssl)
24
+ @sni_hostname = ctx_options.delete(:hostname) || @hostname
25
+
26
+ if @keep_open && @io.is_a?(OpenSSL::SSL::SSLSocket)
27
+ # externally initiated ssl socket
28
+ @ctx = @io.context
29
+ @state = :negotiated
30
+ else
31
+ @ctx = OpenSSL::SSL::SSLContext.new
32
+ @ctx.set_params(ctx_options) unless ctx_options.empty?
33
+ unless @ctx.session_cache_mode.nil? # a dummy method on JRuby
34
+ @ctx.session_cache_mode =
35
+ OpenSSL::SSL::SSLContext::SESSION_CACHE_CLIENT | OpenSSL::SSL::SSLContext::SESSION_CACHE_NO_INTERNAL_STORE
36
+ end
37
+
38
+ yield(self) if block_given?
39
+ end
40
+
41
+ @verify_hostname = @ctx.verify_hostname
42
+ end
43
+
44
+ if OpenSSL::SSL::SSLContext.method_defined?(:session_new_cb=)
45
+ def session_new_cb(&pr)
46
+ @ctx.session_new_cb = proc { |_, sess| pr.call(sess) }
47
+ end
48
+ else
49
+ # session_new_cb not implemented under JRuby
50
+ def session_new_cb; end
51
+ end
52
+
53
+ def protocol
54
+ @io.alpn_protocol || super
55
+ rescue StandardError
56
+ super
57
+ end
58
+
59
+ if RUBY_ENGINE == "jruby"
60
+ # in jruby, alpn_protocol may return ""
61
+ # https://github.com/jruby/jruby-openssl/issues/287
62
+ def protocol
63
+ proto = @io.alpn_protocol
64
+
65
+ return super if proto.nil? || proto.empty?
66
+
67
+ proto
68
+ rescue StandardError
69
+ super
70
+ end
71
+ end
72
+
73
+ def can_verify_peer?
74
+ @ctx.verify_mode == OpenSSL::SSL::VERIFY_PEER
75
+ end
76
+
77
+ def verify_hostname(host)
78
+ return false if @ctx.verify_mode == OpenSSL::SSL::VERIFY_NONE
79
+ return false if !@io.respond_to?(:peer_cert) || @io.peer_cert.nil?
80
+
81
+ OpenSSL::SSL.verify_certificate_identity(@io.peer_cert, host)
82
+ end
83
+
84
+ def connected?
85
+ @state == :negotiated
86
+ end
87
+
88
+ def ssl_session_expired?
89
+ @ssl_session.nil? || Process.clock_gettime(Process::CLOCK_REALTIME) >= (@ssl_session.time.to_f + @ssl_session.timeout)
90
+ end
91
+
92
+ def connect
93
+ return if @state == :negotiated
94
+
95
+ unless @state == :connected
96
+ super
97
+ return unless @state == :connected
98
+ end
99
+
100
+ unless @io.is_a?(OpenSSL::SSL::SSLSocket)
101
+ if (hostname_is_ip = (@ip == @sni_hostname)) && @ctx.verify_hostname
102
+ # IPv6 address would be "[::1]", must turn to "0000:0000:0000:0000:0000:0000:0000:0001" for cert SAN check
103
+ @sni_hostname = @ip.to_string
104
+ # IP addresses in SNI is not valid per RFC 6066, section 3.
105
+ @ctx.verify_hostname = false
106
+ end
107
+
108
+ @io = OpenSSL::SSL::SSLSocket.new(@io, @ctx)
109
+
110
+ @io.hostname = @sni_hostname unless hostname_is_ip
111
+ @io.session = @ssl_session unless ssl_session_expired?
112
+ @io.sync_close = true
113
+ end
114
+ try_ssl_connect
115
+ end
116
+
117
+ def try_ssl_connect
118
+ ret = @io.connect_nonblock(exception: false)
119
+ log(level: 3, color: :cyan) { "TLS CONNECT: #{ret}..." }
120
+ case ret
121
+ when :wait_readable
122
+ @interests = :r
123
+ return
124
+ when :wait_writable
125
+ @interests = :w
126
+ return
127
+ end
128
+ @io.post_connection_check(@sni_hostname) if @ctx.verify_mode != OpenSSL::SSL::VERIFY_NONE && @verify_hostname
129
+ transition(:negotiated)
130
+ @interests = :w
131
+ end
132
+
133
+ private
134
+
135
+ def transition(nextstate)
136
+ case nextstate
137
+ when :negotiated
138
+ return unless @state == :connected
139
+
140
+ when :closed
141
+ return unless @state == :negotiated ||
142
+ @state == :connected
143
+ end
144
+ do_transition(nextstate)
145
+ end
146
+
147
+ def log_transition_state(nextstate)
148
+ return super unless nextstate == :negotiated
149
+
150
+ server_cert = @io.peer_cert
151
+
152
+ "#{super}\n\n" \
153
+ "SSL connection using #{@io.ssl_version} / #{Array(@io.cipher).first}\n" \
154
+ "ALPN, server accepted to use #{protocol}\n" \
155
+ "Server certificate:\n " \
156
+ "subject: #{server_cert.subject}\n " \
157
+ "start date: #{server_cert.not_before}\n " \
158
+ "expire date: #{server_cert.not_after}\n " \
159
+ "issuer: #{server_cert.issuer}\n " \
160
+ "SSL certificate verify ok."
161
+ end
162
+ end
163
+ end