httpunk 0.4.5__tar.gz → 0.5.0__tar.gz

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 (161) hide show
  1. {httpunk-0.4.5 → httpunk-0.5.0}/Cargo.lock +47 -22
  2. {httpunk-0.4.5 → httpunk-0.5.0}/Cargo.toml +14 -12
  3. {httpunk-0.4.5 → httpunk-0.5.0}/PKG-INFO +2 -3
  4. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-h2/Cargo.toml +2 -2
  5. httpunk-0.5.0/crates/vendor-h2/UPSTREAM_VERSION +1 -0
  6. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-h2/src/frame/go_away.rs +11 -1
  7. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-h2/src/frame/headers.rs +2 -2
  8. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-h2/src/frame/mod.rs +2 -2
  9. httpunk-0.5.0/crates/vendor-h2/src/hpack/huffman/decode.rs +349 -0
  10. httpunk-0.5.0/crates/vendor-h2/src/hpack/huffman/encode.rs +124 -0
  11. httpunk-0.5.0/crates/vendor-h2/src/hpack/huffman/mod.rs +100 -0
  12. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-h2/src/hpack/huffman/table.rs +42 -259
  13. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-h2/src/hpack/table.rs +6 -11
  14. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-h2/src/lib.rs +9 -10
  15. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-h2/src/proto/mod.rs +1 -1
  16. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-hyper/Cargo.toml +2 -1
  17. httpunk-0.5.0/crates/vendor-hyper/UPSTREAM_VERSION +1 -0
  18. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-hyper/src/ext/h1_reason_phrase.rs +5 -1
  19. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-hyper/src/ext/informational.rs +1 -1
  20. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-hyper/src/ext/mod.rs +5 -40
  21. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-hyper/src/lib.rs +12 -9
  22. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-hyper/src/proto/h1/decode.rs +12 -9
  23. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-hyper/src/proto/h1/encode.rs +18 -14
  24. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-hyper/src/proto/h1/httpunk.rs +96 -63
  25. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-hyper/src/proto/h1/mod.rs +1 -0
  26. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-hyper/src/proto/h1/role.rs +400 -14
  27. httpunk-0.5.0/crates/vendor-hyper-util/Cargo.toml +25 -0
  28. httpunk-0.5.0/crates/vendor-hyper-util/UPSTREAM_VERSION +1 -0
  29. httpunk-0.5.0/crates/vendor-hyper-util/src/client/mod.rs +32 -0
  30. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-hyper-util/src/client/proxy/matcher.rs +80 -30
  31. httpunk-0.5.0/crates/vendor-hyper-util/src/client/proxy/mod.rs +3 -0
  32. httpunk-0.5.0/crates/vendor-hyper-util/src/lib.rs +19 -0
  33. {httpunk-0.4.5 → httpunk-0.5.0}/httpunk/_backend/asyncio.py +12 -10
  34. {httpunk-0.4.5 → httpunk-0.5.0}/httpunk/_backend/tonio.py +4 -2
  35. {httpunk-0.4.5 → httpunk-0.5.0}/httpunk/_common.py +14 -3
  36. {httpunk-0.4.5 → httpunk-0.5.0}/httpunk/_httpunk.pyi +55 -14
  37. {httpunk-0.4.5 → httpunk-0.5.0}/httpunk/asyncio.py +5 -5
  38. {httpunk-0.4.5 → httpunk-0.5.0}/httpunk/exceptions.py +1 -1
  39. {httpunk-0.4.5 → httpunk-0.5.0}/httpunk/h1/client.py +100 -43
  40. {httpunk-0.4.5 → httpunk-0.5.0}/httpunk/h1/connection.py +7 -7
  41. {httpunk-0.4.5 → httpunk-0.5.0}/httpunk/h1/server.py +82 -36
  42. {httpunk-0.4.5 → httpunk-0.5.0}/httpunk/h1/share.py +3 -3
  43. {httpunk-0.4.5 → httpunk-0.5.0}/httpunk/h2/client.py +79 -19
  44. {httpunk-0.4.5 → httpunk-0.5.0}/httpunk/h2/connection.py +34 -19
  45. {httpunk-0.4.5 → httpunk-0.5.0}/httpunk/h2/server.py +16 -8
  46. {httpunk-0.4.5 → httpunk-0.5.0}/httpunk/h2/share.py +2 -2
  47. {httpunk-0.4.5 → httpunk-0.5.0}/httpunk/h2/stream.py +2 -2
  48. {httpunk-0.4.5 → httpunk-0.5.0}/httpunk/types.py +2 -2
  49. {httpunk-0.4.5 → httpunk-0.5.0}/httpunk/util/auto.py +9 -3
  50. {httpunk-0.4.5 → httpunk-0.5.0}/httpunk/util/client.py +1 -1
  51. {httpunk-0.4.5 → httpunk-0.5.0}/httpunk/util/graceful.py +2 -2
  52. {httpunk-0.4.5 → httpunk-0.5.0}/httpunk/util/pool.py +104 -76
  53. {httpunk-0.4.5 → httpunk-0.5.0}/pyproject.toml +1 -2
  54. {httpunk-0.4.5 → httpunk-0.5.0}/src/h1/codec.rs +135 -39
  55. {httpunk-0.4.5 → httpunk-0.5.0}/src/h1/conn.rs +27 -11
  56. {httpunk-0.4.5 → httpunk-0.5.0}/src/h1/errors.rs +3 -2
  57. {httpunk-0.4.5 → httpunk-0.5.0}/src/h2/codec.rs +41 -28
  58. {httpunk-0.4.5 → httpunk-0.5.0}/src/h2/conn.rs +193 -95
  59. {httpunk-0.4.5 → httpunk-0.5.0}/src/h2/errors.rs +23 -2
  60. {httpunk-0.4.5 → httpunk-0.5.0}/src/h2/reason.rs +1 -8
  61. {httpunk-0.4.5 → httpunk-0.5.0}/src/h2/settings.rs +4 -4
  62. {httpunk-0.4.5 → httpunk-0.5.0}/src/h2/streams.rs +27 -23
  63. {httpunk-0.4.5 → httpunk-0.5.0}/src/http/mod.rs +2 -2
  64. {httpunk-0.4.5 → httpunk-0.5.0}/src/py.rs +3 -5
  65. httpunk-0.5.0/tests/_net.py +285 -0
  66. {httpunk-0.4.5 → httpunk-0.5.0}/tests/conftest.py +20 -4
  67. {httpunk-0.4.5 → httpunk-0.5.0}/tests/test_asyncio_backend.py +6 -6
  68. {httpunk-0.4.5 → httpunk-0.5.0}/tests/test_asyncio_e2e.py +108 -10
  69. {httpunk-0.4.5 → httpunk-0.5.0}/tests/test_asyncio_protocol.py +5 -5
  70. {httpunk-0.4.5 → httpunk-0.5.0}/tests/test_backend.py +5 -3
  71. httpunk-0.5.0/tests/test_h1_builder_options.py +163 -0
  72. {httpunk-0.4.5 → httpunk-0.5.0}/tests/test_h1_codec.py +18 -6
  73. {httpunk-0.4.5 → httpunk-0.5.0}/tests/test_h1_conn.py +234 -420
  74. {httpunk-0.4.5 → httpunk-0.5.0}/tests/test_h1_decode.py +2 -2
  75. httpunk-0.5.0/tests/test_h1_max_header_size.py +75 -0
  76. {httpunk-0.4.5 → httpunk-0.5.0}/tests/test_h1_server.py +344 -565
  77. httpunk-0.5.0/tests/test_h2_builder_options.py +200 -0
  78. {httpunk-0.4.5 → httpunk-0.5.0}/tests/test_h2_codec.py +1 -1
  79. httpunk-0.5.0/tests/test_h2_conn.py +45 -0
  80. httpunk-0.5.0/tests/test_h2_errors.py +695 -0
  81. {httpunk-0.4.5 → httpunk-0.5.0}/tests/test_h2_flow.py +56 -110
  82. {httpunk-0.4.5 → httpunk-0.5.0}/tests/test_h2_ready.py +2 -2
  83. httpunk-0.5.0/tests/test_h2_refusal.py +84 -0
  84. {httpunk-0.4.5 → httpunk-0.5.0}/tests/test_h2_server.py +260 -460
  85. {httpunk-0.4.5 → httpunk-0.5.0}/tests/test_h2_settings.py +2 -2
  86. {httpunk-0.4.5 → httpunk-0.5.0}/tests/test_h2_write_batch.py +3 -4
  87. httpunk-0.5.0/tests/test_handshake_abort.py +134 -0
  88. {httpunk-0.4.5 → httpunk-0.5.0}/tests/test_util_auto.py +5 -10
  89. {httpunk-0.4.5 → httpunk-0.5.0}/tests/test_util_graceful.py +8 -15
  90. httpunk-0.5.0/tests/test_util_pool.py +564 -0
  91. {httpunk-0.4.5 → httpunk-0.5.0}/tests/test_util_tls.py +12 -28
  92. httpunk-0.4.5/crates/vendor-h2/UPSTREAM_VERSION +0 -1
  93. httpunk-0.4.5/crates/vendor-h2/src/hpack/huffman/mod.rs +0 -263
  94. httpunk-0.4.5/crates/vendor-hyper/UPSTREAM_VERSION +0 -1
  95. httpunk-0.4.5/crates/vendor-hyper-util/Cargo.toml +0 -22
  96. httpunk-0.4.5/crates/vendor-hyper-util/UPSTREAM_VERSION +0 -1
  97. httpunk-0.4.5/crates/vendor-hyper-util/src/client/mod.rs +0 -4
  98. httpunk-0.4.5/crates/vendor-hyper-util/src/client/proxy/mod.rs +0 -5
  99. httpunk-0.4.5/crates/vendor-hyper-util/src/lib.rs +0 -18
  100. httpunk-0.4.5/tests/_client.py +0 -25
  101. httpunk-0.4.5/tests/test_h2_conn.py +0 -91
  102. httpunk-0.4.5/tests/test_h2_errors.py +0 -881
  103. httpunk-0.4.5/tests/test_util_pool.py +0 -402
  104. {httpunk-0.4.5 → httpunk-0.5.0}/LICENSE +0 -0
  105. {httpunk-0.4.5 → httpunk-0.5.0}/README.md +0 -0
  106. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-h2/LICENSE +0 -0
  107. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-h2/src/codec/error.rs +0 -0
  108. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-h2/src/codec/mod.rs +0 -0
  109. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-h2/src/error.rs +0 -0
  110. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-h2/src/ext.rs +0 -0
  111. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-h2/src/frame/data.rs +0 -0
  112. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-h2/src/frame/head.rs +0 -0
  113. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-h2/src/frame/ping.rs +0 -0
  114. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-h2/src/frame/priority.rs +0 -0
  115. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-h2/src/frame/reason.rs +0 -0
  116. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-h2/src/frame/reset.rs +0 -0
  117. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-h2/src/frame/settings.rs +0 -0
  118. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-h2/src/frame/stream_id.rs +0 -0
  119. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-h2/src/frame/util.rs +0 -0
  120. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-h2/src/frame/window_update.rs +0 -0
  121. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-h2/src/hpack/decoder.rs +0 -0
  122. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-h2/src/hpack/encoder.rs +0 -0
  123. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-h2/src/hpack/header.rs +0 -0
  124. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-h2/src/hpack/mod.rs +0 -0
  125. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-h2/src/proto/error.rs +0 -0
  126. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-h2/src/proto/streams/flow_control.rs +0 -0
  127. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-h2/src/proto/streams/mod.rs +0 -0
  128. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-h2/src/proto/streams/state.rs +0 -0
  129. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-hyper/LICENSE +0 -0
  130. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-hyper/src/body/length.rs +0 -0
  131. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-hyper/src/body/mod.rs +0 -0
  132. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-hyper/src/cfg.rs +0 -0
  133. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-hyper/src/common/date.rs +0 -0
  134. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-hyper/src/common/mod.rs +0 -0
  135. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-hyper/src/error.rs +0 -0
  136. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-hyper/src/headers.rs +0 -0
  137. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-hyper/src/proto/h1/io.rs +0 -0
  138. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-hyper/src/proto/mod.rs +0 -0
  139. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-hyper/src/trace.rs +0 -0
  140. {httpunk-0.4.5 → httpunk-0.5.0}/crates/vendor-hyper-util/LICENSE +0 -0
  141. {httpunk-0.4.5 → httpunk-0.5.0}/httpunk/__init__.py +0 -0
  142. {httpunk-0.4.5 → httpunk-0.5.0}/httpunk/_backend/__init__.py +0 -0
  143. {httpunk-0.4.5 → httpunk-0.5.0}/httpunk/h1/__init__.py +0 -0
  144. {httpunk-0.4.5 → httpunk-0.5.0}/httpunk/h2/__init__.py +0 -0
  145. {httpunk-0.4.5 → httpunk-0.5.0}/httpunk/http.py +0 -0
  146. {httpunk-0.4.5 → httpunk-0.5.0}/httpunk/py.typed +0 -0
  147. {httpunk-0.4.5 → httpunk-0.5.0}/httpunk/util/__init__.py +0 -0
  148. {httpunk-0.4.5 → httpunk-0.5.0}/httpunk/util/proxy.py +0 -0
  149. {httpunk-0.4.5 → httpunk-0.5.0}/src/errors.rs +0 -0
  150. {httpunk-0.4.5 → httpunk-0.5.0}/src/h1/mod.rs +0 -0
  151. {httpunk-0.4.5 → httpunk-0.5.0}/src/h2/mod.rs +0 -0
  152. {httpunk-0.4.5 → httpunk-0.5.0}/src/lib.rs +0 -0
  153. {httpunk-0.4.5 → httpunk-0.5.0}/src/proxy.rs +0 -0
  154. {httpunk-0.4.5 → httpunk-0.5.0}/tests/_transport.py +0 -0
  155. {httpunk-0.4.5 → httpunk-0.5.0}/tests/test_asyncio_client_protocol.py +0 -0
  156. {httpunk-0.4.5 → httpunk-0.5.0}/tests/test_error_retention.py +0 -0
  157. {httpunk-0.4.5 → httpunk-0.5.0}/tests/test_h2_flow_control.py +0 -0
  158. {httpunk-0.4.5 → httpunk-0.5.0}/tests/test_h2_state.py +0 -0
  159. {httpunk-0.4.5 → httpunk-0.5.0}/tests/test_headermap.py +0 -0
  160. {httpunk-0.4.5 → httpunk-0.5.0}/tests/test_util_connect.py +0 -0
  161. {httpunk-0.4.5 → httpunk-0.5.0}/tests/test_util_proxy.py +0 -0
@@ -10,9 +10,9 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
10
10
 
11
11
  [[package]]
12
12
  name = "base64"
13
- version = "0.22.1"
13
+ version = "0.23.1"
14
14
  source = "registry+https://github.com/rust-lang/crates.io-index"
15
- checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
15
+ checksum = "ac07cdecf99051d9a5238b80f35af32cdeba5b336e55d957b318b50137e18da5"
16
16
 
17
17
  [[package]]
18
18
  name = "bytes"
@@ -71,9 +71,9 @@ checksum = "1944426bf7d03f1d14f708785e4b33efd750b36d48a157b836b3efc15ede8e1d"
71
71
 
72
72
  [[package]]
73
73
  name = "h2"
74
- version = "0.4.19"
74
+ version = "0.4.20"
75
75
  source = "registry+https://github.com/rust-lang/crates.io-index"
76
- checksum = "ef8e5e5a340588f4452631496976cf8636d4a7ecf600239fdc27615d2530bc16"
76
+ checksum = "7d29020232d6aa3fb1daca64c1127cf662cf97f254ae16c18c05b8ab635fc118"
77
77
  dependencies = [
78
78
  "atomic-waker",
79
79
  "bytes",
@@ -134,12 +134,13 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
134
134
 
135
135
  [[package]]
136
136
  name = "httpunk"
137
- version = "0.4.5"
137
+ version = "0.5.0"
138
138
  dependencies = [
139
139
  "bytes",
140
140
  "h2",
141
141
  "http",
142
142
  "hyper",
143
+ "hyper-util",
143
144
  "mimalloc",
144
145
  "pyo3",
145
146
  "vendor-h2",
@@ -149,13 +150,12 @@ dependencies = [
149
150
 
150
151
  [[package]]
151
152
  name = "hyper"
152
- version = "1.11.1"
153
+ version = "1.12.0"
153
154
  source = "registry+https://github.com/rust-lang/crates.io-index"
154
- checksum = "27b501faa50e7a26c3d3560ca625132f4078a17771f4810baf70475ae48cbe43"
155
+ checksum = "2c3e324da4c95177d6291d4c8730197c0d1822f8a9766814a4a44fa5ab797c9c"
155
156
  dependencies = [
156
157
  "atomic-waker",
157
158
  "bytes",
158
- "futures-channel",
159
159
  "futures-core",
160
160
  "http",
161
161
  "http-body",
@@ -168,6 +168,25 @@ dependencies = [
168
168
  "want",
169
169
  ]
170
170
 
171
+ [[package]]
172
+ name = "hyper-util"
173
+ version = "0.1.21"
174
+ source = "registry+https://github.com/rust-lang/crates.io-index"
175
+ checksum = "ddc03d96684f9226b8a787cdb71488417b53ab5ea8fdb1dac946cb9431cc8bff"
176
+ dependencies = [
177
+ "base64",
178
+ "bytes",
179
+ "futures-channel",
180
+ "http",
181
+ "http-body",
182
+ "hyper",
183
+ "ipnet",
184
+ "percent-encoding",
185
+ "pin-project-lite",
186
+ "tower-service",
187
+ "tracing",
188
+ ]
189
+
171
190
  [[package]]
172
191
  name = "indexmap"
173
192
  version = "2.14.0"
@@ -249,9 +268,9 @@ dependencies = [
249
268
 
250
269
  [[package]]
251
270
  name = "pyo3"
252
- version = "0.29.2"
271
+ version = "0.30.1"
253
272
  source = "registry+https://github.com/rust-lang/crates.io-index"
254
- checksum = "4688ddedf473e32662b9b067670129a8afb8c18e351482c70d62ba4a88171e8b"
273
+ checksum = "229ca13b8a15bb0d1487b81ab975bfcd97513416499a8312011b6036e42e0de4"
255
274
  dependencies = [
256
275
  "libc",
257
276
  "once_cell",
@@ -263,18 +282,18 @@ dependencies = [
263
282
 
264
283
  [[package]]
265
284
  name = "pyo3-build-config"
266
- version = "0.29.2"
285
+ version = "0.30.1"
267
286
  source = "registry+https://github.com/rust-lang/crates.io-index"
268
- checksum = "f41027e41b4bd03f6e60f9f417fe24a6341a6bb744edd62b6f709f2a52ea30e9"
287
+ checksum = "70130e2b6dd1ee589a8788026a429561ca5c40fa7a2fa7914c2282eddae24700"
269
288
  dependencies = [
270
289
  "target-lexicon",
271
290
  ]
272
291
 
273
292
  [[package]]
274
293
  name = "pyo3-ffi"
275
- version = "0.29.2"
294
+ version = "0.30.1"
276
295
  source = "registry+https://github.com/rust-lang/crates.io-index"
277
- checksum = "e591a95526fead067432c3b3a33fc74770b87b1e04e73671090d9c2055a2b327"
296
+ checksum = "5e7ff73c555c286d212d4ce7e5fbda845a973c4f61bd5f160f5f2c3c2a04d1c4"
278
297
  dependencies = [
279
298
  "libc",
280
299
  "pyo3-build-config",
@@ -282,9 +301,9 @@ dependencies = [
282
301
 
283
302
  [[package]]
284
303
  name = "pyo3-macros"
285
- version = "0.29.2"
304
+ version = "0.30.1"
286
305
  source = "registry+https://github.com/rust-lang/crates.io-index"
287
- checksum = "73225868fc1cd84eef2c3c230ddb91273bf1de46aeb8a4248da76d32a0924a1c"
306
+ checksum = "c46d2e5862c7bb8207e3b639f713dda3c499933444784154c11d013c5a691b60"
288
307
  dependencies = [
289
308
  "proc-macro2",
290
309
  "pyo3-macros-backend",
@@ -294,9 +313,9 @@ dependencies = [
294
313
 
295
314
  [[package]]
296
315
  name = "pyo3-macros-backend"
297
- version = "0.29.2"
316
+ version = "0.30.1"
298
317
  source = "registry+https://github.com/rust-lang/crates.io-index"
299
- checksum = "571575aa3749fa6216757dd47d2a3e7ef360f329a40f0666a9fbd14889024952"
318
+ checksum = "38b89f066f2ae72a2aef52d1537ca2fcd104440ebfadee06e97aa90738a25b9b"
300
319
  dependencies = [
301
320
  "heck",
302
321
  "proc-macro2",
@@ -333,9 +352,9 @@ checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90"
333
352
 
334
353
  [[package]]
335
354
  name = "syn"
336
- version = "2.0.119"
355
+ version = "3.0.9"
337
356
  source = "registry+https://github.com/rust-lang/crates.io-index"
338
- checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297"
357
+ checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b"
339
358
  dependencies = [
340
359
  "proc-macro2",
341
360
  "quote",
@@ -372,6 +391,12 @@ dependencies = [
372
391
  "tokio",
373
392
  ]
374
393
 
394
+ [[package]]
395
+ name = "tower-service"
396
+ version = "0.3.3"
397
+ source = "registry+https://github.com/rust-lang/crates.io-index"
398
+ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
399
+
375
400
  [[package]]
376
401
  name = "tracing"
377
402
  version = "0.1.44"
@@ -438,9 +463,9 @@ dependencies = [
438
463
 
439
464
  [[package]]
440
465
  name = "want"
441
- version = "0.3.1"
466
+ version = "0.3.2"
442
467
  source = "registry+https://github.com/rust-lang/crates.io-index"
443
- checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
468
+ checksum = "ec4cdd0dd910afe868b7ef477227d8d538b46b3075031afee8a9f2acb0a2ed0b"
444
469
  dependencies = [
445
470
  "try-lock",
446
471
  ]
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "httpunk"
3
- version = "0.4.5"
3
+ version = "0.5.0"
4
4
  description = "The Rust HTTP library for Python"
5
5
  authors = [
6
6
  "Giovanni Barillari <g@baro.dev>",
@@ -40,25 +40,27 @@ crate-type = ["cdylib"]
40
40
 
41
41
  [features]
42
42
  mimalloc = ["dep:mimalloc"]
43
- # Never enabled. Exists only so the optional crates.io `h2`/`hyper` deps are
44
- # referenced (no "unused optional dependency"), keeping them in Cargo.lock for
45
- # advisory scanning while they stay uncompiled. See the dependency comments.
46
- _audit = ["dep:h2", "dep:hyper"]
43
+ # Never enabled. Exists only so the optional crates.io `h2`/`hyper`/`hyper-util`
44
+ # deps are referenced (no "unused optional dependency"), keeping them in Cargo.lock
45
+ # for advisory scanning while they stay uncompiled. See the dependency comments.
46
+ _audit = ["dep:h2", "dep:hyper", "dep:hyper-util"]
47
47
 
48
48
  [dependencies]
49
49
  bytes = "1"
50
50
  http = "1.1"
51
51
  mimalloc = { version = "0.1.49", default-features = false, features = ["local_dynamic_tls"], optional = true }
52
- pyo3 = { version = "=0.29", features = ["extension-module", "generate-import-lib"] }
52
+ pyo3 = { version = "=0.30", features = ["extension-module", "generate-import-lib"] }
53
53
  vendor-h2 = { path = "crates/vendor-h2" }
54
54
  vendor-hyper = { path = "crates/vendor-hyper", features = ["client", "server", "http1"] }
55
55
  vendor-hyper-util = { path = "crates/vendor-hyper-util" }
56
- # NOT compiled: the crates.io `h2`/`hyper` — vendored into crates/vendor-*/ (see
57
- # THIRD-PARTY.md). Optional + gated behind the never-enabled `_audit` feature so
58
- # the pinned versions land in Cargo.lock for `cargo audit` / Dependabot advisory
59
- # coverage without pulling them (and tokio) into the build.
60
- h2 = { version = "=0.4.19", optional = true }
61
- hyper = { version = "=1.11.1", optional = true, default-features = false, features = ["http1", "client", "server"] }
56
+ # NOT compiled: the crates.io `h2`/`hyper`/`hyper-util`; their sans-IO code is
57
+ # vendored into crates/vendor-*/ by scripts/vendor-*.sh. Optional + gated behind
58
+ # the never-enabled `_audit` feature so the pinned versions land in Cargo.lock
59
+ # for `cargo audit` / Dependabot advisory coverage without pulling them (and
60
+ # tokio) into the build. hyper-util's client-proxy mirrors the vendored surface.
61
+ h2 = { version = "=0.4.20", optional = true }
62
+ hyper = { version = "=1.12.0", optional = true, default-features = false, features = ["http1", "client", "server"] }
63
+ hyper-util = { version = "=0.1.21", optional = true, default-features = false, features = ["client-proxy"] }
62
64
 
63
65
  [profile.release]
64
66
  codegen-units = 1
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: httpunk
3
- Version: 0.4.5
3
+ Version: 0.5.0
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: License :: OSI Approved :: BSD License
@@ -8,7 +8,6 @@ Classifier: Operating System :: MacOS
8
8
  Classifier: Operating System :: Microsoft :: Windows
9
9
  Classifier: Operating System :: POSIX :: Linux
10
10
  Classifier: Programming Language :: Python :: 3
11
- Classifier: Programming Language :: Python :: 3.10
12
11
  Classifier: Programming Language :: Python :: 3.11
13
12
  Classifier: Programming Language :: Python :: 3.12
14
13
  Classifier: Programming Language :: Python :: 3.13
@@ -28,7 +27,7 @@ Keywords: http,h10,h11,h2
28
27
  Home-Page: https://github.com/gi0baro/httpunk
29
28
  Author-email: Giovanni Barillari <g@baro.dev>
30
29
  License: BSD-3-Clause
31
- Requires-Python: >=3.10
30
+ Requires-Python: >=3.11
32
31
  Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
33
32
  Project-URL: Funding, https://github.com/sponsors/gi0baro
34
33
  Project-URL: Homepage, https://github.com/gi0baro/httpunk
@@ -1,5 +1,5 @@
1
- # Vendored hyperium/h2 (frame + hpack + sync proto pieces), byte-identical to
2
- # upstream — see ../../THIRD-PARTY.md. A workspace member crate so it owns its
1
+ # Vendored hyperium/h2 (frame + hpack + sync proto pieces); scripts/vendor-h2.sh
2
+ # enumerates every modification to upstream. A workspace member crate so it owns its
3
3
  # own crate root (upstream `crate::` paths resolve natively, no rewrite) and is
4
4
  # excluded from the main crate's fmt/clippy via `cargo fmt -p`.
5
5
  [package]
@@ -0,0 +1 @@
1
+ 0.4.20
@@ -40,7 +40,17 @@ impl GoAway {
40
40
  &self.debug_data
41
41
  }
42
42
 
43
- pub fn load(payload: &[u8]) -> Result<GoAway, Error> {
43
+ pub fn load(head: Head, payload: &[u8]) -> Result<GoAway, Error> {
44
+ debug_assert_eq!(head.kind(), crate::frame::Kind::GoAway);
45
+
46
+ // The GOAWAY frame applies to the connection, not a specific stream.
47
+ // An endpoint MUST treat a GOAWAY frame with a stream identifier
48
+ // other than 0x00 as a connection error (Section 5.4.1) of type
49
+ // PROTOCOL_ERROR.
50
+ if !head.stream_id().is_zero() {
51
+ return Err(Error::InvalidStreamId);
52
+ }
53
+
44
54
  if payload.len() < 8 {
45
55
  return Err(Error::BadFrameSize);
46
56
  }
@@ -381,7 +381,7 @@ impl PushPromise {
381
381
 
382
382
  // A promised request "that indicates the presence of a request body
383
383
  // MUST reset the promised stream with a stream error"
384
- if let Some(content_length) = req.headers().get(header::CONTENT_LENGTH) {
384
+ for content_length in req.headers().get_all(header::CONTENT_LENGTH) {
385
385
  let parsed_length = parse_u64(content_length.as_bytes());
386
386
  if parsed_length != Ok(0) {
387
387
  return Err(InvalidContentLength(parsed_length));
@@ -948,7 +948,7 @@ impl HeaderBlock {
948
948
  }
949
949
  if !self.is_over_size {
950
950
  self.field_size += header_size;
951
- if let Err(_) = self.fields.try_append(name, value) {
951
+ if self.fields.try_append(name, value).is_err() {
952
952
  // HeaderMap capacity exceeded — treat as over-size
953
953
  // so the stream is rejected downstream (RST_STREAM / 431)
954
954
  // instead of panicking on the 24,577th unique header.
@@ -153,8 +153,8 @@ pub enum Error {
153
153
 
154
154
  /// An invalid stream identifier was provided.
155
155
  ///
156
- /// This is returned if a SETTINGS or PING frame is received with a stream
157
- /// identifier other than zero.
156
+ /// This is returned if a SETTINGS, PING or GOAWAY frame is received with a
157
+ /// stream identifier other than zero.
158
158
  InvalidStreamId,
159
159
 
160
160
  /// A request or response is malformed.
@@ -0,0 +1,349 @@
1
+ //! Huffman decoding for HPACK (RFC 7541 §5.2).
2
+ //!
3
+ //! The decoder has a fast path which decodes 12 bits a time. The decoder
4
+ //! looks the next 12 bits up in `FAST_TABLE`, which maps directly to either
5
+ //! one or two symbols to decode. Since ASCII letters and digits have 5-7 bit
6
+ //! codes, one lookup usually decodes two symbols at once.
7
+ //!
8
+ //! Two situations fall off this fast path:
9
+ //!
10
+ //! - Codes longer than 12 bits: control characters and bytes >= 0x80
11
+ //! - The end of the input, when fewer than 12 bits remain.
12
+ //!
13
+ //! These are decoded by walking the generated `DECODE_TABLE` one input byte at a time.
14
+
15
+ use crate::hpack::huffman::table::{DECODE_TABLE, ENCODE_CODES, ENCODE_CODE_LENGTHS};
16
+ use crate::hpack::DecoderError;
17
+
18
+ use bytes::BytesMut;
19
+
20
+ // DECODE_TABLE (in the generated `table.rs`) is a series of 256-entry
21
+ // tables, walked one input byte at a time. A leaf entry (BRANCH bit clear)
22
+ // holds a decoded symbol and the number of bits its code used. A branch
23
+ // entry (BRANCH bit set) holds the index of the table for the next byte.
24
+ // No valid code leads back to table 0, so a branch to 0 means the input is
25
+ // not a valid code.
26
+ const BRANCH: u16 = 0x8000;
27
+ const TABLE_INDEX_MASK: u16 = 0x7f00;
28
+ const TABLE_WIDTH: usize = 256;
29
+
30
+ // Maps each possible 12-bit chunk of input to the symbol(s) it starts
31
+ // with. Entry layout (u32):
32
+ //
33
+ // bits 0..8 first decoded byte
34
+ // bits 8..16 second decoded byte (if any)
35
+ // bits 16..24 number of symbols decoded: 1, 2, or 0, where 0 means the
36
+ // code is longer than 12 bits and the slow path must run
37
+ // bits 24..32 how many of the 12 bits the decoded symbols used
38
+ const FAST_BITS: usize = 12;
39
+ const FAST_DECODE_TABLE: [u32; 1 << FAST_BITS] = build_fast_table();
40
+
41
+ const fn build_fast_table() -> [u32; 1 << FAST_BITS] {
42
+ let mut table = [0; 1 << FAST_BITS];
43
+
44
+ // First fill in every index that starts with one whole code
45
+ let mut a = 0;
46
+ while a < 256 {
47
+ let len1 = ENCODE_CODE_LENGTHS[a] as usize;
48
+ let code1 = ENCODE_CODES[a] as u64;
49
+ if len1 <= FAST_BITS {
50
+ let rem = FAST_BITS - len1;
51
+ let base = (code1 as usize) << rem;
52
+ let single = (1 << 16) | ((len1 as u32) << 24) | a as u32;
53
+ let mut i = 0;
54
+ while i < (1 << rem) {
55
+ table[base + i] = single;
56
+ i += 1;
57
+ }
58
+ }
59
+ a += 1;
60
+ }
61
+
62
+ // Overwrite the indices where a second whole code fit right after the first
63
+ let mut a = 0;
64
+ while a < 256 {
65
+ let len1 = ENCODE_CODE_LENGTHS[a] as usize;
66
+ let code1 = ENCODE_CODES[a] as u64;
67
+ // A second code needs at least 5 more bits (the shortest code)
68
+ if len1 + 5 <= FAST_BITS {
69
+ let rem = FAST_BITS - len1;
70
+ let mut b = 0;
71
+ while b < 256 {
72
+ let len2 = ENCODE_CODE_LENGTHS[b] as usize;
73
+ let code2 = ENCODE_CODES[b] as u64;
74
+ if len2 <= rem {
75
+ let rem2 = rem - len2;
76
+ let base = ((code1 as usize) << rem) | ((code2 as usize) << rem2);
77
+ let pair =
78
+ (2 << 16) | (((len1 + len2) as u32) << 24) | ((b as u32) << 8) | a as u32;
79
+ let mut i = 0;
80
+ while i < (1 << rem2) {
81
+ table[base + i] = pair;
82
+ i += 1;
83
+ }
84
+ }
85
+ b += 1;
86
+ }
87
+ }
88
+ a += 1;
89
+ }
90
+
91
+ table
92
+ }
93
+
94
+ // Decodes one code of any length by walking DECODE_TABLE one input byte at
95
+ // a time, and writes the symbol to `dst[*o]`. Used for codes longer than
96
+ // FAST_BITS bits and for the tail of the input.
97
+ //
98
+ // Inlining avoids a 35% performance regression on ASCII benchmarks.
99
+ #[inline(always)]
100
+ fn decode_code_slow(
101
+ acc: &mut u64,
102
+ bits: &mut usize,
103
+ dst: &mut [u8],
104
+ o: &mut usize,
105
+ ) -> Result<(), DecoderError> {
106
+ let mut table = 0;
107
+ loop {
108
+ let e = DECODE_TABLE[table * TABLE_WIDTH + (*acc >> 56) as usize];
109
+ if e & BRANCH == 0 {
110
+ let used = (e >> 8) as usize;
111
+ if used > *bits {
112
+ return Err(DecoderError::InvalidHuffmanCode);
113
+ }
114
+ dst[*o] = e as u8;
115
+ *o += 1;
116
+ *acc <<= used;
117
+ *bits -= used;
118
+ return Ok(());
119
+ }
120
+ if *bits < 8 {
121
+ return Err(DecoderError::InvalidHuffmanCode);
122
+ }
123
+ table = ((e & TABLE_INDEX_MASK) >> 8) as usize;
124
+ if table == 0 {
125
+ return Err(DecoderError::InvalidHuffmanCode);
126
+ }
127
+ *acc <<= 8;
128
+ *bits -= 8;
129
+ }
130
+ }
131
+
132
+ // Decodes a Huffman encoded string into the provided buffer.
133
+ pub fn decode(src: &[u8], buf: &mut BytesMut) -> Result<BytesMut, DecoderError> {
134
+ let len = src.len();
135
+ let base_len = buf.len();
136
+
137
+ // Reserve the worst case output size. Every code is at least 5 bits,
138
+ // so `len` input bytes can't decode to more than `len * 8 / 5` output
139
+ // bytes. One more byte covers the fast path always writing two bytes
140
+ // even when it decoded only one symbol.
141
+ buf.resize(base_len + len * 8 / 5 + 1, 0);
142
+ let dst = &mut buf[base_len..];
143
+ let mut o = 0;
144
+
145
+ let mut acc: u64 = 0;
146
+ let mut bits: usize = 0;
147
+ let mut pos: usize = 0;
148
+
149
+ 'outer: loop {
150
+ // Fill the bit buffer. While 8 or more input bytes remain, load
151
+ // the next 8 in one go and count as many whole bytes as fit under
152
+ // the bits already in the buffer (bringing it to 56-63 bits). The
153
+ // bytes that didn't fit still land in the low end of `acc`; the
154
+ // next refill just ORs the same values over them, so no harm done.
155
+ if pos + 8 <= len {
156
+ let word = u64::from_be_bytes(src[pos..pos + 8].try_into().unwrap());
157
+ acc |= word >> bits;
158
+ pos += (63 - bits) >> 3; // bytes now accounted for in `bits`
159
+ bits |= 56; // equals bits + 8 * (bytes added)
160
+ } else {
161
+ while bits <= 56 && pos < len {
162
+ acc |= (src[pos] as u64) << (56 - bits);
163
+ pos += 1;
164
+ bits += 8;
165
+ }
166
+ }
167
+
168
+ while bits >= FAST_BITS {
169
+ let entry = FAST_DECODE_TABLE[(acc >> (64 - FAST_BITS)) as usize];
170
+ let count = (entry >> 16) & 0xff;
171
+ if count == 0 {
172
+ // The next code is longer than 12 bits. Refill first if it
173
+ // might not be in the buffer yet (the longest code is 30
174
+ // bits), then decode it by walking DECODE_TABLE.
175
+ if bits < 30 && pos < len {
176
+ continue 'outer;
177
+ }
178
+ decode_code_slow(&mut acc, &mut bits, dst, &mut o)?;
179
+ continue;
180
+ }
181
+ let consumed = (entry >> 24) as usize;
182
+ dst[o] = entry as u8;
183
+ dst[o + 1] = (entry >> 8) as u8;
184
+ o += count as usize;
185
+ acc <<= consumed;
186
+ bits -= consumed;
187
+ }
188
+
189
+ if pos >= len {
190
+ break;
191
+ }
192
+ }
193
+
194
+ // Tail: the input is exhausted and fewer than 12 bits remain.
195
+ while bits > 0 {
196
+ // The encoder pads the last byte with up to 7 one-bits, which are
197
+ // valid only between symbols. Anything else must decode.
198
+ if bits < 8 && (acc >> (64 - bits)) == (1 << bits) - 1 {
199
+ break;
200
+ }
201
+ decode_code_slow(&mut acc, &mut bits, dst, &mut o)?;
202
+ }
203
+
204
+ buf.truncate(base_len + o);
205
+ Ok(buf.split())
206
+ }
207
+
208
+ #[cfg(test)]
209
+ mod test {
210
+ use super::*;
211
+
212
+ use bytes::BufMut;
213
+ use rand::rngs::StdRng;
214
+ use rand::{Rng, SeedableRng};
215
+
216
+ fn decode(src: &[u8]) -> Result<BytesMut, DecoderError> {
217
+ let mut buf = BytesMut::new();
218
+ super::decode(src, &mut buf)
219
+ }
220
+
221
+ // The simplest decoder we can write, used to double-check the real
222
+ // one: turn the input into a literal string of '0'/'1' characters and
223
+ // repeatedly strip off the first code that matches. No code is a
224
+ // prefix of another, so at most one can match. EOS (index 256) is left
225
+ // out on purpose: encoded EOS is an error per RFC 7541 §5.2.
226
+ fn reference_decode(src: &[u8]) -> Result<BytesMut, DecoderError> {
227
+ // Each symbol's code as a string of '0' and '1', e.g. "11111000".
228
+ let codes: Vec<String> = ENCODE_CODES
229
+ .iter()
230
+ .zip(ENCODE_CODE_LENGTHS.iter())
231
+ .map(|(&code, &len)| format!("{code:0len$b}", len = len as usize))
232
+ .collect();
233
+ let bits: String = src.iter().map(|byte| format!("{byte:08b}")).collect();
234
+
235
+ let mut decoded = BytesMut::new();
236
+ let mut remaining_bits: &str = &bits;
237
+ while let Some(sym) = (0..256).find(|&sym| remaining_bits.starts_with(&codes[sym])) {
238
+ decoded.put_u8(sym as u8);
239
+ remaining_bits = &remaining_bits[codes[sym].len()..];
240
+ }
241
+ // We expect anything that cannot be matched to be padding. Padding is
242
+ // fewer than 8 bits, and all ones.
243
+ if remaining_bits.len() >= 8 || remaining_bits.chars().any(|bit| bit == '0') {
244
+ return Err(DecoderError::InvalidHuffmanCode);
245
+ }
246
+ Ok(decoded)
247
+ }
248
+
249
+ #[test]
250
+ fn decode_single_byte() {
251
+ assert_eq!("o", decode(&[0b00111111]).unwrap());
252
+ assert_eq!("0", decode(&[7]).unwrap());
253
+ assert_eq!("A", decode(&[(0x21 << 2) + 3]).unwrap());
254
+ }
255
+
256
+ #[test]
257
+ fn single_char_multi_byte() {
258
+ assert_eq!("#", decode(&[255, 160 + 15]).unwrap());
259
+ assert_eq!("$", decode(&[255, 200 + 7]).unwrap());
260
+ assert_eq!("\x0a", decode(&[255, 255, 255, 240 + 3]).unwrap());
261
+ }
262
+
263
+ #[test]
264
+ fn multi_char() {
265
+ assert_eq!("!0", decode(&[254, 1]).unwrap());
266
+ assert_eq!(" !", decode(&[0b01010011, 0b11111000]).unwrap());
267
+ }
268
+
269
+ // Random (mostly invalid) byte strings must produce identical results to reference impl
270
+ #[test]
271
+ fn matches_reference_on_arbitrary_bytes() {
272
+ let mut rng = StdRng::seed_from_u64(0xdeadbeefcafe);
273
+
274
+ for _ in 0..10_000 {
275
+ let len = rng.gen_range(0..40);
276
+ let src: Vec<u8> = (0..len).map(|_| rng.gen()).collect();
277
+ assert_eq!(reference_decode(&src), decode(&src), "src={:?}", src);
278
+ }
279
+
280
+ // Bias toward high bytes to exercise long codes and EOS prefixes.
281
+ for _ in 0..10_000 {
282
+ let len = rng.gen_range(0..40);
283
+ let src: Vec<u8> = (0..len).map(|_| rng.gen::<u8>() | 0xe0).collect();
284
+ assert_eq!(reference_decode(&src), decode(&src), "src={:?}", src);
285
+ }
286
+ }
287
+
288
+ #[test]
289
+ fn rejects_eos_and_invalid_padding() {
290
+ assert_eq!(decode(&[0xff]), Err(DecoderError::InvalidHuffmanCode));
291
+ assert_eq!(
292
+ decode(&[0xff, 0xff, 0xff, 0xff]),
293
+ Err(DecoderError::InvalidHuffmanCode)
294
+ );
295
+ assert_eq!(decode(&[0]), Err(DecoderError::InvalidHuffmanCode));
296
+ }
297
+ }
298
+
299
+ /*
300
+ // uncomment to run benchmarks
301
+ #[cfg(test)]
302
+ mod bench {
303
+ extern crate test;
304
+
305
+ use self::test::{black_box, Bencher};
306
+ use super::*;
307
+
308
+ use crate::hpack::huffman::encode;
309
+
310
+ fn decode_input(b: &mut Bencher, input: &[u8]) {
311
+ let mut encoded = BytesMut::new();
312
+ encode(input, &mut encoded);
313
+
314
+ let mut scratch = BytesMut::with_capacity(input.len() * 2);
315
+ b.bytes = encoded.len() as u64;
316
+ b.iter(|| {
317
+ let decoded = decode(black_box(encoded.as_ref()), &mut scratch).unwrap();
318
+ black_box(decoded);
319
+ });
320
+ }
321
+
322
+ #[bench]
323
+ fn decode_short_ascii(b: &mut Bencher) {
324
+ decode_input(b, b"www.example.com");
325
+ }
326
+
327
+ #[bench]
328
+ fn decode_header_value(b: &mut Bencher) {
329
+ decode_input(
330
+ b,
331
+ b"text/html,application/xhtml+xml,application/xml;q=0.9;q=0.8",
332
+ );
333
+ }
334
+
335
+ #[bench]
336
+ fn decode_long_ascii(b: &mut Bencher) {
337
+ decode_input(
338
+ b,
339
+ b"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0",
340
+ );
341
+ }
342
+
343
+ #[bench]
344
+ fn decode_all_octets(b: &mut Bencher) {
345
+ let input: Vec<_> = (0..=u8::MAX).collect();
346
+ decode_input(b, &input);
347
+ }
348
+ }
349
+ */