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,468 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "securerandom"
4
+ require "http/2"
5
+
6
+ module HTTPX
7
+ class Connection::HTTP2
8
+ include Callbacks
9
+ include Loggable
10
+
11
+ MAX_CONCURRENT_REQUESTS = ::HTTP2::DEFAULT_MAX_CONCURRENT_STREAMS
12
+
13
+ class Error < Error
14
+ def initialize(id, error)
15
+ super("stream #{id} closed with error: #{error}")
16
+ end
17
+ end
18
+
19
+ class PingError < Error
20
+ def initialize
21
+ super(0, :ping_error)
22
+ end
23
+ end
24
+
25
+ class GoawayError < Error
26
+ def initialize(code = :no_error)
27
+ super(0, code)
28
+ end
29
+ end
30
+
31
+ attr_reader :streams, :pending
32
+
33
+ def initialize(buffer, options)
34
+ @options = options
35
+ @settings = @options.http2_settings
36
+ @pending = []
37
+ @streams = {}
38
+ @drains = {}
39
+ @pings = []
40
+ @buffer = buffer
41
+ @handshake_completed = false
42
+ @wait_for_handshake = @settings.key?(:wait_for_handshake) ? @settings.delete(:wait_for_handshake) : true
43
+ @max_concurrent_requests = @options.max_concurrent_requests || MAX_CONCURRENT_REQUESTS
44
+ @max_requests = @options.max_requests
45
+ init_connection
46
+ end
47
+
48
+ def timeout
49
+ return @options.timeout[:operation_timeout] if @handshake_completed
50
+
51
+ @options.timeout[:settings_timeout]
52
+ end
53
+
54
+ def interests
55
+ if @connection.state == :closed
56
+ return unless @handshake_completed
57
+
58
+ return if @buffer.empty?
59
+
60
+ return :w
61
+ end
62
+
63
+ unless @connection.state == :connected && @handshake_completed
64
+ return @buffer.empty? ? :r : :rw
65
+ end
66
+
67
+ unless @connection.send_buffer.empty?
68
+ return :rw unless @buffer.empty?
69
+
70
+ # waiting for WINDOW_UPDATE frames
71
+ return :r
72
+ end
73
+
74
+ return :w if !@pending.empty? && can_buffer_more_requests?
75
+
76
+ return :w unless @drains.empty?
77
+
78
+ if @buffer.empty?
79
+ return if @streams.empty? && @pings.empty?
80
+
81
+ :r
82
+ else
83
+ :w
84
+ end
85
+ end
86
+
87
+ def close
88
+ unless @connection.state == :closed
89
+ @connection.goaway
90
+ emit(:timeout, @options.timeout[:close_handshake_timeout])
91
+ end
92
+ emit(:close, true)
93
+ end
94
+
95
+ def empty?
96
+ @connection.state == :closed || @streams.empty?
97
+ end
98
+
99
+ def exhausted?
100
+ !@max_requests.positive?
101
+ end
102
+
103
+ def <<(data)
104
+ @connection << data
105
+ end
106
+
107
+ def send(request, head = false)
108
+ unless can_buffer_more_requests?
109
+ head ? @pending.unshift(request) : @pending << request
110
+ return false
111
+ end
112
+ unless (stream = @streams[request])
113
+ stream = @connection.new_stream
114
+ handle_stream(stream, request)
115
+ @streams[request] = stream
116
+ @max_requests -= 1
117
+ end
118
+ handle(request, stream)
119
+ true
120
+ rescue ::HTTP2::Error::StreamLimitExceeded
121
+ @pending.unshift(request)
122
+ false
123
+ end
124
+
125
+ def consume
126
+ @streams.each do |request, stream|
127
+ next unless request.can_buffer?
128
+
129
+ handle(request, stream)
130
+ end
131
+ end
132
+
133
+ def handle_error(ex, request = nil)
134
+ if ex.is_a?(OperationTimeoutError) && !@handshake_completed && @connection.state != :closed
135
+ @connection.goaway(:settings_timeout, "closing due to settings timeout")
136
+ emit(:close_handshake)
137
+ settings_ex = SettingsTimeoutError.new(ex.timeout, ex.message)
138
+ settings_ex.set_backtrace(ex.backtrace)
139
+ ex = settings_ex
140
+ end
141
+ @streams.each_key do |req|
142
+ next if request && request == req
143
+
144
+ emit(:error, req, ex)
145
+ end
146
+ while (req = @pending.shift)
147
+ next if request && request == req
148
+
149
+ emit(:error, req, ex)
150
+ end
151
+ end
152
+
153
+ def ping
154
+ ping = SecureRandom.gen_random(8)
155
+ @connection.ping(ping.dup)
156
+ ensure
157
+ @pings << ping
158
+ end
159
+
160
+ def waiting_for_ping?
161
+ @pings.any?
162
+ end
163
+
164
+ private
165
+
166
+ def can_buffer_more_requests?
167
+ (@handshake_completed || !@wait_for_handshake) &&
168
+ @streams.size < @max_concurrent_requests &&
169
+ @streams.size < @max_requests
170
+ end
171
+
172
+ def send_pending
173
+ while (request = @pending.shift)
174
+ break unless send(request, true)
175
+ end
176
+ end
177
+
178
+ def handle(request, stream)
179
+ catch(:buffer_full) do
180
+ request.transition(:headers)
181
+ join_headers(stream, request) if request.state == :headers
182
+ request.transition(:body)
183
+ join_body(stream, request) if request.state == :body
184
+ request.transition(:trailers)
185
+ join_trailers(stream, request) if request.state == :trailers && !request.body.empty?
186
+ request.transition(:done)
187
+ end
188
+ end
189
+
190
+ def init_connection
191
+ @connection = ::HTTP2::Client.new(@settings)
192
+ @connection.on(:frame, &method(:on_frame))
193
+ @connection.on(:frame_sent, &method(:on_frame_sent))
194
+ @connection.on(:frame_received, &method(:on_frame_received))
195
+ @connection.on(:origin, &method(:on_origin))
196
+ @connection.on(:promise, &method(:on_promise))
197
+ @connection.on(:altsvc) { |frame| on_altsvc(frame[:origin], frame) }
198
+ @connection.on(:settings_ack, &method(:on_settings))
199
+ @connection.on(:ack, &method(:on_pong))
200
+ @connection.on(:goaway, &method(:on_close))
201
+ #
202
+ # Some servers initiate HTTP/2 negotiation right away, some don't.
203
+ # As such, we have to check the socket buffer. If there is something
204
+ # to read, the server initiated the negotiation. If not, we have to
205
+ # initiate it.
206
+ #
207
+ @connection.send_connection_preface
208
+ end
209
+
210
+ alias_method :reset, :init_connection
211
+ public :reset
212
+
213
+ def handle_stream(stream, request)
214
+ request.on(:refuse, &method(:on_stream_refuse).curry(3)[stream, request])
215
+ stream.on(:close, &method(:on_stream_close).curry(3)[stream, request])
216
+ stream.on(:half_close) do
217
+ log(level: 2) { "#{stream.id}: waiting for response..." }
218
+ end
219
+ stream.on(:altsvc, &method(:on_altsvc).curry(2)[request.origin])
220
+ stream.on(:headers, &method(:on_stream_headers).curry(3)[stream, request])
221
+ stream.on(:data, &method(:on_stream_data).curry(3)[stream, request])
222
+ end
223
+
224
+ def set_protocol_headers(request)
225
+ {
226
+ ":scheme" => request.scheme,
227
+ ":method" => request.verb,
228
+ ":path" => request.path,
229
+ ":authority" => request.authority,
230
+ }
231
+ end
232
+
233
+ def join_headers(stream, request)
234
+ extra_headers = set_protocol_headers(request)
235
+
236
+ if request.headers.key?("host")
237
+ log { "forbidden \"host\" header found (#{log_redact(request.headers["host"])}), will use it as authority..." }
238
+ extra_headers[":authority"] = request.headers["host"]
239
+ end
240
+
241
+ log(level: 1, color: :yellow) do
242
+ "\n#{request.headers.merge(extra_headers).each.map { |k, v| "#{stream.id}: -> HEADER: #{k}: #{log_redact(v)}" }.join("\n")}"
243
+ end
244
+ stream.headers(request.headers.each(extra_headers), end_stream: request.body.empty?)
245
+ end
246
+
247
+ def join_trailers(stream, request)
248
+ unless request.trailers?
249
+ stream.data("", end_stream: true) if request.callbacks_for?(:trailers)
250
+ return
251
+ end
252
+
253
+ log(level: 1, color: :yellow) do
254
+ request.trailers.each.map { |k, v| "#{stream.id}: -> HEADER: #{k}: #{log_redact(v)}" }.join("\n")
255
+ end
256
+ stream.headers(request.trailers.each, end_stream: true)
257
+ end
258
+
259
+ def join_body(stream, request)
260
+ return if request.body.empty?
261
+
262
+ chunk = @drains.delete(request) || request.drain_body
263
+ while chunk
264
+ next_chunk = request.drain_body
265
+ send_chunk(request, stream, chunk, next_chunk)
266
+
267
+ if next_chunk && (@buffer.full? || request.body.unbounded_body?)
268
+ @drains[request] = next_chunk
269
+ throw(:buffer_full)
270
+ end
271
+
272
+ chunk = next_chunk
273
+ end
274
+
275
+ return unless (error = request.drain_error)
276
+
277
+ on_stream_refuse(stream, request, error)
278
+ end
279
+
280
+ def send_chunk(request, stream, chunk, next_chunk)
281
+ log(level: 1, color: :green) { "#{stream.id}: -> DATA: #{chunk.bytesize} bytes..." }
282
+ log(level: 2, color: :green) { "#{stream.id}: -> #{log_redact(chunk.inspect)}" }
283
+ stream.data(chunk, end_stream: end_stream?(request, next_chunk))
284
+ end
285
+
286
+ def end_stream?(request, next_chunk)
287
+ !(next_chunk || request.trailers? || request.callbacks_for?(:trailers))
288
+ end
289
+
290
+ ######
291
+ # HTTP/2 Callbacks
292
+ ######
293
+
294
+ def on_stream_headers(stream, request, h)
295
+ response = request.response
296
+
297
+ if response.is_a?(Response) && response.version == "2.0"
298
+ on_stream_trailers(stream, response, h)
299
+ return
300
+ end
301
+
302
+ log(color: :yellow) do
303
+ h.map { |k, v| "#{stream.id}: <- HEADER: #{k}: #{log_redact(v)}" }.join("\n")
304
+ end
305
+ _, status = h.shift
306
+ headers = request.options.headers_class.new(h)
307
+ response = request.options.response_class.new(request, status, "2.0", headers)
308
+ request.response = response
309
+ @streams[request] = stream
310
+
311
+ handle(request, stream) if request.expects?
312
+ end
313
+
314
+ def on_stream_trailers(stream, response, h)
315
+ log(color: :yellow) do
316
+ h.map { |k, v| "#{stream.id}: <- HEADER: #{k}: #{log_redact(v)}" }.join("\n")
317
+ end
318
+ response.merge_headers(h)
319
+ end
320
+
321
+ def on_stream_data(stream, request, data)
322
+ log(level: 1, color: :green) { "#{stream.id}: <- DATA: #{data.bytesize} bytes..." }
323
+ log(level: 2, color: :green) { "#{stream.id}: <- #{log_redact(data.inspect)}" }
324
+ request.response << data
325
+ end
326
+
327
+ def on_stream_refuse(stream, request, error)
328
+ on_stream_close(stream, request, error)
329
+ stream.close
330
+ end
331
+
332
+ def on_stream_close(stream, request, error)
333
+ return if error == :stream_closed && !@streams.key?(request)
334
+
335
+ log(level: 2) { "#{stream.id}: closing stream" }
336
+ teardown(request)
337
+
338
+ if error
339
+ case error
340
+ when :http_1_1_required
341
+ emit(:error, request, error)
342
+ else
343
+ ex = Error.new(stream.id, error)
344
+ ex.set_backtrace(caller)
345
+ response = ErrorResponse.new(request, ex)
346
+ request.response = response
347
+ emit(:response, request, response)
348
+ end
349
+ else
350
+ response = request.response
351
+ if response && response.is_a?(Response) && response.status == 421
352
+ emit(:error, request, :http_1_1_required)
353
+ else
354
+ emit(:response, request, response)
355
+ end
356
+ end
357
+ send(@pending.shift) unless @pending.empty?
358
+
359
+ return unless @streams.empty? && exhausted?
360
+
361
+ if @pending.empty?
362
+ close
363
+ else
364
+ emit(:exhausted)
365
+ end
366
+ end
367
+
368
+ def on_frame(bytes)
369
+ @buffer << bytes
370
+ end
371
+
372
+ def on_settings(*)
373
+ @handshake_completed = true
374
+ emit(:current_timeout)
375
+ @max_concurrent_requests = [@max_concurrent_requests, @connection.remote_settings[:settings_max_concurrent_streams]].min
376
+ send_pending
377
+ end
378
+
379
+ def on_close(_last_frame, error, _payload)
380
+ is_connection_closed = @connection.state == :closed
381
+ if error
382
+ @buffer.clear if is_connection_closed
383
+ case error
384
+ when :http_1_1_required
385
+ while (request = @pending.shift)
386
+ emit(:error, request, error)
387
+ end
388
+ else
389
+ ex = GoawayError.new(error)
390
+ @pending.unshift(*@streams.keys)
391
+ teardown
392
+ end
393
+
394
+ if ex
395
+ ex.set_backtrace(caller)
396
+ handle_error(ex)
397
+ end
398
+ end
399
+ return unless is_connection_closed && @streams.empty?
400
+
401
+ emit(:close, is_connection_closed)
402
+ end
403
+
404
+ def on_frame_sent(frame)
405
+ log(level: 2) { "#{frame[:stream]}: frame was sent!" }
406
+ log(level: 2, color: :blue) do
407
+ payload =
408
+ case frame[:type]
409
+ when :data
410
+ frame.merge(payload: frame[:payload].bytesize)
411
+ when :headers, :ping
412
+ frame.merge(payload: log_redact(frame[:payload]))
413
+ else
414
+ frame
415
+ end
416
+ "#{frame[:stream]}: #{payload}"
417
+ end
418
+ end
419
+
420
+ def on_frame_received(frame)
421
+ log(level: 2) { "#{frame[:stream]}: frame was received!" }
422
+ log(level: 2, color: :magenta) do
423
+ payload =
424
+ case frame[:type]
425
+ when :data
426
+ frame.merge(payload: frame[:payload].bytesize)
427
+ when :headers, :ping
428
+ frame.merge(payload: log_redact(frame[:payload]))
429
+ else
430
+ frame
431
+ end
432
+ "#{frame[:stream]}: #{payload}"
433
+ end
434
+ end
435
+
436
+ def on_altsvc(origin, frame)
437
+ log(level: 2) { "#{frame[:stream]}: altsvc frame was received" }
438
+ log(level: 2) { "#{frame[:stream]}: #{log_redact(frame.inspect)}" }
439
+ alt_origin = URI.parse("#{frame[:proto]}://#{frame[:host]}:#{frame[:port]}")
440
+ params = { "ma" => frame[:max_age] }
441
+ emit(:altsvc, origin, alt_origin, origin, params)
442
+ end
443
+
444
+ def on_promise(stream)
445
+ emit(:promise, @streams.key(stream.parent), stream)
446
+ end
447
+
448
+ def on_origin(origin)
449
+ emit(:origin, origin)
450
+ end
451
+
452
+ def on_pong(ping)
453
+ raise PingError unless @pings.delete(ping.to_s)
454
+
455
+ emit(:pong)
456
+ end
457
+
458
+ def teardown(request = nil)
459
+ if request
460
+ @drains.delete(request)
461
+ @streams.delete(request)
462
+ else
463
+ @drains.clear
464
+ @streams.clear
465
+ end
466
+ end
467
+ end
468
+ end