From a9b5422d57ad0c53c24a37e8f07ecb29bb338b89 Mon Sep 17 00:00:00 2001 From: Caio Date: Thu, 15 Aug 2024 16:09:40 -0300 Subject: [PATCH] Improve HTTP2 performance --- .scripts/internal-tests-0.sh | 17 +- Cargo.lock | 1801 +---------------- README.md | 1 - wtx-docs/src/http-server-framework/README.md | 2 + wtx-docs/src/http2/README.md | 19 +- wtx-instances/Cargo.toml | 34 +- .../database-client-postgres-tokio-rustls.rs | 5 +- .../examples/http-client-framework.rs | 22 + .../examples/http-server-framework.rs | 6 +- .../examples/http2-client-tokio-rustls.rs | 30 - .../examples/http2-server-tokio-rustls.rs | 38 - .../web-socket-client-raw-tokio-rustls.rs | 10 +- .../web-socket-server-raw-tokio-rustls.rs | 6 +- wtx-instances/fulfillments/h2spec-server.rs | 4 +- wtx-ui/Cargo.toml | 4 +- wtx-ui/src/schema_manager.rs | 4 +- wtx/Cargo.toml | 55 +- .../data_format/graph_ql/graph_ql_request.rs | 11 +- .../data_format/json/json_request.rs | 23 - .../data_format/json/json_response.rs | 47 - .../data_format/xml/xml_request.rs | 22 - .../data_format/xml/xml_response.rs | 47 - .../data_format/yaml/yaml_request.rs | 22 - .../data_format/yaml/yaml_response.rs | 47 - wtx/src/client_api_framework/dnsn.rs | 12 - .../client_api_framework/dnsn/miniserde.rs | 31 - .../client_api_framework/dnsn/serde_xml_rs.rs | 26 - .../client_api_framework/dnsn/serde_yaml.rs | 23 - wtx/src/client_api_framework/dnsn/tests.rs | 2 - .../misc/request_counter.rs | 2 +- wtx/src/database/client/postgres/executor.rs | 4 +- .../client/postgres/integration_tests.rs | 5 +- wtx/src/database/from_records.rs | 2 +- wtx/src/database/schema_manager/misc.rs | 2 +- wtx/src/error.rs | 102 +- wtx/src/http/client_framework.rs | 102 +- .../client_framework_builder.rs | 2 +- .../http_client_framework_error.rs | 6 + wtx/src/http/client_framework/req_builder.rs | 8 +- wtx/src/http/http_error.rs | 2 + wtx/src/http/low_level_server/tokio_http2.rs | 94 +- wtx/src/http/server_framework.rs | 68 +- wtx/src/http/server_framework/middlewares.rs | 57 +- wtx/src/http/server_framework/path_fun.rs | 23 +- .../http/server_framework/path_management.rs | 27 +- wtx/src/http/server_framework/wrappers.rs | 45 +- wtx/src/http2.rs | 220 +- wtx/src/http2/client_stream.rs | 131 +- wtx/src/http2/frame_reader.rs | 188 ++ wtx/src/http2/headers_frame.rs | 7 +- wtx/src/http2/hpack_decoder.rs | 42 +- wtx/src/http2/hpack_encoder.rs | 4 +- wtx/src/http2/http2_buffer.rs | 25 +- wtx/src/http2/http2_data.rs | 123 +- wtx/src/http2/http2_error.rs | 6 +- wtx/src/http2/huffman.rs | 12 +- wtx/src/http2/macros.rs | 44 +- wtx/src/http2/misc.rs | 327 +-- wtx/src/http2/ping_frame.rs | 9 +- wtx/src/http2/process_receipt_frame_ty.rs | 190 +- wtx/src/http2/reset_stream_frame.rs | 4 +- wtx/src/http2/send_msg.rs | 147 +- wtx/src/http2/server_stream.rs | 114 +- wtx/src/http2/stream_receiver.rs | 12 +- wtx/src/http2/tests.rs | 1 - wtx/src/http2/tests/connections.rs | 68 +- wtx/src/http2/window.rs | 17 +- wtx/src/lib.rs | 2 +- wtx/src/macros.rs | 2 +- wtx/src/misc.rs | 42 +- wtx/src/misc/array_chunks.rs | 2 +- wtx/src/misc/fx_hasher.rs | 46 - wtx/src/misc/generic_time.rs | 28 +- wtx/src/misc/lease.rs | 20 - wtx/src/misc/lock.rs | 52 - wtx/src/misc/mem_transfer.rs | 37 +- wtx/src/misc/poll_once.rs | 33 - wtx/src/misc/queue.rs | 2 +- wtx/src/misc/queue_utils.rs | 4 +- wtx/src/misc/stream.rs | 645 +----- wtx/src/misc/stream/bytes_stream.rs | 60 + wtx/src/misc/stream/std.rs | 26 + wtx/src/misc/stream/stream_reader.rs | 63 + wtx/src/misc/stream/stream_with_tls.rs | 24 + wtx/src/misc/stream/stream_writer.rs | 39 + wtx/src/misc/stream/tokio.rs | 77 + wtx/src/misc/stream/tokio_rustls.rs | 114 ++ wtx/src/misc/tokio_rustls.rs | 149 +- wtx/src/misc/vector.rs | 11 - wtx/src/pool/resource_manager.rs | 18 +- wtx/src/pool/simple_pool.rs | 4 +- wtx/src/web_socket/handshake.rs | 2 +- wtx/src/web_socket/handshake/tests.rs | 8 +- 93 files changed, 2088 insertions(+), 4035 deletions(-) create mode 100644 wtx-instances/examples/http-client-framework.rs delete mode 100644 wtx-instances/examples/http2-client-tokio-rustls.rs delete mode 100644 wtx-instances/examples/http2-server-tokio-rustls.rs delete mode 100644 wtx/src/client_api_framework/dnsn/miniserde.rs delete mode 100644 wtx/src/client_api_framework/dnsn/serde_xml_rs.rs delete mode 100644 wtx/src/client_api_framework/dnsn/serde_yaml.rs create mode 100644 wtx/src/http/client_framework/http_client_framework_error.rs create mode 100644 wtx/src/http2/frame_reader.rs delete mode 100644 wtx/src/misc/fx_hasher.rs delete mode 100644 wtx/src/misc/poll_once.rs create mode 100644 wtx/src/misc/stream/bytes_stream.rs create mode 100644 wtx/src/misc/stream/std.rs create mode 100644 wtx/src/misc/stream/stream_reader.rs create mode 100644 wtx/src/misc/stream/stream_with_tls.rs create mode 100644 wtx/src/misc/stream/stream_writer.rs create mode 100644 wtx/src/misc/stream/tokio.rs create mode 100644 wtx/src/misc/stream/tokio_rustls.rs diff --git a/.scripts/internal-tests-0.sh b/.scripts/internal-tests-0.sh index 413c3f62..7b429fde 100755 --- a/.scripts/internal-tests-0.sh +++ b/.scripts/internal-tests-0.sh @@ -12,7 +12,6 @@ cargo miri test -p wtx $rt check-generic wtx $rt test-with-features wtx ahash $rt test-with-features wtx arbitrary -$rt test-with-features wtx async-std $rt test-with-features wtx atoi $rt test-with-features wtx base64 $rt test-with-features wtx borsh @@ -22,14 +21,8 @@ $rt test-with-features wtx client-api-framework $rt test-with-features wtx crypto-common $rt test-with-features wtx database $rt test-with-features wtx digest -$rt test-with-features wtx embassy-net,_hack -$rt test-with-features wtx embassy-sync -$rt test-with-features wtx embassy-time -$rt test-with-features wtx embedded-tls $rt test-with-features wtx fastrand $rt test-with-features wtx flate2 -$rt test-with-features wtx futures-lite -$rt test-with-features wtx glommio $rt test-with-features wtx hashbrown $rt test-with-features wtx hmac $rt test-with-features wtx http2 @@ -37,8 +30,6 @@ $rt test-with-features wtx http-client-framework $rt test-with-features wtx http-server-framework $rt test-with-features wtx httparse $rt test-with-features wtx memchr -$rt test-with-features wtx miniserde -$rt test-with-features wtx parking_lot $rt test-with-features wtx pool $rt test-with-features wtx postgres $rt test-with-features wtx proptest @@ -47,20 +38,14 @@ $rt test-with-features wtx rand $rt test-with-features wtx ring $rt test-with-features wtx rkyv,_hack $rt test-with-features wtx rust_decimal -$rt test-with-features wtx rustls-pemfile -$rt test-with-features wtx rustls-pki-types $rt test-with-features wtx schema-manager $rt test-with-features wtx schema-manager-dev $rt test-with-features wtx serde $rt test-with-features wtx serde_json -$rt test-with-features wtx serde_yaml -$rt test-with-features wtx serde-xml-rs $rt test-with-features wtx sha1 $rt test-with-features wtx sha2 $rt test-with-features wtx simd-json $rt test-with-features wtx simdutf8 -$rt test-with-features wtx smol -$rt test-with-features wtx smoltcp,_hack $rt test-with-features wtx std $rt test-with-features wtx test-strategy $rt test-with-features wtx tokio @@ -75,7 +60,7 @@ $rt check-with-features wtx _bench $rt check-with-features wtx _hack $rt check-with-features wtx _integration-tests $rt check-with-features wtx _tokio-rustls-client -$rt check-with-features wtx _tracing-subscriber +$rt check-with-features wtx _tracing-tree $rt test-with-features wtx _proptest # WTX Macros diff --git a/Cargo.lock b/Cargo.lock index f3274400..334f9544 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,41 +17,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" -[[package]] -name = "aead" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" -dependencies = [ - "crypto-common", - "generic-array 0.14.7", -] - -[[package]] -name = "aes" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", -] - -[[package]] -name = "aes-gcm" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" -dependencies = [ - "aead", - "aes", - "cipher", - "ctr", - "ghash", - "subtle", -] - [[package]] name = "ahash" version = "0.7.8" @@ -126,229 +91,6 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" -[[package]] -name = "as-slice" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45403b49e3954a4b8428a0ac21a4b7afadccf92bfd96273f1a58cd4812496ae0" -dependencies = [ - "generic-array 0.12.4", - "generic-array 0.13.3", - "generic-array 0.14.7", - "stable_deref_trait", -] - -[[package]] -name = "as-slice" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "516b6b4f0e40d50dcda9365d53964ec74560ad4284da2e7fc97122cd83174516" -dependencies = [ - "stable_deref_trait", -] - -[[package]] -name = "async-channel" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" -dependencies = [ - "concurrent-queue 2.5.0", - "event-listener 2.5.3", - "futures-core", -] - -[[package]] -name = "async-channel" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" -dependencies = [ - "concurrent-queue 2.5.0", - "event-listener-strategy", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-executor" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7ebdfa2ebdab6b1760375fa7d6f382b9f486eac35fc994625a00e89280bdbb7" -dependencies = [ - "async-task", - "concurrent-queue 2.5.0", - "fastrand 2.1.0", - "futures-lite 2.3.0", - "slab", -] - -[[package]] -name = "async-fs" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebcd09b382f40fcd159c2d695175b2ae620ffa5f3bd6f664131efff4e8b9e04a" -dependencies = [ - "async-lock 3.4.0", - "blocking", - "futures-lite 2.3.0", -] - -[[package]] -name = "async-global-executor" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" -dependencies = [ - "async-channel 2.3.1", - "async-executor", - "async-io 2.3.3", - "async-lock 3.4.0", - "blocking", - "futures-lite 2.3.0", - "once_cell", -] - -[[package]] -name = "async-io" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" -dependencies = [ - "async-lock 2.8.0", - "autocfg", - "cfg-if", - "concurrent-queue 2.5.0", - "futures-lite 1.13.0", - "log", - "parking", - "polling 2.8.0", - "rustix 0.37.27", - "slab", - "socket2 0.4.10", - "waker-fn", -] - -[[package]] -name = "async-io" -version = "2.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6baa8f0178795da0e71bc42c9e5d13261aac7ee549853162e66a241ba17964" -dependencies = [ - "async-lock 3.4.0", - "cfg-if", - "concurrent-queue 2.5.0", - "futures-io", - "futures-lite 2.3.0", - "parking", - "polling 3.7.2", - "rustix 0.38.34", - "slab", - "tracing", - "windows-sys 0.52.0", -] - -[[package]] -name = "async-lock" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" -dependencies = [ - "event-listener 2.5.3", -] - -[[package]] -name = "async-lock" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" -dependencies = [ - "event-listener 5.3.1", - "event-listener-strategy", - "pin-project-lite", -] - -[[package]] -name = "async-net" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b948000fad4873c1c9339d60f2623323a0cfd3816e5181033c6a5cb68b2accf7" -dependencies = [ - "async-io 2.3.3", - "blocking", - "futures-lite 2.3.0", -] - -[[package]] -name = "async-process" -version = "2.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7eda79bbd84e29c2b308d1dc099d7de8dcc7035e48f4bf5dc4a531a44ff5e2a" -dependencies = [ - "async-channel 2.3.1", - "async-io 2.3.3", - "async-lock 3.4.0", - "async-signal", - "async-task", - "blocking", - "cfg-if", - "event-listener 5.3.1", - "futures-lite 2.3.0", - "rustix 0.38.34", - "tracing", - "windows-sys 0.52.0", -] - -[[package]] -name = "async-signal" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfb3634b73397aa844481f814fad23bbf07fdb0eabec10f2eb95e58944b1ec32" -dependencies = [ - "async-io 2.3.3", - "async-lock 3.4.0", - "atomic-waker", - "cfg-if", - "futures-core", - "futures-io", - "rustix 0.38.34", - "signal-hook-registry", - "slab", - "windows-sys 0.52.0", -] - -[[package]] -name = "async-std" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" -dependencies = [ - "async-channel 1.9.0", - "async-global-executor", - "async-io 1.13.0", - "async-lock 2.8.0", - "crossbeam-utils", - "futures-channel", - "futures-core", - "futures-io", - "futures-lite 1.13.0", - "gloo-timers", - "kv-log-macro", - "log", - "memchr", - "once_cell", - "pin-project-lite", - "pin-utils", - "slab", - "wasm-bindgen-futures", -] - -[[package]] -name = "async-task" -version = "4.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" - [[package]] name = "atoi" version = "2.0.0" @@ -358,33 +100,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "atomic-polyfill" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" -dependencies = [ - "critical-section", -] - -[[package]] -name = "atomic-pool" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58c5fc22e05ec2884db458bf307dc7b278c9428888d2b6e6fad9c0ae7804f5f6" -dependencies = [ - "as-slice 0.1.5", - "as-slice 0.2.1", - "atomic-polyfill", - "stable_deref_trait", -] - -[[package]] -name = "atomic-waker" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" - [[package]] name = "autocfg" version = "1.3.0" @@ -406,12 +121,6 @@ dependencies = [ "rustc-demangle", ] -[[package]] -name = "base16ct" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" - [[package]] name = "base64" version = "0.22.1" @@ -434,24 +143,12 @@ dependencies = [ "smallvec", ] -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - [[package]] name = "bitflags" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" -[[package]] -name = "bitmaps" -version = "3.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d084b0137aaa901caf9f1e8b21daa6aa24d41cd806e111335541eff9683bd6" - [[package]] name = "bitvec" version = "1.0.1" @@ -470,20 +167,7 @@ version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "generic-array 0.14.7", -] - -[[package]] -name = "blocking" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" -dependencies = [ - "async-channel 2.3.1", - "async-task", - "futures-io", - "futures-lite 2.3.0", - "piper", + "generic-array", ] [[package]] @@ -510,12 +194,6 @@ dependencies = [ "syn_derive", ] -[[package]] -name = "buddy-alloc" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3240a4cb09cf0da6a51641bd40ce90e96ea6065e3a1adc46434029254bcc2d09" - [[package]] name = "bumpalo" version = "3.16.0" @@ -555,17 +233,11 @@ version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" -[[package]] -name = "cache-padded" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "981520c98f422fcc584dc1a95c334e6953900b9106bc47a9839b81790009eb21" - [[package]] name = "cc" -version = "1.1.7" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26a5c3fd7bfa1ce3897a3a3501d362b2d87b7f2583ebcb4a949ec25911025cbc" +checksum = "504bdec147f2cc13c8b57ed9401fd8a147cc66b67ad5cb241394244f2c947549" dependencies = [ "jobserver", "libc", @@ -592,17 +264,7 @@ dependencies = [ "android-tzdata", "iana-time-zone", "num-traits", - "windows-targets 0.52.6", -] - -[[package]] -name = "cipher" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" -dependencies = [ - "crypto-common", - "inout", + "windows-targets", ] [[package]] @@ -617,9 +279,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.13" +version = "4.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fbb260a053428790f3de475e304ff84cdbc4face759ea7a3e64c1edd938a7fc" +checksum = "11d8838454fda655dafd3accb2b6e2bea645b9e4078abe84a22ceb947235c5cc" dependencies = [ "clap_builder", "clap_derive", @@ -627,9 +289,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.13" +version = "4.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64b17d7ea74e9f833c7dbf2cbe4fb12ff26783eda4782a8975b72f895c9b4d99" +checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6" dependencies = [ "anstyle", "clap_lex", @@ -653,24 +315,6 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" -[[package]] -name = "concurrent-queue" -version = "1.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af4780a44ab5696ea9e28294517f1fffb421a83a25af521333c838635509db9c" -dependencies = [ - "cache-padded", -] - -[[package]] -name = "concurrent-queue" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" -dependencies = [ - "crossbeam-utils", -] - [[package]] name = "const-oid" version = "0.9.6" @@ -701,99 +345,16 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "critical-section" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216" - -[[package]] -name = "crossbeam" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8" -dependencies = [ - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-epoch", - "crossbeam-queue", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-channel" -version = "0.5.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-queue" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" - -[[package]] -name = "crypto-bigint" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" -dependencies = [ - "generic-array 0.14.7", - "rand_core", - "subtle", - "zeroize", -] - [[package]] name = "crypto-common" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "generic-array 0.14.7", + "generic-array", "typenum", ] -[[package]] -name = "ctr" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" -dependencies = [ - "cipher", -] - [[package]] name = "der" version = "0.7.9" @@ -826,15 +387,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "document-features" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6969eaabd2421f8a2775cfd2471a2b634372b4a25d41e3bd647b79912850a0" -dependencies = [ - "litrs", -] - [[package]] name = "dotenv" version = "0.15.0" @@ -842,299 +394,35 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" [[package]] -name = "elliptic-curve" -version = "0.13.8" +name = "equivalent" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" -dependencies = [ - "base16ct", - "crypto-bigint", - "digest", - "ff", - "generic-array 0.14.7", - "group", - "hkdf", - "rand_core", - "sec1", - "subtle", - "zeroize", -] +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] -name = "embassy-net" -version = "0.4.0" +name = "fastrand" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cf91dd36dfd623de32242af711fd294d41159f02130052fc93c5c5ba93febe" -dependencies = [ - "as-slice 0.2.1", - "atomic-pool", - "document-features", - "embassy-net-driver", - "embassy-sync 0.5.0", - "embassy-time", - "embedded-io-async", - "embedded-nal-async", - "futures", - "generic-array 0.14.7", - "heapless 0.8.0", - "managed", - "smoltcp", - "stable_deref_trait", -] +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" [[package]] -name = "embassy-net-driver" -version = "0.2.0" +name = "flate2" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524eb3c489760508f71360112bca70f6e53173e6fe48fc5f0efd0f5ab217751d" +checksum = "7f211bbe8e69bbd0cfdea405084f128ae8b4aaa6b0b522fc8f2b009084797920" +dependencies = [ + "crc32fast", + "libz-rs-sys", + "miniz_oxide", +] [[package]] -name = "embassy-sync" -version = "0.5.0" +name = "float-cmp" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd938f25c0798db4280fcd8026bf4c2f48789aebf8f77b6e5cf8a7693ba114ec" +checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" dependencies = [ - "cfg-if", - "critical-section", - "embedded-io-async", - "futures-util", - "heapless 0.8.0", -] - -[[package]] -name = "embassy-sync" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3e0c49ff02ebe324faf3a8653ba91582e2d0a7fdef5bc88f449d5aa1bfcc05c" -dependencies = [ - "cfg-if", - "critical-section", - "embedded-io-async", - "futures-util", - "heapless 0.8.0", -] - -[[package]] -name = "embassy-time" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "158080d48f824fad101d7b2fae2d83ac39e3f7a6fa01811034f7ab8ffc6e7309" -dependencies = [ - "cfg-if", - "critical-section", - "document-features", - "embassy-time-driver", - "embassy-time-queue-driver", - "embedded-hal 0.2.7", - "embedded-hal 1.0.0", - "embedded-hal-async", - "futures-util", - "heapless 0.8.0", -] - -[[package]] -name = "embassy-time-driver" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e0c214077aaa9206958b16411c157961fb7990d4ea628120a78d1a5a28aed24" -dependencies = [ - "document-features", -] - -[[package]] -name = "embassy-time-queue-driver" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1177859559ebf42cd24ae7ba8fe6ee707489b01d0bf471f8827b7b12dcb0bc0" - -[[package]] -name = "embedded-hal" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" -dependencies = [ - "nb 0.1.3", - "void", -] - -[[package]] -name = "embedded-hal" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" - -[[package]] -name = "embedded-hal-async" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4c685bbef7fe13c3c6dd4da26841ed3980ef33e841cddfa15ce8a8fb3f1884" -dependencies = [ - "embedded-hal 1.0.0", -] - -[[package]] -name = "embedded-io" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" - -[[package]] -name = "embedded-io-async" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ff09972d4073aa8c299395be75161d582e7629cd663171d62af73c8d50dba3f" -dependencies = [ - "embedded-io", -] - -[[package]] -name = "embedded-nal" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a943fad5ed3d3f8a00f1e80f6bba371f1e7f0df28ec38477535eb318dc19cc" -dependencies = [ - "nb 1.1.0", - "no-std-net", -] - -[[package]] -name = "embedded-nal-async" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72229137a4fc12d239b0b7f50f04b30790678da6d782a0f3f1909bf57ec4b759" -dependencies = [ - "embedded-io-async", - "embedded-nal", - "no-std-net", -] - -[[package]] -name = "embedded-tls" -version = "0.16.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f44f7883b34eaeb4288d79dbb01eba6edd190b1c55665ad115369f8d0abf553e" -dependencies = [ - "aes-gcm", - "atomic-polyfill", - "digest", - "embedded-io", - "embedded-io-async", - "generic-array 0.14.7", - "heapless 0.6.1", - "heapless 0.7.17", - "hkdf", - "hmac", - "p256", - "rand_core", - "sha2", - "typenum", -] - -[[package]] -name = "enclose" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef4f6f904480430009ad8f22edc9573e26e4f137365f014d7ea998d5341639a" - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "errno" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "event-listener" -version = "2.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" - -[[package]] -name = "event-listener" -version = "5.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" -dependencies = [ - "concurrent-queue 2.5.0", - "parking", - "pin-project-lite", -] - -[[package]] -name = "event-listener-strategy" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" -dependencies = [ - "event-listener 5.3.1", - "pin-project-lite", -] - -[[package]] -name = "fastrand" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] - -[[package]] -name = "fastrand" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" - -[[package]] -name = "ff" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" -dependencies = [ - "rand_core", - "subtle", -] - -[[package]] -name = "flate2" -version = "1.0.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f211bbe8e69bbd0cfdea405084f128ae8b4aaa6b0b522fc8f2b009084797920" -dependencies = [ - "crc32fast", - "libz-rs-sys", - "miniz_oxide", -] - -[[package]] -name = "float-cmp" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" -dependencies = [ - "num-traits", -] - -[[package]] -name = "flume" -version = "0.10.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577" -dependencies = [ - "futures-core", - "futures-sink", - "nanorand", - "pin-project", - "spin", + "num-traits", ] [[package]] @@ -1143,125 +431,6 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" -[[package]] -name = "futures" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" - -[[package]] -name = "futures-io" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" - -[[package]] -name = "futures-lite" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" -dependencies = [ - "fastrand 1.9.0", - "futures-core", - "futures-io", - "memchr", - "parking", - "pin-project-lite", - "waker-fn", -] - -[[package]] -name = "futures-lite" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" -dependencies = [ - "fastrand 2.1.0", - "futures-core", - "futures-io", - "parking", - "pin-project-lite", -] - -[[package]] -name = "futures-macro" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.72", -] - -[[package]] -name = "futures-sink" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" - -[[package]] -name = "futures-task" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" - -[[package]] -name = "futures-util" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" -dependencies = [ - "futures-core", - "futures-macro", - "futures-sink", - "futures-task", - "pin-project-lite", - "pin-utils", -] - -[[package]] -name = "generic-array" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" -dependencies = [ - "typenum", -] - -[[package]] -name = "generic-array" -version = "0.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f797e67af32588215eaaab8327027ee8e71b9dd0b2b26996aedf20c030fce309" -dependencies = [ - "typenum", -] - [[package]] name = "generic-array" version = "0.14.7" @@ -1270,7 +439,6 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", - "zeroize", ] [[package]] @@ -1286,16 +454,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "ghash" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" -dependencies = [ - "opaque-debug", - "polyval", -] - [[package]] name = "gimli" version = "0.29.0" @@ -1308,64 +466,6 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" -[[package]] -name = "glommio" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1f8bc1fce949d18098dc0a4e861314e40351a0144ebf61e59bdb5254a2273b2" -dependencies = [ - "ahash 0.7.8", - "backtrace", - "bitflags 2.6.0", - "bitmaps", - "buddy-alloc", - "cc", - "concurrent-queue 1.2.4", - "crossbeam", - "enclose", - "flume", - "futures-lite 1.13.0", - "intrusive-collections", - "lazy_static", - "libc", - "lockfree", - "log", - "nix", - "pin-project-lite", - "rlimit", - "scoped-tls", - "scopeguard", - "signal-hook", - "sketches-ddsketch", - "smallvec", - "socket2 0.4.10", - "tracing", - "typenum", -] - -[[package]] -name = "gloo-timers" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" -dependencies = [ - "futures-channel", - "futures-core", - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "group" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" -dependencies = [ - "ff", - "rand_core", - "subtle", -] - [[package]] name = "halfbrown" version = "0.2.5" @@ -1376,33 +476,6 @@ dependencies = [ "serde", ] -[[package]] -name = "hash32" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4041af86e63ac4298ce40e5cca669066e75b6f1aa3390fe2561ffa5e1d9f4cc" -dependencies = [ - "byteorder", -] - -[[package]] -name = "hash32" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" -dependencies = [ - "byteorder", -] - -[[package]] -name = "hash32" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" -dependencies = [ - "byteorder", -] - [[package]] name = "hashbrown" version = "0.12.3" @@ -1422,41 +495,6 @@ dependencies = [ "allocator-api2", ] -[[package]] -name = "heapless" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634bd4d29cbf24424d0a4bfcbf80c6960129dc24424752a7d1d1390607023422" -dependencies = [ - "as-slice 0.1.5", - "generic-array 0.14.7", - "hash32 0.1.1", - "stable_deref_trait", -] - -[[package]] -name = "heapless" -version = "0.7.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" -dependencies = [ - "atomic-polyfill", - "hash32 0.2.1", - "rustc_version", - "spin", - "stable_deref_trait", -] - -[[package]] -name = "heapless" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" -dependencies = [ - "hash32 0.3.1", - "stable_deref_trait", -] - [[package]] name = "heck" version = "0.5.0" @@ -1469,27 +507,12 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" -[[package]] -name = "hermit-abi" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" - [[package]] name = "hex" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -[[package]] -name = "hkdf" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" -dependencies = [ - "hmac", -] - [[package]] name = "hmac" version = "0.12.1" @@ -1538,44 +561,6 @@ dependencies = [ "hashbrown 0.14.5", ] -[[package]] -name = "inout" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" -dependencies = [ - "generic-array 0.14.7", -] - -[[package]] -name = "instant" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "intrusive-collections" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b694dc9f70c3bda874626d2aed13b780f137aab435f4e9814121955cf706122e" -dependencies = [ - "memoffset", -] - -[[package]] -name = "io-lifetimes" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" -dependencies = [ - "hermit-abi 0.3.9", - "libc", - "windows-sys 0.48.0", -] - [[package]] name = "itoa" version = "1.0.11" @@ -1600,15 +585,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "kv-log-macro" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" -dependencies = [ - "log", -] - [[package]] name = "lazy_static" version = "1.5.0" @@ -1711,57 +687,11 @@ dependencies = [ "zlib-rs", ] -[[package]] -name = "linux-raw-sys" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" - -[[package]] -name = "linux-raw-sys" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" - -[[package]] -name = "litrs" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" - -[[package]] -name = "lock_api" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "lockfree" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74ee94b5ad113c7cb98c5a040f783d0952ee4fe100993881d1673c2cb002dd23" -dependencies = [ - "owned-alloc", -] - [[package]] name = "log" version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" -dependencies = [ - "value-bag", -] - -[[package]] -name = "managed" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d" [[package]] name = "matchers" @@ -1778,37 +708,6 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" -[[package]] -name = "memoffset" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" -dependencies = [ - "autocfg", -] - -[[package]] -name = "mini-internal" -version = "0.1.39" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28c501b91dabb672c4b303fb6ea259022ab21ed8d06a457ac21b70e479fb367" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.72", -] - -[[package]] -name = "miniserde" -version = "0.1.39" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd044c3b41ba1d92e3dbeef687ecfe5d1dcbd8b4fa1d33610f5ce5546ad6aac1" -dependencies = [ - "itoa", - "mini-internal", - "ryu", -] - [[package]] name = "miniz_oxide" version = "0.7.4" @@ -1824,235 +723,62 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4" dependencies = [ - "hermit-abi 0.3.9", + "hermit-abi", "libc", - "wasi", - "windows-sys 0.52.0", -] - -[[package]] -name = "nanorand" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" -dependencies = [ - "getrandom", -] - -[[package]] -name = "nb" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" -dependencies = [ - "nb 1.1.0", -] - -[[package]] -name = "nb" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" - -[[package]] -name = "nix" -version = "0.27.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" -dependencies = [ - "bitflags 2.6.0", - "cfg-if", - "libc", - "memoffset", -] - -[[package]] -name = "no-std-net" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43794a0ace135be66a25d3ae77d41b91615fb68ae937f904090203e81f755b65" - -[[package]] -name = "nu-ansi-term" -version = "0.50.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", - "libm", -] - -[[package]] -name = "object" -version = "0.36.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f203fa8daa7bb185f760ae12bd8e097f63d17041dcdcaf675ac54cdf863170e" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - -[[package]] -name = "opaque-debug" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" - -[[package]] -name = "owned-alloc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30fceb411f9a12ff9222c5f824026be368ff15dc2f13468d850c7d3f502205d6" - -[[package]] -name = "p256" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" -dependencies = [ - "elliptic-curve", - "primeorder", -] - -[[package]] -name = "parking" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" - -[[package]] -name = "parking_lot" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets 0.52.6", -] - -[[package]] -name = "pem" -version = "3.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae" -dependencies = [ - "base64", - "serde", -] - -[[package]] -name = "pin-project" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.72", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + "wasi", + "windows-sys 0.52.0", +] [[package]] -name = "piper" -version = "0.2.3" +name = "nu-ansi-term" +version = "0.50.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae1d5c74c9876f070d3e8fd503d748c7d974c3e48da8f41350fa5222ef9b4391" +checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399" dependencies = [ - "atomic-waker", - "fastrand 2.1.0", - "futures-io", + "windows-sys 0.52.0", ] [[package]] -name = "polling" -version = "2.8.0" +name = "num-traits" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", - "bitflags 1.3.2", - "cfg-if", - "concurrent-queue 2.5.0", - "libc", - "log", - "pin-project-lite", - "windows-sys 0.48.0", + "libm", ] [[package]] -name = "polling" -version = "3.7.2" +name = "object" +version = "0.36.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3ed00ed3fbf728b5816498ecd316d1716eecaced9c0c8d2c5a6740ca214985b" +checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" dependencies = [ - "cfg-if", - "concurrent-queue 2.5.0", - "hermit-abi 0.4.0", - "pin-project-lite", - "rustix 0.38.34", - "tracing", - "windows-sys 0.52.0", + "memchr", ] [[package]] -name = "polyval" -version = "0.6.2" +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "pem" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae" dependencies = [ - "cfg-if", - "cpufeatures", - "opaque-debug", - "universal-hash", + "base64", + "serde", ] +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + [[package]] name = "ppv-lite86" version = "0.2.20" @@ -2062,15 +788,6 @@ dependencies = [ "zerocopy", ] -[[package]] -name = "primeorder" -version = "0.13.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" -dependencies = [ - "elliptic-curve", -] - [[package]] name = "proc-macro-crate" version = "3.1.0" @@ -2118,7 +835,7 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c2511913b88df1637da85cc8d96ec8e43a3f8bb8ccb71ee1ac240d6f3df58d" dependencies = [ - "bitflags 2.6.0", + "bitflags", "lazy_static", "num-traits", "rand", @@ -2222,15 +939,6 @@ dependencies = [ "rand_core", ] -[[package]] -name = "redox_syscall" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" -dependencies = [ - "bitflags 2.6.0", -] - [[package]] name = "regex" version = "1.10.6" @@ -2326,15 +1034,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "rlimit" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc0bf25554376fd362f54332b8410a625c71f15445bca32ffdfdf4ec9ac91726" -dependencies = [ - "libc", -] - [[package]] name = "rust_decimal" version = "1.35.0" @@ -2352,42 +1051,6 @@ version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" -[[package]] -name = "rustc_version" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" -dependencies = [ - "semver", -] - -[[package]] -name = "rustix" -version = "0.37.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" -dependencies = [ - "bitflags 1.3.2", - "errno", - "io-lifetimes", - "libc", - "linux-raw-sys 0.3.8", - "windows-sys 0.48.0", -] - -[[package]] -name = "rustix" -version = "0.38.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" -dependencies = [ - "bitflags 2.6.0", - "errno", - "libc", - "linux-raw-sys 0.4.14", - "windows-sys 0.52.0", -] - [[package]] name = "rustls" version = "0.23.12" @@ -2414,9 +1077,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" +checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" [[package]] name = "rustls-webpki" @@ -2435,69 +1098,26 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" -[[package]] -name = "scoped-tls" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - [[package]] name = "seahash" version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" -[[package]] -name = "sec1" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" -dependencies = [ - "base16ct", - "der", - "generic-array 0.14.7", - "subtle", - "zeroize", -] - -[[package]] -name = "semver" -version = "1.0.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" - [[package]] name = "serde" -version = "1.0.204" +version = "1.0.205" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +checksum = "e33aedb1a7135da52b7c21791455563facbbcc43d0f0f66165b42c21b3dfb150" dependencies = [ "serde_derive", ] -[[package]] -name = "serde-xml-rs" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb3aa78ecda1ebc9ec9847d5d3aba7d618823446a049ba2491940506da6e2782" -dependencies = [ - "log", - "serde", - "thiserror", - "xml-rs", -] - [[package]] name = "serde_derive" -version = "1.0.204" +version = "1.0.205" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +checksum = "692d6f5ac90220161d6774db30c662202721e64aed9058d2c394f451261420c1" dependencies = [ "proc-macro2", "quote", @@ -2525,19 +1145,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_yaml" -version = "0.9.34+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" -dependencies = [ - "indexmap", - "itoa", - "ryu", - "serde", - "unsafe-libyaml", -] - [[package]] name = "sha1" version = "0.10.6" @@ -2569,25 +1176,6 @@ dependencies = [ "lazy_static", ] -[[package]] -name = "signal-hook" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" -dependencies = [ - "libc", - "signal-hook-registry", -] - -[[package]] -name = "signal-hook-registry" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" -dependencies = [ - "libc", -] - [[package]] name = "signature" version = "2.2.0" @@ -2618,67 +1206,12 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" -[[package]] -name = "sketches-ddsketch" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04d2ecae5fcf33b122e2e6bd520a57ccf152d2dde3b38c71039df1a6867264ee" - -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - [[package]] name = "smallvec" version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" -[[package]] -name = "smol" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e635339259e51ef85ac7aa29a1cd991b957047507288697a690e80ab97d07cad" -dependencies = [ - "async-channel 2.3.1", - "async-executor", - "async-fs", - "async-io 2.3.3", - "async-lock 3.4.0", - "async-net", - "async-process", - "blocking", - "futures-lite 2.3.0", -] - -[[package]] -name = "smoltcp" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a1a996951e50b5971a2c8c0fa05a381480d70a933064245c4a223ddc87ccc97" -dependencies = [ - "bitflags 1.3.2", - "byteorder", - "cfg-if", - "heapless 0.8.0", - "managed", -] - -[[package]] -name = "socket2" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" -dependencies = [ - "libc", - "winapi", -] - [[package]] name = "socket2" version = "0.5.7" @@ -2694,9 +1227,6 @@ name = "spin" version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" -dependencies = [ - "lock_api", -] [[package]] name = "spki" @@ -2708,12 +1238,6 @@ dependencies = [ "der", ] -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - [[package]] name = "static_assertions" version = "1.1.0" @@ -2866,7 +1390,7 @@ dependencies = [ "libc", "mio", "pin-project-lite", - "socket2 0.5.7", + "socket2", "tokio-macros", "windows-sys 0.52.0", ] @@ -3028,22 +1552,6 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" -[[package]] -name = "universal-hash" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" -dependencies = [ - "crypto-common", - "subtle", -] - -[[package]] -name = "unsafe-libyaml" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" - [[package]] name = "untrusted" version = "0.9.0" @@ -3056,12 +1564,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" -[[package]] -name = "value-bag" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a84c137d37ab0142f0f2ddfe332651fdbf252e7b7dbb4e67b6c1f1b2e925101" - [[package]] name = "value-trait" version = "0.6.1" @@ -3080,18 +1582,6 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" -[[package]] -name = "void" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" - -[[package]] -name = "waker-fn" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -3123,18 +1613,6 @@ dependencies = [ "wasm-bindgen-shared", ] -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - [[package]] name = "wasm-bindgen-macro" version = "0.2.92" @@ -3164,16 +1642,6 @@ version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" -[[package]] -name = "web-sys" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - [[package]] name = "webpki-roots" version = "0.26.3" @@ -3183,22 +1651,6 @@ dependencies = [ "rustls-pki-types", ] -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - [[package]] name = "winapi-util" version = "0.1.9" @@ -3208,28 +1660,13 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - [[package]] name = "windows-core" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", + "windows-targets", ] [[package]] @@ -3238,7 +1675,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -3247,22 +1684,7 @@ version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", + "windows-targets", ] [[package]] @@ -3271,46 +1693,28 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -3323,48 +1727,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - [[package]] name = "windows_x86_64_msvc" version = "0.52.6" @@ -3395,7 +1775,6 @@ version = "0.14.0" dependencies = [ "ahash 0.8.11", "arbitrary", - "async-std", "atoi", "base64", "borsh", @@ -3403,21 +1782,12 @@ dependencies = [ "cl-aux", "crypto-common", "digest", - "embassy-net", - "embassy-sync 0.6.0", - "embassy-time", - "embedded-io-async", - "embedded-tls", - "fastrand 2.1.0", + "fastrand", "flate2", - "futures-lite 1.13.0", - "glommio", "hashbrown 0.14.5", "hmac", "httparse", "memchr", - "miniserde", - "parking_lot", "proptest", "protobuf", "rand", @@ -3427,15 +1797,11 @@ dependencies = [ "rustls-pemfile", "rustls-pki-types", "serde", - "serde-xml-rs", "serde_json", - "serde_yaml", "sha1", "sha2", "simd-json", "simdutf8", - "smol", - "smoltcp", "test-strategy", "tokio", "tokio-rustls", @@ -3443,6 +1809,7 @@ dependencies = [ "tracing-subscriber", "tracing-tree", "webpki-roots", + "wtx", "x509-certificate", ] @@ -3460,7 +1827,7 @@ name = "wtx-instances" version = "0.0.0" dependencies = [ "serde", - "simd-json", + "serde_json", "tokio", "tokio-rustls", "wtx", @@ -3515,12 +1882,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "xml-rs" -version = "0.8.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "539a77ee7c0de333dcc6da69b177380a0b81e0dacfa4f7344c465a36871ee601" - [[package]] name = "zerocopy" version = "0.7.35" diff --git a/README.md b/README.md index 39eec782..45ebaf8e 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,6 @@ For example, in a 32bit system you can allocate a maximum of 2^29 bytes of memor ## Possible future features * gRPC over HTTP/2 (). -* Web server framework * WebSocket over an HTTP/2 stream (). * cURL bindings * WebTransport over HTTP/2 (). diff --git a/wtx-docs/src/http-server-framework/README.md b/wtx-docs/src/http-server-framework/README.md index 314c9685..0c8e4cfd 100644 --- a/wtx-docs/src/http-server-framework/README.md +++ b/wtx-docs/src/http-server-framework/README.md @@ -2,6 +2,8 @@ A small and fast to compile framework that can interact with many built-in features like PostgreSQL connections. +Activation feature is called `http-server-framework`. + The bellow snippet requires ~30 dependencies and has an optimized binary size of ~690K. ```rust,edition2021,no_run diff --git a/wtx-docs/src/http2/README.md b/wtx-docs/src/http2/README.md index 82fb04af..c69e5fb2 100644 --- a/wtx-docs/src/http2/README.md +++ b/wtx-docs/src/http2/README.md @@ -6,35 +6,42 @@ Passes the `hpack-test-case` and the `h2spec` test suites. Due to official depre Activation feature is called `http2`. -```rust,edition2021 +```rust,edition2021,no_run extern crate tokio; extern crate wtx; use wtx::{ http::{Method, Request, ReqResBuffer}, http2::{Http2Buffer, Http2ErrorCode, Http2Params, Http2Tokio}, - misc::{from_utf8_basic, UriRef}, + misc::{from_utf8_basic, Either, UriRef}, rng::NoStdRng, }; use std::net::ToSocketAddrs; use tokio::net::TcpStream; -async fn client() { +#[tokio::main] +async fn main() { let uri = UriRef::new("127.0.0.1:9000"); - let mut http2 = Http2Tokio::connect( + let (frame_reader, mut http2) = Http2Tokio::connect( Http2Buffer::new(NoStdRng::default()), Http2Params::default(), - TcpStream::connect(uri.host().to_socket_addrs().unwrap().next().unwrap()).await.unwrap(), + TcpStream::connect(uri.host().to_socket_addrs().unwrap().next().unwrap()).await.unwrap().into_split(), ) .await .unwrap(); + let _jh = tokio::spawn(async move { + frame_reader.await.unwrap(); + }); let mut rrb = ReqResBuffer::default(); let mut stream = http2.stream().await.unwrap(); stream .send_req(Request::http2(Method::Get, b"Hello!"), &uri) .await + .unwrap() .unwrap(); - let res = stream.recv_res(rrb).await.unwrap(); + let Either::Right(res) = stream.recv_res(rrb).await.unwrap() else { + panic!(); + }; println!("{}", from_utf8_basic(res.0.body()).unwrap()); http2.send_go_away(Http2ErrorCode::NoError).await; } diff --git a/wtx-instances/Cargo.toml b/wtx-instances/Cargo.toml index 094d2c7e..a18f6dc5 100644 --- a/wtx-instances/Cargo.toml +++ b/wtx-instances/Cargo.toml @@ -7,21 +7,16 @@ name = "database-client-postgres-tokio-rustls" path = "examples/database-client-postgres-tokio-rustls.rs" required-features = ["wtx/_tokio-rustls-client", "wtx/postgres"] +[[example]] +name = "http-client-framework" +path = "examples/http-client-framework.rs" +required-features = ["wtx/http-client-framework", "wtx/tokio-rustls", "wtx/webpki-roots"] + [[example]] name = "http-server-framework" path = "examples/http-server-framework.rs" required-features = ["wtx/http-server-framework", "wtx/pool", "wtx/postgres", "wtx/serde", "wtx/simd-json"] -[[example]] -name = "http2-client-tokio-rustls" -path = "examples/http2-client-tokio-rustls.rs" -required-features = ["wtx/_tokio-rustls-client", "wtx/http2"] - -[[example]] -name = "http2-server-tokio-rustls" -path = "examples/http2-server-tokio-rustls.rs" -required-features = ["wtx/_tokio-rustls-client", "wtx/http2"] - [[example]] name = "web-socket-client-raw-tokio-rustls" path = "examples/web-socket-client-raw-tokio-rustls.rs" @@ -30,14 +25,7 @@ required-features = ["wtx/_tokio-rustls-client", "wtx/tokio", "wtx/web-socket-ha [[example]] name = "web-socket-server-raw-tokio-rustls" path = "examples/web-socket-server-raw-tokio-rustls.rs" -required-features = ["wtx/pool", "wtx/rustls-pemfile", "wtx/tokio-rustls", "wtx/web-socket-handshake"] - -[dependencies] -serde = { default-features = false, version = "1.0" } -simd-json = { default-features = false, features = ["serde_impl"], version = "0.11" } -tokio = { default-features = false, features = ["macros", "rt-multi-thread"], version = "1.0" } -tokio-rustls = { default-features = false, version = "0.26" } -wtx = { default-features = false, path = "../wtx" } +required-features = ["wtx/pool", "wtx/tokio-rustls", "wtx/web-socket-handshake"] # Fulfillments @@ -56,6 +44,16 @@ name = "h2spec-server" path = "fulfillments/h2spec-server.rs" required-features = ["wtx/http2", "wtx/tokio"] +[dependencies] +serde = { default-features = false, version = "1.0" } +serde_json = { default-features = false, features = ["alloc"], version = "1.0" } +tokio = { default-features = false, features = ["macros", "rt-multi-thread"], version = "1.0" } +tokio-rustls = { default-features = false, version = "0.26" } +wtx = { default-features = false, path = "../wtx" } + +[features] +_tracing-tree = ["wtx/_tracing-tree"] + [package] edition = "2024" name = "wtx-instances" diff --git a/wtx-instances/examples/database-client-postgres-tokio-rustls.rs b/wtx-instances/examples/database-client-postgres-tokio-rustls.rs index b41356f9..d0ac535c 100644 --- a/wtx-instances/examples/database-client-postgres-tokio-rustls.rs +++ b/wtx-instances/examples/database-client-postgres-tokio-rustls.rs @@ -22,10 +22,11 @@ async fn main() { TcpStream::connect(uri_ref.host()).await.unwrap(), &mut rng, |stream| { - TokioRustlsConnector::from_webpki_roots() + TokioRustlsConnector::from_auto() + .unwrap() .push_certs(include_bytes!("../../.certs/root-ca.crt")) .unwrap() - .with_generic_stream(uri_ref.hostname(), stream) + .connect_without_client_auth(uri_ref.hostname(), stream) }, ) .await diff --git a/wtx-instances/examples/http-client-framework.rs b/wtx-instances/examples/http-client-framework.rs new file mode 100644 index 00000000..306c928f --- /dev/null +++ b/wtx-instances/examples/http-client-framework.rs @@ -0,0 +1,22 @@ +//! Http2 CLI framework + +use wtx::{ + http::{ClientFramework, Method, ReqResBuffer}, + misc::{from_utf8_basic, Uri}, +}; + +#[tokio::main] +async fn main() { + let client = ClientFramework::tokio_rustls(1).build(); + let buffer = ReqResBuffer::default(); + let hello = client + .send(Method::Get, buffer, &Uri::new("https://www.google.com:443/search?q=hello")) + .await + .unwrap(); + println!("{}", from_utf8_basic(hello.rrd.body()).unwrap()); + let world = client + .send(Method::Get, hello.rrd, &Uri::new("https://www.google.com:443/search?q=world")) + .await + .unwrap(); + println!("{}", from_utf8_basic(world.rrd.body()).unwrap()); +} diff --git a/wtx-instances/examples/http-server-framework.rs b/wtx-instances/examples/http-server-framework.rs index 41284c82..80b6db6a 100644 --- a/wtx-instances/examples/http-server-framework.rs +++ b/wtx-instances/examples/http-server-framework.rs @@ -21,7 +21,7 @@ static POOL: LazyLock>> = Lazy #[tokio::main] async fn main() -> wtx::Result<()> { let router = Router::paths(paths!( - ("db/{id}", get(db)), + ("db/:id", get(db)), ("json", post(json)), ( "say", @@ -64,9 +64,9 @@ async fn json(mut req: Request) -> wtx::Result = simd_json::from_slice(req.rrd.body_mut())?; + let _de: DeserializeExample<'_> = serde_json::from_slice(req.rrd.body_mut())?; req.rrd.clear(); - simd_json::to_writer(&mut req.rrd, &SerializeExample { _baz: &[1, 2, 3, 4, 5] })?; + serde_json::to_writer(&mut req.rrd, &SerializeExample { _baz: &[1, 2, 3, 4, 5] })?; Ok(req.into_response(StatusCode::Ok)) } diff --git a/wtx-instances/examples/http2-client-tokio-rustls.rs b/wtx-instances/examples/http2-client-tokio-rustls.rs deleted file mode 100644 index c6fef98c..00000000 --- a/wtx-instances/examples/http2-client-tokio-rustls.rs +++ /dev/null @@ -1,30 +0,0 @@ -//! Http2 CLI client - -use wtx::{ - http::{Method, ReqResBuffer, Request}, - http2::{Http2Buffer, Http2ErrorCode, Http2Params, Http2Tokio}, - misc::{from_utf8_basic, TokioRustlsConnector, UriString}, - rng::NoStdRng, -}; - -#[tokio::main] -async fn main() { - let uri = UriString::new(wtx_instances::uri_from_args()); - let mut http2 = Http2Tokio::connect( - Http2Buffer::new(NoStdRng::default()), - Http2Params::default(), - TokioRustlsConnector::from_webpki_roots() - .http2() - .with_tcp_stream(uri.host(), uri.hostname()) - .await - .unwrap(), - ) - .await - .unwrap(); - let mut stream = http2.stream().await.unwrap(); - stream.send_req(Request::http2(Method::Get, ()), &uri.to_ref()).await.unwrap(); - let rrb = ReqResBuffer::default(); - let (res_rrb, _status_code) = stream.recv_res(rrb).await.unwrap(); - println!("{}", from_utf8_basic(res_rrb.body()).unwrap()); - http2.send_go_away(Http2ErrorCode::NoError).await; -} diff --git a/wtx-instances/examples/http2-server-tokio-rustls.rs b/wtx-instances/examples/http2-server-tokio-rustls.rs deleted file mode 100644 index a3d82834..00000000 --- a/wtx-instances/examples/http2-server-tokio-rustls.rs +++ /dev/null @@ -1,38 +0,0 @@ -//! Http2 echo server. - -use wtx::{ - http::{LowLevelServer, ReqResBuffer, Request, Response, StatusCode}, - http2::{Http2Buffer, Http2Params}, - misc::TokioRustlsAcceptor, - rng::StdRng, -}; - -static CERT: &[u8] = include_bytes!("../../.certs/cert.pem"); -static KEY: &[u8] = include_bytes!("../../.certs/key.pem"); - -#[tokio::main] -async fn main() { - LowLevelServer::tokio_http2( - (), - &wtx_instances::host_from_args(), - |err| eprintln!("Error: {err:?}"), - handle, - || Ok(Http2Buffer::new(StdRng::default())), - || Http2Params::default(), - || Ok(ReqResBuffer::default()), - ( - || TokioRustlsAcceptor::default().with_cert_chain_and_priv_key(CERT, KEY).unwrap(), - |acceptor| acceptor.clone(), - |acceptor, stream| async move { Ok(acceptor.accept(stream).await?) }, - ), - ) - .await - .unwrap() -} - -async fn handle( - (_, mut req): ((), Request), -) -> Result, wtx::Error> { - req.rrd.clear(); - Ok(req.into_response(StatusCode::Ok)) -} diff --git a/wtx-instances/examples/web-socket-client-raw-tokio-rustls.rs b/wtx-instances/examples/web-socket-client-raw-tokio-rustls.rs index 069e947e..0debed4a 100644 --- a/wtx-instances/examples/web-socket-client-raw-tokio-rustls.rs +++ b/wtx-instances/examples/web-socket-client-raw-tokio-rustls.rs @@ -1,6 +1,9 @@ //! WebSocket CLI client. -use tokio::io::{AsyncBufReadExt, BufReader}; +use tokio::{ + io::{AsyncBufReadExt, BufReader}, + net::TcpStream, +}; use wtx::{ misc::{TokioRustlsConnector, UriString}, rng::StdRng, @@ -19,10 +22,11 @@ async fn main() { [], &mut HeadersBuffer::default(), StdRng::default(), - TokioRustlsConnector::from_webpki_roots() + TokioRustlsConnector::from_auto() + .unwrap() .push_certs(include_bytes!("../../.certs/root-ca.crt")) .unwrap() - .with_tcp_stream(uri.host(), uri.hostname()) + .connect_without_client_auth(uri.hostname(), TcpStream::connect(uri.host()).await.unwrap()) .await .unwrap(), &uri.to_ref(), diff --git a/wtx-instances/examples/web-socket-server-raw-tokio-rustls.rs b/wtx-instances/examples/web-socket-server-raw-tokio-rustls.rs index f06567a4..b043379e 100644 --- a/wtx-instances/examples/web-socket-server-raw-tokio-rustls.rs +++ b/wtx-instances/examples/web-socket-server-raw-tokio-rustls.rs @@ -21,7 +21,11 @@ async fn main() { |err| eprintln!("Connection error: {err:?}"), handle, ( - || TokioRustlsAcceptor::default().with_cert_chain_and_priv_key(CERT, KEY).unwrap(), + || { + TokioRustlsAcceptor::without_client_auth() + .build_with_cert_chain_and_priv_key(CERT, KEY) + .unwrap() + }, |acceptor| acceptor.clone(), |acceptor, stream| async move { Ok(acceptor.accept(stream).await?) }, ), diff --git a/wtx-instances/fulfillments/h2spec-server.rs b/wtx-instances/fulfillments/h2spec-server.rs index 088dce89..b5d6abc9 100644 --- a/wtx-instances/fulfillments/h2spec-server.rs +++ b/wtx-instances/fulfillments/h2spec-server.rs @@ -8,6 +8,8 @@ use wtx::{ #[tokio::main] async fn main() { + #[cfg(feature = "_tracing-tree")] + let _rslt = wtx::misc::tracing_tree_init(); LowLevelServer::tokio_http2( (), "127.0.0.1:9000", @@ -16,7 +18,7 @@ async fn main() { || Ok(Http2Buffer::new(StdRng::default())), Http2Params::default, || Ok(ReqResBuffer::default()), - (|| {}, |_| {}, |_, stream| async move { Ok(stream) }), + (|| Ok(()), |_| {}, |_, stream| async move { Ok(stream.into_split()) }), ) .await .unwrap() diff --git a/wtx-ui/Cargo.toml b/wtx-ui/Cargo.toml index 2f531b34..73c6bd41 100644 --- a/wtx-ui/Cargo.toml +++ b/wtx-ui/Cargo.toml @@ -1,7 +1,7 @@ cargo-features = ["edition2024"] [dependencies] -clap = { default-features = false, features = ["derive", "help", "std", "usage"], optional = true, version = "4.5" } +clap = { default-features = false, features = ["derive", "help", "std", "usage"], optional = true, version = "4.0" } dotenv = { default-features = false, optional = true, version = "0.15" } tokio = { default-features = false, features = ["io-std", "io-util", "macros", "net", "rt-multi-thread"], version = "1.0" } wtx = { default-features = false, features = ["tokio"], path = "../wtx" } @@ -13,7 +13,7 @@ dotenv = ["dep:dotenv"] embed-migrations = ["clap", "tokio/fs", "wtx/schema-manager", "wtx/std"] http-client = ["clap", "wtx/http-client-framework", "wtx/tokio-rustls", "wtx/webpki-roots"] schema-manager = ["clap", "wtx/postgres", "wtx/schema-manager", "wtx/std"] -schema-manager-dev = ["dotenv", "schema-manager", "wtx/_tracing-subscriber", "wtx/schema-manager-dev"] +schema-manager-dev = ["dotenv", "schema-manager", "wtx/_tracing-tree", "wtx/schema-manager-dev"] web-socket = ["clap", "wtx/web-socket-handshake"] [package] diff --git a/wtx-ui/src/schema_manager.rs b/wtx-ui/src/schema_manager.rs index b8ed0849..702165de 100644 --- a/wtx-ui/src/schema_manager.rs +++ b/wtx-ui/src/schema_manager.rs @@ -15,7 +15,7 @@ pub(crate) async fn schema_manager(sm: &SchemaManager) -> wtx::Result<()> { #[cfg(feature = "schema-manager-dev")] { let _rslt = dotenv::dotenv(); - wtx::misc::tracing_subscriber_init()?; + wtx::misc::tracing_tree_init()?; } let var = std::env::var(DEFAULT_URI_VAR)?; @@ -32,7 +32,7 @@ pub(crate) async fn schema_manager(sm: &SchemaManager) -> wtx::Result<()> { .await?; handle_commands(executor, sm).await?; } - _ => return Err(wtx::Error::MISC_InvalidUrl), + _ => return Err(wtx::Error::MISC_InvalidUri), } Ok(()) } diff --git a/wtx/Cargo.toml b/wtx/Cargo.toml index db8c1053..4ba31730 100644 --- a/wtx/Cargo.toml +++ b/wtx/Cargo.toml @@ -3,48 +3,33 @@ cargo-features = ["edition2024"] [dependencies] ahash = { default-features = false, features = ["no-rng"], optional = true, version = "0.8" } arbitrary = { default-features = false, features = ["derive_arbitrary"], optional = true, version = "1.0" } -async-std = { default-features = false, features = ["default"], optional = true, version = "1.0" } atoi = { default-features = false, optional = true, version = "2.0" } base64 = { default-features = false, features = ["alloc"], optional = true, version = "0.22" } -borsh = { default-features = false, features = ["derive", "std"], optional = true, version = "1.4" } -bytes = { default-features = false, optional = true, version = "1.0" } +borsh = { default-features = false, features = ["derive", "std"], optional = true, version = "1.0" } chrono = { default-features = false, optional = true, version = "0.4" } cl-aux = { default-features = false, optional = true, features = ["alloc"], version = "5.0" } crypto-common = { default-features = false, optional = true, version = "0.1" } digest = { default-features = false, features = ["mac"], optional = true, version = "0.10" } -embassy-net = { default-features = false, features = ["tcp"], optional = true, version = "0.4" } -embassy-sync = { default-features = false, optional = true, version = "0.6" } -embassy-time = { default-features = false, optional = true, version = "0.3" } -embedded-io-async = { default-features = false, optional = true, version = "0.6" } -embedded-tls = { default-features = false, features = ["async"], optional = true, version = "0.16" } fastrand = { default-features = false, optional = true, version = "2.0" } flate2 = { default-features = false, features = ["zlib-rs"], optional = true, version = "1.0" } -futures-lite = { default-features = false, optional = true, version = "1.0" } -glommio = { default-features = false, optional = true, version = "0.9" } hashbrown = { default-features = false, features = ["ahash", "allocator-api2", "inline-more"], optional = true, version = "0.14" } hmac = { default-features = false, optional = true, version = "0.12" } httparse = { default-features = false, optional = true, version = "1.0" } -memchr = { default-features = false, optional = true, version = "2.7" } -miniserde = { default-features = false, optional = true, version = "0.1" } -parking_lot = { default-features = false, optional = true, version = "0.12" } +memchr = { default-features = false, optional = true, version = "2.0" } proptest = { default-features = false, features = ["alloc"], optional = true, version = "1.0" } -protobuf = { default-features = false, optional = true, version = "3.4" } +protobuf = { default-features = false, optional = true, version = "3.0" } rand = { default-features = false, features = ["small_rng"], optional = true, version = "0.8" } ring = { default-features = false, optional = true, version = "0.17" } rkyv = { default-features = false, features = ["validation"], optional = true, version = "0.7" } -rust_decimal = { default-features = false, features = ["maths"], optional = true, version = "1.34" } -rustls-pemfile = { default-features = false, features = ["std"], optional = true, version = "2.1" } -rustls-pki-types = { default-features = false, optional = true, version = "1.4" } +rust_decimal = { default-features = false, features = ["maths"], optional = true, version = "1.0" } +rustls-pemfile = { default-features = false, features = ["std"], optional = true, version = "2.0" } +rustls-pki-types = { default-features = false, optional = true, version = "1.0" } serde = { default-features = false, features = ["alloc", "derive"], optional = true, version = "1.0" } serde_json = { default-features = false, features = ["alloc"], optional = true, version = "1.0" } -serde_yaml = { default-features = false, optional = true, version = "0.9" } -serde-xml-rs = { default-features = false, optional = true, version = "0.6" } sha1 = { default-features = false, optional = true, version = "0.10" } sha2 = { default-features = false, optional = true, version = "0.10" } simd-json = { default-features = false, features = ["serde_impl"], optional = true, version = "0.11" } simdutf8 = { default-features = false, features = ["aarch64_neon"], optional = true, version = "0.1" } -smol = { default-features = false, optional = true, version = "2.0" } -smoltcp = { default-features = false, optional = true, version = "0.11" } test-strategy = { default-features = false, optional = true, version = "0.4" } tokio = { default-features = false, features = ["io-util", "net", "rt", "sync", "time"], optional = true, version = "1.0" } tokio-rustls = { default-features = false, features = ["ring"], optional = true, version = "0.26" } @@ -55,13 +40,12 @@ webpki-roots = { default-features = false, optional = true, version = "0.26" } x509-certificate = { default-features = false, optional = true, version = "0.23" } [dev-dependencies] -chrono = { default-features = false, features = ["clock"], version = "0.4" } tokio = { default-features = false, features = ["macros", "net", "rt-multi-thread", "time"], version = "1.0" } +wtx = { default-features = false, features = ["std", "tokio"], path = "./" } [features] ahash = ["dep:ahash", "hashbrown?/ahash"] arbitrary = ["dep:arbitrary", "std"] -async-std = ["dep:async-std", "std"] atoi = ["dep:atoi"] base64 = ["dep:base64"] borsh = ["dep:borsh", "std"] @@ -72,14 +56,8 @@ crypto-common = ["dep:crypto-common"] database = [] default = [] digest = ["dep:digest"] -embassy-net = ["dep:embassy-net"] -embassy-sync = ["dep:embassy-sync"] -embassy-time = ["dep:embassy-time"] -embedded-tls = ["dep:embedded-io-async", "dep:embedded-tls"] fastrand = ["dep:fastrand"] flate2 = ["dep:flate2"] -futures-lite = ["dep:futures-lite"] -glommio = ["futures-lite", "dep:glommio", "std"] hashbrown = ["dep:hashbrown"] hmac = ["dep:hmac"] http-client-framework = ["http2", "pool", "std"] @@ -87,9 +65,7 @@ http-server-framework = ["http2", "tokio"] http2 = ["ahash", "hashbrown"] httparse = ["dep:httparse"] memchr = ["dep:memchr"] -miniserde = ["dep:miniserde", "std"] optimization = ["atoi", "memchr", "simdutf8"] -parking_lot = ["dep:parking_lot"] pool = [] postgres = ["ahash", "base64", "crypto-common", "database", "digest", "hashbrown", "hmac", "sha2"] proptest = ["dep:proptest"] @@ -98,36 +74,31 @@ rand = ["dep:rand"] ring = ["dep:ring"] rkyv = ["dep:rkyv"] rust_decimal = ["dep:rust_decimal"] -rustls-pemfile = ["dep:rustls-pemfile"] -rustls-pki-types = ["dep:rustls-pki-types"] schema-manager = ["database", "chrono"] schema-manager-dev = ["schema-manager"] serde = ["cl-aux?/serde", "dep:serde"] serde_json = ["serde", "dep:serde_json", "std"] -serde_yaml = ["serde", "dep:serde_yaml", "std"] -serde-xml-rs = ["serde", "dep:serde-xml-rs", "std"] sha1 = ["dep:sha1"] sha2 = ["dep:sha2"] simd-json = ["serde", "dep:simd-json", "std"] simdutf8 = ["dep:simdutf8"] -smol = ["dep:smol", "std"] -smoltcp = ["dep:smoltcp"] -std = ["ahash?/std", "atoi?/std", "cl-aux?/std", "embassy-sync?/std", "memchr?/std", "miniserde?/std", "serde?/std", "serde_json?/std", "simdutf8?/std"] +std = ["ahash?/std", "atoi?/std", "cl-aux?/std", "memchr?/std", "serde?/std", "serde_json?/std", "simdutf8?/std"] test-strategy = ["dep:test-strategy", "proptest", "std"] tokio = ["std", "dep:tokio"] -tokio-rustls = ["ring", "rustls-pki-types", "tokio", "dep:tokio-rustls"] +tokio-rustls = ["ring", "dep:rustls-pemfile", "dep:rustls-pki-types", "tokio", "dep:tokio-rustls"] tracing = ["dep:tracing"] +tracing-subscriber = ["dep:tracing-subscriber"] web-socket = [] web-socket-handshake = ["base64", "httparse", "sha1", "web-socket"] webpki-roots = ["dep:webpki-roots"] x509-certificate = ["dep:x509-certificate"] _bench = [] -_hack = ["embassy-net?/medium-ip", "embassy-net?/proto-ipv4", "rkyv?/size_32", "simd-json?/allow-non-simd", "smoltcp?/medium-ip", "smoltcp?/proto-ipv4", "smoltcp?/socket-tcp"] +_hack = ["rkyv?/size_32", "simd-json?/allow-non-simd"] _integration-tests = ["serde_json?/raw_value"] _proptest = ["proptest/std", "rust_decimal?/proptest", "std", "test-strategy"] -_tokio-rustls-client = ["rustls-pemfile", "tokio-rustls/tls12", "webpki-roots"] -_tracing-subscriber = ["tracing", "dep:tracing-subscriber", "dep:tracing-tree"] +_tokio-rustls-client = ["tokio-rustls/tls12", "webpki-roots"] +_tracing-tree = ["tracing", "tracing-subscriber", "dep:tracing-tree"] [package] authors = ["Caio Fernandes "] diff --git a/wtx/src/client_api_framework/data_format/graph_ql/graph_ql_request.rs b/wtx/src/client_api_framework/data_format/graph_ql/graph_ql_request.rs index 235ae85c..28c28282 100644 --- a/wtx/src/client_api_framework/data_format/graph_ql/graph_ql_request.rs +++ b/wtx/src/client_api_framework/data_format/graph_ql/graph_ql_request.rs @@ -1,21 +1,14 @@ /// GraphQL request or operation, can be a query or a mutation. -#[cfg_attr(feature = "miniserde", derive(miniserde::Serialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize))] #[derive(Debug)] pub struct GraphQlRequest { /// Describes what type of operation you're intending to perform. - #[cfg_attr( - all(feature = "serde", not(feature = "miniserde")), - serde(skip_serializing_if = "Option::is_none") - )] + #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] pub operation_name: Option, /// Describes the desired data to be fetched. pub query: Q, /// Separated data intended to help queries. - #[cfg_attr( - all(feature = "serde", not(feature = "miniserde")), - serde(skip_serializing_if = "Option::is_none") - )] + #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] pub variables: Option, } diff --git a/wtx/src/client_api_framework/data_format/json/json_request.rs b/wtx/src/client_api_framework/data_format/json/json_request.rs index 1502d4ec..1619515c 100644 --- a/wtx/src/client_api_framework/data_format/json/json_request.rs +++ b/wtx/src/client_api_framework/data_format/json/json_request.rs @@ -14,29 +14,6 @@ impl Serialize<()> for JsonRequest { } } -#[cfg(feature = "miniserde")] -mod miniserde { - use crate::{ - client_api_framework::{ - data_format::JsonRequest, - dnsn::{miniserde_serialize, Miniserde}, - }, - misc::Vector, - }; - - impl crate::client_api_framework::dnsn::Serialize for JsonRequest - where - D: miniserde::Serialize, - { - fn to_bytes(&mut self, bytes: &mut Vector, _: &mut Miniserde) -> crate::Result<()> { - if size_of::() == 0 { - return Ok(()); - } - miniserde_serialize(bytes, &self.data) - } - } -} - #[cfg(feature = "serde_json")] mod serde_json { use crate::{ diff --git a/wtx/src/client_api_framework/data_format/json/json_response.rs b/wtx/src/client_api_framework/data_format/json/json_response.rs index ae9d5614..0899e957 100644 --- a/wtx/src/client_api_framework/data_format/json/json_response.rs +++ b/wtx/src/client_api_framework/data_format/json/json_response.rs @@ -35,53 +35,6 @@ impl Serialize<()> for JsonResponse { } } -#[cfg(feature = "miniserde")] -mod miniserde { - use crate::{ - client_api_framework::{ - data_format::JsonResponse, - dnsn::{miniserde_serialize, Miniserde}, - }, - misc::{from_utf8_basic, Vector}, - }; - use core::fmt::Display; - - impl crate::client_api_framework::dnsn::Deserialize for JsonResponse - where - D: miniserde::Deserialize, - { - fn from_bytes(bytes: &[u8], _: &mut Miniserde) -> crate::Result { - Ok(Self { data: miniserde::json::from_str(from_utf8_basic(bytes)?)? }) - } - - fn seq_from_bytes( - bytes: &[u8], - _: &mut Miniserde, - mut cb: impl FnMut(Self) -> Result<(), E>, - ) -> Result<(), E> - where - E: Display + From, - { - let data_fn = || crate::Result::Ok(miniserde::json::from_str(from_utf8_basic(bytes)?)?); - cb(Self { data: data_fn()? })?; - Ok(()) - } - } - - impl crate::client_api_framework::dnsn::Serialize for JsonResponse - where - D: miniserde::Serialize, - { - #[inline] - fn to_bytes(&mut self, bytes: &mut Vector, _: &mut Miniserde) -> crate::Result<()> { - if size_of::() == 0 { - return Ok(()); - } - miniserde_serialize(bytes, &self.data) - } - } -} - #[cfg(feature = "serde_json")] mod serde_json { use crate::{ diff --git a/wtx/src/client_api_framework/data_format/xml/xml_request.rs b/wtx/src/client_api_framework/data_format/xml/xml_request.rs index 97bd1dbe..2f6f24e9 100644 --- a/wtx/src/client_api_framework/data_format/xml/xml_request.rs +++ b/wtx/src/client_api_framework/data_format/xml/xml_request.rs @@ -15,25 +15,3 @@ impl Serialize<()> for XmlRequest { Ok(()) } } - -#[cfg(feature = "serde-xml-rs")] -mod serde_xml_rs { - use crate::{ - client_api_framework::{data_format::XmlRequest, dnsn::SerdeXmlRs}, - misc::Vector, - }; - - impl crate::client_api_framework::dnsn::Serialize for XmlRequest - where - D: serde::Serialize, - { - #[inline] - fn to_bytes(&mut self, bytes: &mut Vector, _: &mut SerdeXmlRs) -> crate::Result<()> { - if size_of::() == 0 { - return Ok(()); - } - serde_xml_rs::to_writer(bytes, &self.data)?; - Ok(()) - } - } -} diff --git a/wtx/src/client_api_framework/data_format/xml/xml_response.rs b/wtx/src/client_api_framework/data_format/xml/xml_response.rs index 40e1e2f0..fbb1e9e1 100644 --- a/wtx/src/client_api_framework/data_format/xml/xml_response.rs +++ b/wtx/src/client_api_framework/data_format/xml/xml_response.rs @@ -37,50 +37,3 @@ impl Serialize<()> for XmlResponse { Ok(()) } } - -#[cfg(feature = "serde-xml-rs")] -mod serde_xml_rs { - use crate::{ - client_api_framework::{ - data_format::XmlResponse, dnsn::SerdeXmlRs, misc::seq_visitor::_SeqVisitor, - }, - misc::Vector, - }; - use core::fmt::Display; - use serde::de::Deserializer; - - impl crate::client_api_framework::dnsn::Deserialize for XmlResponse - where - D: for<'de> serde::Deserialize<'de>, - { - fn from_bytes(bytes: &[u8], _: &mut SerdeXmlRs) -> crate::Result { - Ok(serde_xml_rs::from_reader(bytes)?) - } - - fn seq_from_bytes( - bytes: &[u8], - _: &mut SerdeXmlRs, - mut cb: impl FnMut(Self) -> Result<(), E>, - ) -> Result<(), E> - where - E: Display + From, - { - let mut de = serde_xml_rs::Deserializer::new_from_reader(bytes); - de.deserialize_seq(_SeqVisitor::_new(|data| cb(Self { data }))).map_err(Into::into)?; - Ok(()) - } - } - - impl crate::client_api_framework::dnsn::Serialize for XmlResponse - where - D: serde::Serialize, - { - fn to_bytes(&mut self, bytes: &mut Vector, _: &mut SerdeXmlRs) -> crate::Result<()> { - if size_of::() == 0 { - return Ok(()); - } - serde_xml_rs::to_writer(bytes, self)?; - Ok(()) - } - } -} diff --git a/wtx/src/client_api_framework/data_format/yaml/yaml_request.rs b/wtx/src/client_api_framework/data_format/yaml/yaml_request.rs index b38e239b..6b6578aa 100644 --- a/wtx/src/client_api_framework/data_format/yaml/yaml_request.rs +++ b/wtx/src/client_api_framework/data_format/yaml/yaml_request.rs @@ -15,25 +15,3 @@ impl Serialize<()> for YamlRequest { Ok(()) } } - -#[cfg(feature = "serde_yaml")] -mod serde_yaml { - use crate::{ - client_api_framework::{data_format::YamlRequest, dnsn::SerdeYaml}, - misc::Vector, - }; - - impl crate::client_api_framework::dnsn::Serialize for YamlRequest - where - D: serde::Serialize, - { - #[inline] - fn to_bytes(&mut self, bytes: &mut Vector, _: &mut SerdeYaml) -> crate::Result<()> { - if size_of::() == 0 { - return Ok(()); - } - serde_yaml::to_writer(bytes, &self.data)?; - Ok(()) - } - } -} diff --git a/wtx/src/client_api_framework/data_format/yaml/yaml_response.rs b/wtx/src/client_api_framework/data_format/yaml/yaml_response.rs index b61644e2..1b316371 100644 --- a/wtx/src/client_api_framework/data_format/yaml/yaml_response.rs +++ b/wtx/src/client_api_framework/data_format/yaml/yaml_response.rs @@ -37,50 +37,3 @@ impl Serialize<()> for YamlResponse { Ok(()) } } - -#[cfg(feature = "serde_yaml")] -mod serde_yaml { - use crate::{ - client_api_framework::{ - data_format::YamlResponse, dnsn::SerdeYaml, misc::seq_visitor::_SeqVisitor, - }, - misc::Vector, - }; - use core::fmt::Display; - use serde::de::Deserializer; - - impl crate::client_api_framework::dnsn::Deserialize for YamlResponse - where - D: for<'de> serde::Deserialize<'de>, - { - fn from_bytes(bytes: &[u8], _: &mut SerdeYaml) -> crate::Result { - Ok(serde_yaml::from_reader(bytes)?) - } - - fn seq_from_bytes( - bytes: &[u8], - _: &mut SerdeYaml, - mut cb: impl FnMut(Self) -> Result<(), E>, - ) -> Result<(), E> - where - E: Display + From, - { - let de = serde_yaml::Deserializer::from_reader(bytes); - de.deserialize_seq(_SeqVisitor::_new(|data| cb(Self { data }))).map_err(Into::into)?; - Ok(()) - } - } - - impl crate::client_api_framework::dnsn::Serialize for YamlResponse - where - D: serde::Serialize, - { - fn to_bytes(&mut self, bytes: &mut Vector, _: &mut SerdeYaml) -> crate::Result<()> { - if size_of::() == 0 { - return Ok(()); - } - serde_yaml::to_writer(bytes, self)?; - Ok(()) - } - } -} diff --git a/wtx/src/client_api_framework/dnsn.rs b/wtx/src/client_api_framework/dnsn.rs index 18d9da0e..37a67b15 100644 --- a/wtx/src/client_api_framework/dnsn.rs +++ b/wtx/src/client_api_framework/dnsn.rs @@ -10,36 +10,24 @@ mod tests; #[cfg(feature = "borsh")] mod borsh; mod deserialize; -#[cfg(feature = "miniserde")] -mod miniserde; #[cfg(feature = "protobuf")] mod protobuf; #[cfg(feature = "rkyv")] mod rkyv; #[cfg(feature = "serde_json")] mod serde_json; -#[cfg(feature = "serde-xml-rs")] -mod serde_xml_rs; -#[cfg(feature = "serde_yaml")] -mod serde_yaml; mod serialize; #[cfg(feature = "simd-json")] mod simd_json; #[cfg(feature = "borsh")] pub use self::borsh::*; -#[cfg(feature = "miniserde")] -pub use self::miniserde::*; #[cfg(feature = "protobuf")] pub use self::protobuf::*; #[cfg(feature = "rkyv")] pub use self::rkyv::*; #[cfg(feature = "serde_json")] pub use self::serde_json::*; -#[cfg(feature = "serde-xml-rs")] -pub use self::serde_xml_rs::*; -#[cfg(feature = "serde_yaml")] -pub use self::serde_yaml::*; #[cfg(feature = "simd-json")] pub use self::simd_json::*; pub use deserialize::*; diff --git a/wtx/src/client_api_framework/dnsn/miniserde.rs b/wtx/src/client_api_framework/dnsn/miniserde.rs deleted file mode 100644 index 20ba7c70..00000000 --- a/wtx/src/client_api_framework/dnsn/miniserde.rs +++ /dev/null @@ -1,31 +0,0 @@ -use crate::misc::Vector; - -/// Type that indicates the usage of the `miniserde` dependency. -#[derive(Debug)] -pub struct Miniserde; - -_impl_se_collections!( - for Miniserde => miniserde::Serialize; - - slice_ref: |this, bytes, _drsr| { miniserde_serialize(bytes, this)?; } - vec: |this, bytes, _drsr| { miniserde_serialize(bytes, this)?; } -); - -pub(crate) fn miniserde_serialize(bytes: &mut Vector, elem: &E) -> crate::Result<()> -where - E: miniserde::Serialize, -{ - bytes.extend_from_slice(miniserde::json::to_string(elem).as_bytes())?; - Ok(()) -} - -#[cfg(test)] -mod tests { - _create_dnsn_test!( - json, - (JsonRequest, JsonResponse), - Miniserde as Miniserde, - (r#"{"foo":"foo"}"#.into(), r#"{"bar":"bar"}"#.into()), - (JsonRequest { data: Foo { foo: "foo" } }, JsonResponse { data: Bar { bar: "bar".into() } }), - ); -} diff --git a/wtx/src/client_api_framework/dnsn/serde_xml_rs.rs b/wtx/src/client_api_framework/dnsn/serde_xml_rs.rs deleted file mode 100644 index 24f7ed7b..00000000 --- a/wtx/src/client_api_framework/dnsn/serde_xml_rs.rs +++ /dev/null @@ -1,26 +0,0 @@ -/// Type that indicates the usage of the `serde-xml-rs` dependency. -#[derive(Debug)] -pub struct SerdeXmlRs; - -_impl_se_collections!( - for SerdeXmlRs => serde::Serialize; - - array: |this, bytes, _drsr| { serde_xml_rs::to_writer(bytes, &&this[..])?; } - arrayvector: |this, bytes, _drsr| { serde_xml_rs::to_writer(bytes, this)?; } - slice_ref: |this, bytes, _drsr| { serde_xml_rs::to_writer(bytes, this)?; } - vec: |this, bytes, _drsr| { serde_xml_rs::to_writer(bytes, this)?; } -); - -#[cfg(test)] -mod tests { - _create_dnsn_test!( - xml, - (XmlRequest, XmlResponse), - SerdeXmlRs as SerdeXmlRs, - ( - r#"foo"#.into(), - r#"bar"#.into() - ), - (XmlRequest { data: Foo { foo: "foo" } }, XmlResponse { data: Bar { bar: "bar".into() } }), - ); -} diff --git a/wtx/src/client_api_framework/dnsn/serde_yaml.rs b/wtx/src/client_api_framework/dnsn/serde_yaml.rs deleted file mode 100644 index fec9c24b..00000000 --- a/wtx/src/client_api_framework/dnsn/serde_yaml.rs +++ /dev/null @@ -1,23 +0,0 @@ -/// Type that indicates the usage of the `serde-xml-rs` dependency. -#[derive(Debug)] -pub struct SerdeYaml; - -_impl_se_collections!( - for SerdeYaml => serde::Serialize; - - array: |this, bytes, _drsr| { serde_yaml::to_writer(bytes, &this[..])?; } - arrayvector: |this, bytes, _drsr| { serde_yaml::to_writer(bytes, this)?; } - slice_ref: |this, bytes, _drsr| { serde_yaml::to_writer(bytes, this)?; } - vec: |this, bytes, _drsr| { serde_yaml::to_writer(bytes, this)?; } -); - -#[cfg(test)] -mod tests { - _create_dnsn_test!( - yaml, - (YamlRequest, YamlResponse), - SerdeYaml as SerdeYaml, - ("foo: foo\n".into(), r#"bar: bar"#.into()), - (YamlRequest { data: Foo { foo: "foo" } }, YamlResponse { data: Bar { bar: "bar".into() } }), - ); -} diff --git a/wtx/src/client_api_framework/dnsn/tests.rs b/wtx/src/client_api_framework/dnsn/tests.rs index 5987e796..d9ff71bf 100644 --- a/wtx/src/client_api_framework/dnsn/tests.rs +++ b/wtx/src/client_api_framework/dnsn/tests.rs @@ -45,7 +45,6 @@ where } #[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize))] -#[cfg_attr(feature = "miniserde", derive(miniserde::Serialize))] #[cfg_attr(feature = "rkyv", derive(rkyv::Archive, rkyv::Serialize))] #[cfg_attr(feature = "rkyv", archive_attr(derive(Debug, rkyv::bytecheck::CheckBytes)))] #[cfg_attr(feature = "serde", derive(serde::Serialize))] @@ -56,7 +55,6 @@ pub(crate) struct Foo { } #[cfg_attr(feature = "borsh", derive(borsh::BorshDeserialize, borsh::BorshSerialize))] -#[cfg_attr(feature = "miniserde", derive(miniserde::Deserialize))] #[cfg_attr(feature = "rkyv", derive(rkyv::Archive, rkyv::Deserialize))] #[cfg_attr(feature = "rkyv", archive_attr(derive(Debug, rkyv::bytecheck::CheckBytes)))] #[cfg_attr(feature = "serde", derive(serde::Deserialize))] diff --git a/wtx/src/client_api_framework/misc/request_counter.rs b/wtx/src/client_api_framework/misc/request_counter.rs index ea5ed99b..24bf4005 100644 --- a/wtx/src/client_api_framework/misc/request_counter.rs +++ b/wtx/src/client_api_framework/misc/request_counter.rs @@ -72,7 +72,7 @@ impl Default for RequestCounter { } } -#[cfg(all(feature = "tokio", test))] +#[cfg(test)] mod tests { use crate::client_api_framework::misc::{RequestCounter, RequestLimit}; use core::time::Duration; diff --git a/wtx/src/database/client/postgres/executor.rs b/wtx/src/database/client/postgres/executor.rs index 440f0f97..50106a48 100644 --- a/wtx/src/database/client/postgres/executor.rs +++ b/wtx/src/database/client/postgres/executor.rs @@ -15,7 +15,7 @@ use crate::{ }, Database, RecordValues, StmtCmd, TransactionManager as _, }, - misc::{ConnectionState, FilledBufferWriter, Lease, LeaseMut, Stream, TlsStream}, + misc::{ConnectionState, FilledBufferWriter, Lease, LeaseMut, Stream, StreamWithTls}, rng::Rng, }; use core::marker::PhantomData; @@ -63,7 +63,7 @@ where F: Future>, IS: Stream, RNG: Rng, - S: TlsStream, + S: StreamWithTls, { eb.lease_mut().clear(); let mut fbw = FilledBufferWriter::from(&mut eb.lease_mut().nb); diff --git a/wtx/src/database/client/postgres/integration_tests.rs b/wtx/src/database/client/postgres/integration_tests.rs index febd0118..21c9ddec 100644 --- a/wtx/src/database/client/postgres/integration_tests.rs +++ b/wtx/src/database/client/postgres/integration_tests.rs @@ -26,10 +26,11 @@ async fn conn_scram_tls() { &mut rng, |stream| async { Ok( - crate::misc::TokioRustlsConnector::from_webpki_roots() + crate::misc::TokioRustlsConnector::from_auto() + .unwrap() .push_certs(include_bytes!("../../../../../.certs/root-ca.crt")) .unwrap() - .with_generic_stream(uri.hostname(), stream) + .connect_without_client_auth(uri.hostname(), stream) .await .unwrap(), ) diff --git a/wtx/src/database/from_records.rs b/wtx/src/database/from_records.rs index 1aeffe07..ea3f8ea3 100644 --- a/wtx/src/database/from_records.rs +++ b/wtx/src/database/from_records.rs @@ -4,7 +4,7 @@ use crate::{ }; use alloc::boxed::Box; -/// An element that can be represented from one or more database row, in other words, tables +/// An element that can be represented from one or more database rows, in other words, entities /// with relationships. pub trait FromRecords<'exec, D>: Sized where diff --git a/wtx/src/database/schema_manager/misc.rs b/wtx/src/database/schema_manager/misc.rs index d277db7e..00a80235 100644 --- a/wtx/src/database/schema_manager/misc.rs +++ b/wtx/src/database/schema_manager/misc.rs @@ -27,11 +27,11 @@ use { crate::misc::ArrayVector, alloc::string::String, core::cmp::Ordering, - std::path::{Path, PathBuf}, std::{ fmt::Write, fs::{read_to_string, DirEntry, File}, io::Read, + path::{Path, PathBuf}, }, }; diff --git a/wtx/src/error.rs b/wtx/src/error.rs index 92b27afb..6c7c8e49 100644 --- a/wtx/src/error.rs +++ b/wtx/src/error.rs @@ -36,22 +36,16 @@ pub enum Error { DecodeError(base64::DecodeError), #[cfg(feature = "base64")] DecodeSliceError(base64::DecodeSliceError), - #[cfg(feature = "embassy-net")] - EmbassyNet(embassy_net::tcp::Error), #[cfg(feature = "base64")] EncodeSliceError(base64::EncodeSliceError), #[cfg(feature = "flate2")] Flate2CompressError(flate2::CompressError), #[cfg(feature = "flate2")] Flate2DecompressError(Box), - #[cfg(feature = "glommio")] - Glommio(Box>), #[cfg(feature = "httparse")] HttpParse(httparse::Error), #[cfg(feature = "digest")] MacError(digest::MacError), - #[cfg(feature = "miniserde")] - Miniserde(miniserde::Error), #[cfg(feature = "postgres")] PostgresDbError(Box), #[cfg(feature = "protobuf")] @@ -62,23 +56,13 @@ pub enum Error { RkyvSer(Box), #[cfg(feature = "serde_json")] SerdeJson(serde_json::Error), - #[cfg(feature = "serde-xml-rs")] - SerdeXmlRs(Box), - #[cfg(feature = "serde_yaml")] - SerdeYaml(serde_yaml::Error), #[cfg(feature = "simd-json")] SimdJson(Box), - #[cfg(feature = "smoltcp")] - SmoltcpTcpRecvError(smoltcp::socket::tcp::RecvError), - #[cfg(feature = "smoltcp")] - SmoltcpTcpSendError(smoltcp::socket::tcp::SendError), - #[cfg(feature = "embedded-tls")] - TlsError(embedded_tls::TlsError), #[cfg(feature = "tokio")] TokioJoinError(Box), #[cfg(feature = "tokio-rustls")] TokioRustlsError(Box), - #[cfg(feature = "_tracing-subscriber")] + #[cfg(feature = "tracing-subscriber")] TryInitError(tracing_subscriber::util::TryInitError), #[cfg(feature = "std")] TryLockError(std::sync::TryLockError<()>), @@ -105,6 +89,8 @@ pub enum Error { BlocksQueueError(BlocksQueueError), #[cfg(feature = "client-api-framework")] ClientApiFrameworkError(crate::client_api_framework::ClientApiFrameworkError), + #[cfg(feature = "http-client-framework")] + HttpClientFrameworkError(crate::http::HttpClientFrameworkError), HttpError(crate::http::HttpError), #[cfg(feature = "http2")] Http2ErrorGoAway(crate::http2::Http2ErrorCode, Option), @@ -134,10 +120,14 @@ pub enum Error { MISC_InvalidDatabaseUrl(&'static str), /// Backend couldn't perform passed query string MISC_InvalidSqlQuery, - /// Invalid URL - MISC_InvalidUrl, + /// Invalid URI + MISC_InvalidUri, /// Environment variable is not present MISC_MissingEnvVar, + /// There is no CA provider. + MISC_MissingCaProviders, + /// There is no parser to process PEM files. + MISC_MissingPemParser, /// A variant used to transform `Option`s into `Result`s MISC_NoInnerValue(&'static str), /// A set of arithmetic operations resulted in an overflow, underflow or division by zero @@ -221,14 +211,6 @@ impl From for Error { } } -#[cfg(feature = "embassy-net")] -impl From for Error { - #[inline] - fn from(from: embassy_net::tcp::Error) -> Self { - Self::EmbassyNet(from) - } -} - #[cfg(feature = "base64")] impl From for Error { #[inline] @@ -267,14 +249,6 @@ impl From for Error { } } -#[cfg(feature = "glommio")] -impl From> for Error { - #[inline] - fn from(from: glommio::GlommioError<()>) -> Self { - Self::Glommio(from.into()) - } -} - #[cfg(feature = "httparse")] impl From for Error { #[inline] @@ -310,14 +284,6 @@ impl From for Error { } } -#[cfg(feature = "miniserde")] -impl From for Error { - #[inline] - fn from(from: miniserde::Error) -> Self { - Self::Miniserde(from) - } -} - impl From for Error { #[inline] fn from(from: core::num::ParseIntError) -> Self { @@ -365,22 +331,6 @@ impl From for Error { } } -#[cfg(feature = "serde-xml-rs")] -impl From for Error { - #[inline] - fn from(from: serde_xml_rs::Error) -> Self { - Self::SerdeXmlRs(from.into()) - } -} - -#[cfg(feature = "serde_yaml")] -impl From for Error { - #[inline] - fn from(from: serde_yaml::Error) -> Self { - Self::SerdeYaml(from) - } -} - #[cfg(feature = "simd-json")] impl From for Error { #[inline] @@ -389,30 +339,6 @@ impl From for Error { } } -#[cfg(feature = "smoltcp")] -impl From for Error { - #[inline] - fn from(from: smoltcp::socket::tcp::RecvError) -> Self { - Self::SmoltcpTcpRecvError(from) - } -} - -#[cfg(feature = "smoltcp")] -impl From for Error { - #[inline] - fn from(from: smoltcp::socket::tcp::SendError) -> Self { - Self::SmoltcpTcpSendError(from) - } -} - -#[cfg(feature = "embedded-tls")] -impl From for Error { - #[inline] - fn from(from: embedded_tls::TlsError) -> Self { - Self::TlsError(from) - } -} - #[cfg(feature = "tokio")] impl From for Error { #[inline] @@ -429,7 +355,7 @@ impl From for Error { } } -#[cfg(feature = "_tracing-subscriber")] +#[cfg(feature = "tracing-subscriber")] impl From for Error { #[inline] fn from(from: tracing_subscriber::util::TryInitError) -> Self { @@ -510,6 +436,14 @@ impl From for Error { } } +#[cfg(feature = "http-client-framework")] +impl From for Error { + #[inline] + fn from(from: crate::http::HttpClientFrameworkError) -> Self { + Self::HttpClientFrameworkError(from) + } +} + #[cfg(feature = "postgres")] impl From for Error { #[inline] diff --git a/wtx/src/http/client_framework.rs b/wtx/src/http/client_framework.rs index 320a6541..c36d2e76 100644 --- a/wtx/src/http/client_framework.rs +++ b/wtx/src/http/client_framework.rs @@ -1,28 +1,25 @@ mod client_framework_builder; mod client_params; -#[cfg(all( - feature = "_integration-tests", - feature = "tokio-rustls", - feature = "webpki-roots", - test -))] +mod http_client_framework_error; +#[cfg(all(feature = "_integration-tests", feature = "tokio-rustls", test))] mod integration_tests; mod req_builder; use crate::{ http::{Method, ReqResBuffer, ReqResData, ReqUri, Request, Response}, http2::{Http2, Http2Buffer, Http2Data, Http2ErrorCode, Http2Params}, - misc::{LeaseMut, Lock, RefCounter, Stream}, + misc::{Either, LeaseMut, Lock, RefCounter, StreamWriter}, pool::{Pool, ResourceManager, SimplePool, SimplePoolResource}, }; use core::marker::PhantomData; pub use client_framework_builder::ClientFrameworkBuilder; pub(crate) use client_params::ClientParams; +pub use http_client_framework_error::HttpClientFrameworkError; pub use req_builder::ReqBuilder; #[cfg(feature = "tokio")] pub use tokio::ClientFrameworkTokio; -#[cfg(all(feature = "tokio-rustls", feature = "webpki-roots"))] +#[cfg(feature = "tokio-rustls")] pub use tokio_rustls::ClientFrameworkTokioRustls; /// An optioned pool of different HTTP/2 connections lazily constructed from different URIs. @@ -40,10 +37,10 @@ pub struct ClientFrameworkRM { _phantom: PhantomData, } -impl ClientFramework +impl ClientFramework where HD: RefCounter + 'static, - HD::Item: Lock, RRB, S, true>>, + HD::Item: Lock, RRB, SW, true>>, RL: Lock>, RM: ResourceManager< CreateAux = str, @@ -52,14 +49,14 @@ where Resource = Http2, >, RRB: LeaseMut + ReqResData, - S: Stream, + SW: StreamWriter, for<'any> RL: 'any, for<'any> RM: 'any, { /// Closes all active connections #[inline] pub async fn close_all(&self) { - self.pool.into_for_each(|elem| elem.send_go_away(Http2ErrorCode::NoError)).await + self.pool._into_for_each(|elem| elem.send_go_away(Http2ErrorCode::NoError)).await } /// Sends an arbitrary request. @@ -79,8 +76,13 @@ where }; let mut guard = self.pool.get(uri.as_str(), uri.as_str()).await?; let mut stream = guard.stream().await?; - stream.send_req(Request::http2(method, rrb.lease()), actual_req_uri).await?; - let (res_rrb, status_code) = stream.recv_res(rrb).await?; + if stream.send_req(Request::http2(method, rrb.lease()), actual_req_uri).await?.is_none() { + return Err(HttpClientFrameworkError::ClosedConnection.into()); + } + let (res_rrb, status_code) = match stream.recv_res(rrb).await? { + Either::Left(_) => return Err(HttpClientFrameworkError::ClosedConnection.into()), + Either::Right(elem) => elem, + }; Ok(Response::http2(res_rrb, status_code)) } } @@ -96,12 +98,15 @@ mod tokio { misc::UriRef, pool::{ResourceManager, SimplePoolResource}, }; - use tokio::{net::TcpStream, sync::Mutex}; + use tokio::{ + net::{tcp::OwnedWriteHalf, TcpStream}, + sync::Mutex, + }; /// A [`Client`] using the elements of `tokio`. pub type ClientFrameworkTokio = ClientFramework>, ClientFrameworkRM>; - type Instance = Http2Tokio, ReqResBuffer, TcpStream, true>; + type Instance = Http2Tokio, ReqResBuffer, OwnedWriteHalf, true>; impl ClientFrameworkTokio { /// Creates a new builder with the maximum number of connections delimited by `len`. @@ -124,12 +129,14 @@ mod tokio { #[inline] async fn create(&self, aux: &Self::CreateAux) -> Result { let uri = UriRef::new(aux); - Http2Tokio::connect( + let (frame_reader, http2) = Http2Tokio::connect( Http2Buffer::default(), _hp(&self._cp), - TcpStream::connect(uri.host()).await?, + TcpStream::connect(uri.host()).await?.into_split(), ) - .await + .await?; + let _jh = tokio::spawn(frame_reader); + Ok(http2) } #[inline] @@ -146,14 +153,20 @@ mod tokio { let uri = UriRef::new(aux); let mut buffer = Http2Buffer::default(); resource._swap_buffers(&mut buffer).await; - let stream = TcpStream::connect(uri.host()).await?; - *resource = Http2Tokio::connect(buffer, _hp(&self._cp), stream).await?; + let (frame_reader, http2) = Http2Tokio::connect( + buffer, + _hp(&self._cp), + TcpStream::connect(uri.host()).await?.into_split(), + ) + .await?; + let _jh = tokio::spawn(frame_reader); + *resource = http2; Ok(()) } } } -#[cfg(all(feature = "tokio-rustls", feature = "webpki-roots"))] +#[cfg(feature = "tokio-rustls")] mod tokio_rustls { use crate::{ http::{ @@ -164,13 +177,14 @@ mod tokio_rustls { misc::{TokioRustlsConnector, UriRef}, pool::{ResourceManager, SimplePoolResource}, }; - use tokio::{net::TcpStream, sync::Mutex}; + use tokio::{io::WriteHalf, net::TcpStream, sync::Mutex}; use tokio_rustls::client::TlsStream; /// A [`Client`] using the elements of `tokio-rustls`. pub type ClientFrameworkTokioRustls = - ClientFramework>, ClientFrameworkRM>>; - type Instance = Http2Tokio, ReqResBuffer, TlsStream, true>; + ClientFramework>, ClientFrameworkRM>; + type Instance = Http2Tokio, ReqResBuffer, Writer, true>; + type Writer = WriteHalf>; impl ClientFrameworkTokioRustls { /// Creates a new builder with the maximum number of connections delimited by `len`. @@ -179,12 +193,12 @@ mod tokio_rustls { #[inline] pub fn tokio_rustls( len: usize, - ) -> ClientFrameworkBuilder>, TlsStream> { + ) -> ClientFrameworkBuilder>, Writer> { ClientFrameworkBuilder::_new(len) } } - impl ResourceManager for ClientFrameworkRM> { + impl ResourceManager for ClientFrameworkRM { type CreateAux = str; type Error = crate::Error; type RecycleAux = str; @@ -193,15 +207,19 @@ mod tokio_rustls { #[inline] async fn create(&self, aux: &Self::CreateAux) -> Result { let uri = UriRef::new(aux); - Http2Tokio::connect( + let (frame_reader, http2) = Http2Tokio::connect( Http2Buffer::default(), _hp(&self._cp), - TokioRustlsConnector::from_webpki_roots() - .http2() - .with_tcp_stream(uri.host(), uri.hostname()) - .await?, + tokio::io::split( + TokioRustlsConnector::from_auto()? + .http2() + .connect_without_client_auth(uri.hostname(), TcpStream::connect(uri.host()).await?) + .await?, + ), ) - .await + .await?; + let _jh = tokio::spawn(frame_reader); + Ok(http2) } #[inline] @@ -218,11 +236,19 @@ mod tokio_rustls { let uri = UriRef::new(aux); let mut buffer = Http2Buffer::default(); resource._swap_buffers(&mut buffer).await; - let stream = TokioRustlsConnector::from_webpki_roots() - .http2() - .with_tcp_stream(uri.host(), uri.hostname()) - .await?; - *resource = Http2Tokio::connect(buffer, _hp(&self._cp), stream).await?; + let (frame_reader, http2) = Http2Tokio::connect( + Http2Buffer::default(), + _hp(&self._cp), + tokio::io::split( + TokioRustlsConnector::from_auto()? + .http2() + .connect_without_client_auth(uri.hostname(), TcpStream::connect(uri.host()).await?) + .await?, + ), + ) + .await?; + let _jh = tokio::spawn(frame_reader); + *resource = http2; Ok(()) } } diff --git a/wtx/src/http/client_framework/client_framework_builder.rs b/wtx/src/http/client_framework/client_framework_builder.rs index fbdd0bc1..0b69e3ba 100644 --- a/wtx/src/http/client_framework/client_framework_builder.rs +++ b/wtx/src/http/client_framework/client_framework_builder.rs @@ -3,7 +3,7 @@ use crate::{ misc::Lock, pool::{ResourceManager, SimplePool, SimplePoolResource}, }; -use std::marker::PhantomData; +use core::marker::PhantomData; /// Allows the customization of parameters that control HTTP requests and responses. #[derive(Debug)] diff --git a/wtx/src/http/client_framework/http_client_framework_error.rs b/wtx/src/http/client_framework/http_client_framework_error.rs new file mode 100644 index 00000000..603afe15 --- /dev/null +++ b/wtx/src/http/client_framework/http_client_framework_error.rs @@ -0,0 +1,6 @@ +/// Client Framework Error +#[derive(Debug)] +pub enum HttpClientFrameworkError { + /// The remote server closed the connection + ClosedConnection, +} diff --git a/wtx/src/http/client_framework/req_builder.rs b/wtx/src/http/client_framework/req_builder.rs index 9b90689e..332e95f6 100644 --- a/wtx/src/http/client_framework/req_builder.rs +++ b/wtx/src/http/client_framework/req_builder.rs @@ -4,7 +4,7 @@ use crate::{ Response, }, http2::{Http2, Http2Buffer, Http2Data}, - misc::{LeaseMut, Lock, RefCounter, Stream}, + misc::{LeaseMut, Lock, RefCounter, StreamWriter}, pool::{ResourceManager, SimplePoolResource}, }; @@ -38,14 +38,14 @@ where { /// Sends a request with inner parameters. #[inline] - pub async fn send( + pub async fn send( self, client: &ClientFramework, req_uri: impl Into>, ) -> crate::Result> where HD: RefCounter + 'static, - HD::Item: Lock, RRB, S, true>>, + HD::Item: Lock, RRB, SW, true>>, RL: Lock>, RM: ResourceManager< CreateAux = str, @@ -54,7 +54,7 @@ where Resource = Http2, >, RRB: LeaseMut + ReqResData, - S: Stream, + SW: StreamWriter, for<'any> RL: 'any, for<'any> RM: 'any, { diff --git a/wtx/src/http/http_error.rs b/wtx/src/http/http_error.rs index 5e05cbf9..c02beb6d 100644 --- a/wtx/src/http/http_error.rs +++ b/wtx/src/http/http_error.rs @@ -16,6 +16,8 @@ pub enum HttpError { MissingRequestMethod, /// Received response does not contain a status code field MissingResponseStatusCode, + /// Content-Type mismatch + UnexpectedContentType, /// HTTP version does not match the expected method. UnexpectedHttpMethod { /// Expected method diff --git a/wtx/src/http/low_level_server/tokio_http2.rs b/wtx/src/http/low_level_server/tokio_http2.rs index a2e461cc..2540cc43 100644 --- a/wtx/src/http/low_level_server/tokio_http2.rs +++ b/wtx/src/http/low_level_server/tokio_http2.rs @@ -1,7 +1,7 @@ use crate::{ http::{low_level_server::LowLevelServer, ReqResBuffer, Request, Response}, http2::{Http2ErrorCode, Http2Params, Http2Tokio}, - misc::{FnFut, Stream}, + misc::{Either, FnFut, StreamReader, StreamWriter}, }; use tokio::net::{TcpListener, TcpStream}; @@ -10,7 +10,7 @@ type Http2Buffer = crate::http2::Http2Buffer; impl LowLevelServer { /// Optioned HTTP/2 server using tokio. #[inline] - pub async fn tokio_http2( + pub async fn tokio_http2( aux: AUX, addr: &str, err_cb: impl Copy + Fn(E) + Send + 'static, @@ -19,7 +19,7 @@ impl LowLevelServer { http2_params_cb: impl Copy + Fn() -> Http2Params + Send + 'static, stream_buffer_cb: fn() -> crate::Result, (acceptor_cb, local_acceptor_cb, stream_cb): ( - impl FnOnce() -> ACPT + Send + 'static, + impl FnOnce() -> crate::Result + Send + 'static, impl Copy + Fn(&ACPT) -> ACPT + Send + 'static, impl Copy + Fn(ACPT, TcpStream) -> SF + Send + 'static, ), @@ -28,15 +28,12 @@ impl LowLevelServer { ACPT: Send + 'static, AUX: Clone + Send + 'static, E: From + Send + 'static, - S: Send - + Stream< - read(..): Send, - read_exact(..): Send, - read_skip(..): Send, - write_all(..): Send, - write_all_vectored(..): Send, - > + 'static, - SF: Send + Future>, + SR: Send + + StreamReader + + Unpin + + 'static, + SW: Send + StreamWriter + Unpin + 'static, + SF: Send + Future>, F: Copy + FnFut<(AUX, Request), Result, E>> + Send @@ -45,7 +42,7 @@ impl LowLevelServer { for<'handle> &'handle F: Send, { let listener = TcpListener::bind(addr).await?; - let acceptor = acceptor_cb(); + let acceptor = acceptor_cb()?; loop { let http2_buffer = http2_buffer_cb()?; let (tcp_stream, _) = listener.accept().await?; @@ -71,7 +68,7 @@ impl LowLevelServer { } } -async fn manage_conn( +async fn manage_conn( aux: AUX, http2_buffer: Http2Buffer, local_acceptor: ACPT, @@ -85,56 +82,39 @@ async fn manage_conn( where AUX: Clone + Send + 'static, E: From + Send + 'static, - S: Send - + Stream< - read(..): Send, - read_exact(..): Send, - read_skip(..): Send, - write_all(..): Send, - write_all_vectored(..): Send, - > + 'static, - SF: Future> + Send, + SR: Send + + StreamReader + + Unpin + + 'static, + SW: Send + StreamWriter + Unpin + 'static, + SF: Send + Future>, F: Copy + FnFut<(AUX, Request), Result, E>> + Send + 'static, ), Result, E>>>::Future: Send, for<'handle> &'handle F: Send, { - let stream = stream_cb(local_acceptor, tcp_stream).await?; - let mut http2 = Http2Tokio::accept(http2_buffer, http2_params_cb(), stream).await?; + let (frame_reader, mut http2) = Http2Tokio::accept( + http2_buffer, + http2_params_cb(), + stream_cb(local_acceptor, tcp_stream).await?, + ) + .await?; + let _jh = tokio::spawn(async move { + if let Err(err) = frame_reader.await { + err_cb(err.into()); + } + }); loop { - let rslt = http2.stream(stream_buffer_cb()?).await; - let mut http2_stream = match rslt { - Err(err) => match &err { - // Closing a connection without errors - crate::Error::Http2ErrorGoAway(_, None) => { - drop(http2); - return Ok(()); - } - // Closing a connection with unexpected errors - crate::Error::Http2ErrorGoAway(_, Some(_)) => { - drop(http2); - err_cb(E::from(err)); - return Ok(()); - } - // Resetting a stream without errors - crate::Error::Http2ErrorReset(_, None, _) => { - continue; - } - // Resetting a stream with unexpected errors - crate::Error::Http2ErrorReset(_, Some(_), _) => { - err_cb(E::from(err)); - continue; - } - _ => { - drop(http2); - return Err(err); - } - }, - Ok(elem) => elem, + let mut http2_stream = match http2.stream(stream_buffer_cb()?).await { + Either::Left(_) => return Ok(()), + Either::Right(elem) => elem, }; let local_aux = aux.clone(); let _stream_jh = tokio::spawn(async move { let fun = || async move { - let (rrb, method) = http2_stream.recv_req().await?; + let (rrb, method) = match http2_stream.recv_req().await? { + Either::Left(_) => return Ok(()), + Either::Right(elem) => elem, + }; let req = rrb.into_http2_request(method); let res = match handle_cb((local_aux, req)).await { Err(err) => { @@ -143,7 +123,9 @@ where } Ok(elem) => elem, }; - http2_stream.send_res(res).await?; + if http2_stream.send_res(res).await?.is_none() { + return Ok(()); + } Ok::<_, E>(()) }; if let Err(err) = fun().await { diff --git a/wtx/src/http/server_framework.rs b/wtx/src/http/server_framework.rs index fbd8a6b0..62f476a5 100644 --- a/wtx/src/http/server_framework.rs +++ b/wtx/src/http/server_framework.rs @@ -16,15 +16,15 @@ use crate::{ http2::{Http2Buffer, Http2Params}, rng::StdRng, }; -use core::fmt::Debug; +use alloc::sync::Arc; +use core::{fmt::Debug, marker::PhantomData}; pub use middlewares::{ReqMiddlewares, ResMiddlewares}; pub use path::Path; pub use path_fun::PathFun; pub use path_management::PathManagement; pub use paths::Paths; pub use router::Router; -use std::{marker::PhantomData, sync::Arc}; -pub use wrappers::{get, post, Get, Post}; +pub use wrappers::{get, json, post, Get, Json, Post}; /// Server #[derive(Debug)] @@ -56,28 +56,46 @@ where host: &str, err_cb: impl Copy + Fn(E) + Send + 'static, ) -> crate::Result<()> { - async fn handle( - (router, req): (Arc>, Request), - ) -> Result, E> - where - E: Debug + From + Send + 'static, - P: Send + 'static, - REQM: ReqMiddlewares + Send + 'static, - RESM: ResMiddlewares + Send + 'static, - Arc>: Send, - Router: PathManagement, - { - router.manage_path(true, "", req, [0, 0]).await - } LowLevelServer::tokio_http2( Arc::clone(&self.router), host, err_cb, - handle, + Self::handle, || Ok(Http2Buffer::new(StdRng::default())), move || Http2Params::default().set_max_recv_streams_num(self.max_recv_streams_num), || Ok(ReqResBuffer::default()), - (|| {}, |_| {}, |_, stream| async move { Ok(stream) }), + (|| Ok(()), |_| {}, |_, stream| async move { Ok(stream.into_split()) }), + ) + .await + } + + /// Starts listening to incoming encrypted requests based on the given `host`. + #[cfg(feature = "tokio-rustls")] + #[inline] + pub async fn listen_tls( + self, + cert_chain: &'static [u8], + host: &str, + priv_key: &'static [u8], + err_cb: impl Copy + Fn(E) + Send + 'static, + ) -> crate::Result<()> { + LowLevelServer::tokio_http2( + Arc::clone(&self.router), + host, + err_cb, + Self::handle, + || Ok(Http2Buffer::new(StdRng::default())), + move || Http2Params::default().set_max_recv_streams_num(self.max_recv_streams_num), + || Ok(ReqResBuffer::default()), + ( + || { + crate::misc::TokioRustlsAcceptor::without_client_auth() + .http2() + .build_with_cert_chain_and_priv_key(cert_chain, priv_key) + }, + |acceptor| acceptor.clone(), + |acceptor, stream| async move { Ok(tokio::io::split(acceptor.accept(stream).await?)) }, + ), ) .await } @@ -91,6 +109,20 @@ where self.max_recv_streams_num = elem; self } + + async fn handle( + (router, req): (Arc>, Request), + ) -> Result, E> + where + E: Debug + From + Send + 'static, + P: Send + 'static, + REQM: ReqMiddlewares + Send + 'static, + RESM: ResMiddlewares + Send + 'static, + Arc>: Send, + Router: PathManagement, + { + router.manage_path(true, "", req, [0, 0]).await + } } #[cfg(test)] diff --git a/wtx/src/http/server_framework/middlewares.rs b/wtx/src/http/server_framework/middlewares.rs index ff4223f2..a4dbc0fd 100644 --- a/wtx/src/http/server_framework/middlewares.rs +++ b/wtx/src/http/server_framework/middlewares.rs @@ -1,4 +1,7 @@ -use crate::http::{Request, Response}; +use crate::{ + http::{Request, Response}, + misc::FnFut, +}; /// Requests middlewares pub trait ReqMiddlewares @@ -9,6 +12,18 @@ where fn apply_req_middlewares(&self, _: &mut Request) -> impl Future>; } +impl ReqMiddlewares for &T +where + E: From, + T: for<'any> FnFut<&'any mut Request, Result<(), E>>, +{ + #[inline] + async fn apply_req_middlewares(&self, req: &mut Request) -> Result<(), E> { + (*self)(req).await?; + Ok(()) + } +} + impl ReqMiddlewares for () where E: From, @@ -19,6 +34,20 @@ where } } +impl ReqMiddlewares for [T] +where + E: From, + T: for<'any> FnFut<&'any mut Request, Result<(), E>>, +{ + #[inline] + async fn apply_req_middlewares(&self, req: &mut Request) -> Result<(), E> { + for elem in self { + (elem)(req).await?; + } + Ok(()) + } +} + /// Responses middlewares pub trait ResMiddlewares where @@ -28,6 +57,18 @@ where fn apply_res_middlewares(&self, _: &mut Response) -> impl Future>; } +impl ResMiddlewares for &T +where + E: From, + T: for<'any> FnFut<&'any mut Response, Result<(), E>>, +{ + #[inline] + async fn apply_res_middlewares(&self, req: &mut Response) -> Result<(), E> { + (*self)(req).await?; + Ok(()) + } +} + impl ResMiddlewares for () where E: From, @@ -37,3 +78,17 @@ where Ok(()) } } + +impl ResMiddlewares for [T] +where + E: From, + T: for<'any> FnFut<&'any mut Response, Result<(), E>>, +{ + #[inline] + async fn apply_res_middlewares(&self, req: &mut Response) -> Result<(), E> { + for elem in self { + (elem)(req).await?; + } + Ok(()) + } +} diff --git a/wtx/src/http/server_framework/path_fun.rs b/wtx/src/http/server_framework/path_fun.rs index 8a3fef57..26b36679 100644 --- a/wtx/src/http/server_framework/path_fun.rs +++ b/wtx/src/http/server_framework/path_fun.rs @@ -14,6 +14,21 @@ pub trait PathFun { ) -> impl Future, E>>; } +impl PathFun for &T +where + T: PathFun, +{ + #[inline] + async fn call( + &self, + matching_path: &'static str, + req: Request, + req_path_indcs: [usize; 2], + ) -> Result, E> { + (*self).call(matching_path, req, req_path_indcs).await + } +} + impl PathFun for fn(Request) -> FUT where FUT: Future, E>>, @@ -44,10 +59,10 @@ where ) -> Result, E> { let uri = req.rrd.uri(); let req_path = uri.as_str().get(begin..).unwrap_or_default().as_bytes(); - let elem: &[u8] = bytes_pos1(matching_path.as_bytes(), b'{') - .and_then(|bracket_begin| { - let (mp_before, _) = matching_path.as_bytes().split_at_checked(bracket_begin)?; - let (rp_before, rp_after) = req_path.split_at_checked(bracket_begin)?; + let elem: &[u8] = bytes_pos1(matching_path.as_bytes(), b':') + .and_then(|colon_begin| { + let (mp_before, _) = matching_path.as_bytes().split_at_checked(colon_begin)?; + let (rp_before, rp_after) = req_path.split_at_checked(colon_begin)?; if mp_before != rp_before { return None; } diff --git a/wtx/src/http/server_framework/path_management.rs b/wtx/src/http/server_framework/path_management.rs index a577bfd1..3db5bf08 100644 --- a/wtx/src/http/server_framework/path_management.rs +++ b/wtx/src/http/server_framework/path_management.rs @@ -1,4 +1,4 @@ -use crate::http::{Request, Response}; +use crate::http::{server_framework::Path, HttpError, ReqResData, Request, Response}; /// Used by all structures that somehow interact with incoming requests. pub trait PathManagement @@ -31,3 +31,28 @@ where (*self).manage_path(is_init, matching_path, req, req_path_indcs).await } } + +impl PathManagement for [Path] +where + E: From, + RRD: ReqResData, + T: PathManagement, +{ + #[inline] + async fn manage_path( + &self, + is_init: bool, + matching_path: &'static str, + req: Request, + [begin, end]: [usize; 2], + ) -> Result, E> { + let req_uri = req.rrd.uri(); + let req_path = req_uri.as_str().get(begin..end).unwrap_or_default(); + for elem in self { + if elem.name.starts_with(req_path) { + return elem.value.manage_path(is_init, matching_path, req, [begin, end]).await; + } + } + Err(E::from(HttpError::UriMismatch.into())) + } +} diff --git a/wtx/src/http/server_framework/wrappers.rs b/wtx/src/http/server_framework/wrappers.rs index 197d36de..d1e6ef04 100644 --- a/wtx/src/http/server_framework/wrappers.rs +++ b/wtx/src/http/server_framework/wrappers.rs @@ -1,6 +1,6 @@ use crate::http::{ server_framework::{PathFun, PathManagement}, - HttpError, Method, Request, Response, + HttpError, KnownHeaderName, Method, Mime, ReqResData, Request, Response, }; /// Requires a request of type `GET`. @@ -37,6 +37,49 @@ pub fn get(f: fn(I) -> O) -> Get O> { Get(f) } +/// Requires a request of type `POST` with json MIME. +#[derive(Debug)] +pub struct Json( + /// Path Function + pub PF, +); + +impl PathManagement for Json +where + E: From, + PF: PathFun, + RRD: ReqResData, +{ + #[inline] + async fn manage_path( + &self, + _: bool, + matching_path: &'static str, + req: Request, + req_path_indcs: [usize; 2], + ) -> Result, E> { + if req + .rrd + .headers() + .get_by_name(KnownHeaderName::ContentType.into()) + .map_or(true, |el| el.value == Mime::Json.as_str().as_bytes()) + { + return Err(E::from(crate::Error::from(HttpError::UnexpectedContentType))); + } + if req.method != Method::Post { + return Err(E::from(crate::Error::from(HttpError::UnexpectedHttpMethod { + expected: Method::Post, + }))); + } + self.0.call(matching_path, req, req_path_indcs).await + } +} + +/// Creates a new [`Json`] instance with type inference. +pub fn json(f: fn(I) -> O) -> Json O> { + Json(f) +} + /// Requires a request of type `POST`. #[derive(Debug)] pub struct Post( diff --git a/wtx/src/http2.rs b/wtx/src/http2.rs index 1772fe11..9f4a97f9 100644 --- a/wtx/src/http2.rs +++ b/wtx/src/http2.rs @@ -15,6 +15,7 @@ mod common_flags; mod continuation_frame; mod data_frame; mod frame_init; +mod frame_reader; mod go_away_frame; mod headers_frame; mod hpack_decoder; @@ -46,17 +47,24 @@ mod window; mod window_update_frame; use crate::{ - http::{HttpError, ReqResBuffer, StatusCode}, - http2::misc::{ - process_higher_operation_err, protocol_err, read_header_and_continuations, - server_header_stream_state, + http::ReqResBuffer, + http2::misc::{manage_initial_stream_receiving, process_higher_operation_err, protocol_err}, + misc::{ + ConnectionState, Either, LeaseMut, Lock, PartitionedFilledBuffer, RefCounter, StreamReader, + StreamWriter, Usize, }, - misc::{ConnectionState, LeaseMut, Lock, RefCounter, Stream, Usize, _Span}, }; +use alloc::sync::Arc; pub use client_stream::ClientStream; pub(crate) use common_flags::CommonFlags; pub(crate) use continuation_frame::ContinuationFrame; -use core::{mem, time::Duration}; +use core::{ + future::poll_fn, + mem, + pin::pin, + sync::atomic::{AtomicBool, Ordering}, + task::{Poll, Waker}, +}; pub(crate) use data_frame::DataFrame; pub(crate) use frame_init::{FrameInit, FrameInitTy}; pub(crate) use go_away_frame::GoAwayFrame; @@ -94,49 +102,47 @@ pub(crate) const MAX_FRAME_LEN_UPPER_BOUND: u32 = max_frame_len_upper_bound!(); pub(crate) const MAX_RECV_STREAMS_NUM: u32 = max_recv_streams_num!(); pub(crate) const READ_BUFFER_LEN: u32 = read_buffer_len!(); -const MAX_FINAL_DURATION: Duration = Duration::from_millis(300); -const MAX_FINAL_FETCHES: u8 = 64; const PREFACE: &[u8; 24] = b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"; /// Http2 instance using the mutex from tokio. #[cfg(feature = "tokio")] -pub type Http2Tokio = - Http2, IS_CLIENT>; +pub type Http2Tokio = + Http2, IS_CLIENT>; /// Http2Data instance using the mutex from tokio. #[cfg(feature = "tokio")] -pub type Http2DataTokio = - alloc::sync::Arc>>; +pub type Http2DataTokio = + Arc>>; -pub(crate) type Sorp = HashMap>; +pub(crate) type IsConnOpenSync = Arc; pub(crate) type Scrp = HashMap; +pub(crate) type Sorp = HashMap>; /// Negotiates initial "handshakes" or connections and also manages the creation of streams. #[derive(Debug)] pub struct Http2 { hd: HD, + is_conn_open: IsConnOpenSync, } -impl Http2 +impl Http2 where HB: LeaseMut>, HD: RefCounter, - HD::Item: Lock>, + HD::Item: Lock>, RRB: LeaseMut, - S: Stream, + SW: StreamWriter, { /// See [ConnectionState]. #[inline] pub async fn connection_state(&self) -> ConnectionState { - ConnectionState::from(self.hd.lock().await.is_conn_open()) + ConnectionState::from(self.is_conn_open.load(Ordering::Relaxed)) } /// Sends a GOAWAY frame to the peer, which cancels the connection and consequently all ongoing /// streams. #[inline] pub async fn send_go_away(self, error_code: Http2ErrorCode) { - let mut guard = self.hd.lock().await; - let hdpm = guard.parts_mut(); - misc::send_go_away(error_code, hdpm.is_conn_open, *hdpm.last_stream_id, hdpm.stream).await; + misc::send_go_away(error_code, &mut self.hd.lock().await.parts_mut()).await; } #[inline] @@ -145,131 +151,139 @@ where } #[inline] - async fn apply_initial_params( + async fn manage_initial_params( hb: &mut Http2Buffer, - has_preface: bool, hp: &Http2Params, - stream: &mut S, - ) -> crate::Result<()> { + stream_writer: &mut SW, + ) -> crate::Result<(IsConnOpenSync, u32, PartitionedFilledBuffer)> { let sf = hp.to_settings_frame(); if hp.initial_window_len() != initial_window_len!() { let wuf = WindowUpdateFrame::new( hp.initial_window_len().wrapping_sub(initial_window_len!()).into(), U31::ZERO, )?; - if has_preface { - stream.write_all_vectored(&[PREFACE, sf.bytes(&mut [0; 45]), &wuf.bytes()]).await?; + if HAS_PREFACE { + stream_writer.write_all_vectored(&[PREFACE, sf.bytes(&mut [0; 45]), &wuf.bytes()]).await?; } else { - stream.write_all_vectored(&[sf.bytes(&mut [0; 45]), &wuf.bytes()]).await?; + stream_writer.write_all_vectored(&[sf.bytes(&mut [0; 45]), &wuf.bytes()]).await?; } } else { - if has_preface { - stream.write_all_vectored(&[PREFACE, sf.bytes(&mut [0; 45])]).await?; + if HAS_PREFACE { + stream_writer.write_all_vectored(&[PREFACE, sf.bytes(&mut [0; 45])]).await?; } else { - stream.write_all(sf.bytes(&mut [0; 45])).await?; + stream_writer.write_all(sf.bytes(&mut [0; 45])).await?; } } hb.hpack_dec.set_max_bytes(hp.max_hpack_len().0); hb.hpack_enc.set_max_dyn_super_bytes(hp.max_hpack_len().1); hb.pfb._expand_buffer(*Usize::from(hp.read_buffer_len()))?; - Ok(()) + hb.is_conn_open.store(true, Ordering::Relaxed); + Ok((Arc::clone(&hb.is_conn_open), hp.max_frame_len(), mem::take(&mut hb.pfb))) } } -impl Http2 +impl Http2 where HB: LeaseMut>, HD: RefCounter, - HD::Item: Lock>, + HD::Item: Lock>, RRB: LeaseMut, - S: Stream, + SW: StreamWriter, { /// Accepts an initial connection sending the local parameters to the remote peer. #[inline] - pub async fn accept(mut hb: HB, hp: Http2Params, mut stream: S) -> crate::Result { + pub async fn accept( + mut hb: HB, + hp: Http2Params, + (mut stream_reader, mut stream_writer): (SR, SW), + ) -> crate::Result<(impl Future>, Self)> + where + SR: StreamReader, + { hb.lease_mut().clear(); let mut buffer = [0; 24]; - stream.read_exact(&mut buffer).await?; + stream_reader.read_exact(&mut buffer).await?; if &buffer != PREFACE { - misc::send_go_away(Http2ErrorCode::ProtocolError, &mut true, U31::ZERO, &mut stream).await; + let _rslt = stream_writer + .write_all(&GoAwayFrame::new(Http2ErrorCode::ProtocolError, U31::ZERO).bytes()) + .await; return Err(protocol_err(Http2Error::NoPreface)); } - Self::apply_initial_params(hb.lease_mut(), false, &hp, &mut stream).await?; - Ok(Self { hd: HD::new(HD::Item::new(Http2Data::new(hb, hp, stream))) }) + let (is_conn_open, max_frame_len, pfb) = + Self::manage_initial_params::(hb.lease_mut(), &hp, &mut stream_writer).await?; + let hd = HD::new(HD::Item::new(Http2Data::new(hb, hp, stream_writer))); + let this = Self { hd: hd.clone(), is_conn_open: Arc::clone(&is_conn_open) }; + Ok((frame_reader::frame_reader(hd, is_conn_open, max_frame_len, pfb, stream_reader), this)) } /// Awaits for an initial header to create a stream. + /// + /// Returns [`Either::Left`] if the network connection has been closed, either locally + /// or externally. #[inline] - pub async fn stream(&mut self, mut rrb: RRB) -> crate::Result> { - rrb.lease_mut().clear(); - process_higher_operation!( - &self.hd, - |guard| { - let rslt = 'rslt: { - let hdpm = guard.parts_mut(); - let Some(fi) = hdpm.hb.initial_server_header.take() else { - break 'rslt Ok(None); - }; - rrb.lease_mut().headers_mut().set_max_bytes(*Usize::from(hdpm.hp.max_headers_len())); - let fut = read_header_and_continuations::<_, _, false, false>( - fi, - hdpm.hp, - &mut hdpm.hb.hpack_dec, - hdpm.is_conn_open, - &mut hdpm.hb.pfb, - rrb.lease_mut(), - hdpm.stream, - &mut hdpm.hb.uri_buffer, - |hf| hf.hsreqh().method.ok_or_else(|| HttpError::MissingRequestMethod.into()), - ); - match fut.await { - Err(err) => break 'rslt Err(err), - Ok(elem) => Ok(Some((elem.0, fi, elem.1, elem.2))), - } + pub async fn stream(&mut self, rrb: RRB) -> Either, ServerStream> { + let Self { hd, is_conn_open } = self; + let rrb_opt = &mut Some(rrb); + let mut lock_pin = pin!(hd.lock()); + match poll_fn(|cx| { + let mut lock = lock_pin!(cx, hd, lock_pin); + let hdpm = lock.parts_mut(); + if let Some(mut elem) = rrb_opt.take() { + if !manage_initial_stream_receiving(&hdpm, &is_conn_open, &mut elem) { + return Poll::Ready(Either::Left(Some(elem))); + } + hdpm.hb.initial_server_header_buffers.push_back((elem, cx.waker().clone())); + Poll::Pending + } else { + if !is_conn_open.load(Ordering::Relaxed) { + return Poll::Ready(Either::Left( + hdpm.hb.initial_server_header_buffers.pop_front().map(|el| el.0), + )); + } + let Some((method, stream_id)) = hdpm.hb.initial_server_header_params.pop_front() else { + return Poll::Pending; }; - rslt - }, - |guard, elem| { - let (content_length, fi, has_eos, method) = elem; - let hdpm = guard.parts_mut(); - drop(hdpm.hb.sorp.insert( - fi.stream_id, - StreamOverallRecvParams { - body_len: 0, - content_length, - has_initial_header: true, - rrb, - span: _Span::_none(), - status_code: StatusCode::Ok, - stream_state: server_header_stream_state(has_eos), - windows: Windows::initial(hdpm.hp, hdpm.hps), - }, - )); - Ok(ServerStream::new( - self.hd.clone(), - method, - _trace_span!("Creating server stream", stream_id = fi.stream_id.u32()), - fi.stream_id, - )) + Poll::Ready(Either::Right((method, stream_id))) } - ) + }) + .await + { + Either::Left(elem) => Either::Left(elem), + Either::Right((method, stream_id)) => Either::Right(ServerStream::new( + hd.clone(), + Arc::clone(&is_conn_open), + method, + _trace_span!("New server stream", stream_id = %stream_id), + stream_id, + )), + } } } -impl Http2 +impl Http2 where HB: LeaseMut>, HD: RefCounter, - HD::Item: Lock>, + HD::Item: Lock>, RRB: LeaseMut, - S: Stream, + SW: StreamWriter, { /// Tries to connect to a server sending the local parameters. #[inline] - pub async fn connect(mut hb: HB, hp: Http2Params, mut stream: S) -> crate::Result { + pub async fn connect( + mut hb: HB, + hp: Http2Params, + (stream_reader, mut stream_writer): (SR, SW), + ) -> crate::Result<(impl Future>, Self)> + where + SR: StreamReader, + { hb.lease_mut().clear(); - Self::apply_initial_params(hb.lease_mut(), true, &hp, &mut stream).await?; - Ok(Self { hd: HD::new(HD::Item::new(Http2Data::new(hb, hp, stream))) }) + let (is_conn_open, max_frame_len, pfb) = + Self::manage_initial_params::(hb.lease_mut(), &hp, &mut stream_writer).await?; + let hd = HD::new(HD::Item::new(Http2Data::new(hb, hp, stream_writer))); + let this = Self { hd: hd.clone(), is_conn_open: Arc::clone(&is_conn_open) }; + Ok((frame_reader::frame_reader(hd, is_conn_open, max_frame_len, pfb, stream_reader), this)) } /// Opens a local stream. @@ -278,22 +292,24 @@ where let hdpm = guard.parts_mut(); if hdpm.hb.sorp.len() >= *Usize::from(hdpm.hp.max_concurrent_streams_num()) { drop(guard); - let err = Http2Error::ExceedAmountOfActiveConcurrentStreams; - return Err(process_higher_operation_err(protocol_err(err), &self.hd).await); + let err = protocol_err(Http2Error::ExceedAmountOfActiveConcurrentStreams); + process_higher_operation_err(&err, &self.hd).await; + return Err(err); } let stream_id = *hdpm.last_stream_id; - let span = _trace_span!("Creating client stream", stream_id = stream_id.u32()); + let span = _trace_span!("New client stream", stream_id = %stream_id); drop(hdpm.hb.scrp.insert( stream_id, StreamControlRecvParams { - span: span.clone(), + is_stream_open: true, stream_state: StreamState::Idle, + waker: Waker::noop().clone(), windows: Windows::initial(hdpm.hp, hdpm.hps), }, )); *hdpm.last_stream_id = hdpm.last_stream_id.wrapping_add(U31::TWO); drop(guard); - Ok(ClientStream::new(self.hd.clone(), span, stream_id)) + Ok(ClientStream::new(self.hd.clone(), Arc::clone(&self.is_conn_open), span, stream_id)) } } @@ -303,6 +319,6 @@ where { #[inline] fn clone(&self) -> Self { - Self { hd: self.hd.clone() } + Self { hd: self.hd.clone(), is_conn_open: Arc::clone(&self.is_conn_open) } } } diff --git a/wtx/src/http2/client_stream.rs b/wtx/src/http2/client_stream.rs index 4fa02d68..ac4567d3 100644 --- a/wtx/src/http2/client_stream.rs +++ b/wtx/src/http2/client_stream.rs @@ -1,18 +1,23 @@ use crate::{ http::{ReqResBuffer, ReqResData, ReqUri, Request, StatusCode}, http2::{ - misc::{check_content_length, send_go_away, send_reset_stream}, + misc::{ + manage_initial_stream_receiving, manage_recurrent_stream_receiving, + process_higher_operation_err, send_go_away, send_reset_stream, + }, send_msg::send_msg, HpackStaticRequestHeaders, HpackStaticResponseHeaders, Http2Buffer, Http2Data, Http2ErrorCode, - StreamOverallRecvParams, StreamState, Windows, U31, + IsConnOpenSync, StreamOverallRecvParams, StreamState, Windows, U31, }, - misc::{Lease, LeaseMut, Lock, RefCounter, Stream, Usize, _Span}, + misc::{Either, Lease, LeaseMut, Lock, RefCounter, StreamWriter, _Span}, }; +use core::{future::poll_fn, pin::pin, task::Poll}; /// Groups the methods used by clients that connect to servers. #[derive(Debug)] pub struct ClientStream { hd: HD, + is_conn_open: IsConnOpenSync, span: _Span, stream_id: U31, // Used after the initial sending @@ -20,91 +25,97 @@ pub struct ClientStream { } impl ClientStream { - pub(crate) const fn new(hd: HD, span: _Span, stream_id: U31) -> Self { - Self { hd, span, stream_id, windows: Windows::new() } + #[inline] + pub(crate) const fn new( + hd: HD, + is_conn_open: IsConnOpenSync, + span: _Span, + stream_id: U31, + ) -> Self { + Self { hd, is_conn_open, span, stream_id, windows: Windows::new() } } } -impl ClientStream +impl ClientStream where HB: LeaseMut>, HD: RefCounter, - HD::Item: Lock>, + HD::Item: Lock>, RRB: LeaseMut, - S: Stream, + SW: StreamWriter, { /// Receive response /// /// Higher operation that awaits for the data necessary to build a response and then closes the /// stream. /// + /// Returns [`Either::Left`] if the network/stream connection has been closed, either locally + /// or externally. + /// /// Should be called after [`Self::send_req`] is successfully executed. #[inline] - pub async fn recv_res(self, mut rrb: RRB) -> crate::Result<(RRB, StatusCode)> { - let _e = self.span._enter(); + pub async fn recv_res(mut self, rrb: RRB) -> crate::Result> { + let rrb_opt = &mut Some(rrb); + let Self { hd, is_conn_open, span, stream_id, windows } = &mut self; + let _e = span._enter(); _trace!("Receiving response"); - { - let mut guard = self.hd.lock().await; - let hdpm = guard.parts_mut(); - rrb.lease_mut().clear(); - rrb.lease_mut().headers_mut().set_max_bytes(*Usize::from(hdpm.hp.max_headers_len())); - drop(hdpm.hb.sorp.insert( - self.stream_id, - StreamOverallRecvParams { - body_len: 0, - content_length: None, - has_initial_header: false, - rrb, - span: _Span::_none(), - status_code: StatusCode::Ok, - stream_state: StreamState::HalfClosedLocal, - windows: self.windows, - }, - )); + let mut lock_pin = pin!(hd.lock()); + let rslt = poll_fn(|cx| { + let mut lock = lock_pin!(cx, hd, lock_pin); + let hdpm = lock.parts_mut(); + if let Some(mut elem) = rrb_opt.take() { + if !manage_initial_stream_receiving(&hdpm, is_conn_open, &mut elem) { + return Poll::Ready(Ok(Either::Left(elem))); + } + drop(hdpm.hb.sorp.insert( + *stream_id, + StreamOverallRecvParams { + body_len: 0, + content_length: None, + has_initial_header: false, + is_stream_open: true, + rrb: elem, + status_code: StatusCode::Ok, + stream_state: StreamState::HalfClosedLocal, + waker: cx.waker().clone(), + windows: *windows, + }, + )); + Poll::Pending + } else { + manage_recurrent_stream_receiving(cx, hdpm, is_conn_open, stream_id, |_, _, sorp| { + sorp.status_code + }) + } + }) + .await; + if let Err(err) = &rslt { + process_higher_operation_err(&err, hd).await; } - process_higher_operation!( - &self.hd, - |guard| { - let rslt = 'rslt: { - let hdpm = guard.parts_mut(); - if hdpm.hb.sorp.get(&self.stream_id).map_or(false, |el| el.stream_state.recv_eos()) { - if let Some(sorp) = hdpm.hb.sorp.remove(&self.stream_id) { - if let Some(idx) = sorp.content_length { - if let Err(err) = check_content_length(idx, &sorp) { - break 'rslt Err(err); - } - } - break 'rslt Ok(Some((sorp.rrb, sorp.status_code))); - } - } - Ok(None) - }; - rslt - }, - |_guard, elem| Ok(elem) - ) + rslt } /// Sends a GOAWAY frame to the peer, which cancels the connection and consequently all ongoing /// streams. #[inline] pub async fn send_go_away(self, error_code: Http2ErrorCode) { - let mut guard = self.hd.lock().await; - let hdpm = guard.parts_mut(); - send_go_away(error_code, hdpm.is_conn_open, *hdpm.last_stream_id, hdpm.stream).await; + send_go_away(error_code, &mut self.hd.lock().await.parts_mut()).await; } /// Send Request /// /// Higher operation that sends all data related to a request. /// + /// Returns [`Option::None`] if the network/stream connection has been closed, either locally + /// or externally. + /// /// Shouldn't be called more than once. #[inline] pub async fn send_req( &mut self, req: Request, req_uri: impl Into>, - ) -> crate::Result<()> + ) -> crate::Result> where RRD: ReqResData, RRD::Body: Lease<[u8]>, @@ -129,10 +140,11 @@ where }, HpackStaticResponseHeaders::EMPTY, ), + &self.is_conn_open, self.stream_id, |hdpm| { - if let Some(elem) = hdpm.hb.scrp.remove(&self.stream_id) { - self.windows = elem.windows; + if let Some(scrp) = hdpm.hb.scrp.remove(&self.stream_id) { + self.windows = scrp.windows; } }, ) @@ -143,6 +155,13 @@ where pub async fn send_reset(self, error_code: Http2ErrorCode) { let mut guard = self.hd.lock().await; let hdpm = guard.parts_mut(); - send_reset_stream(error_code, hdpm.hb, hdpm.stream, self.stream_id).await; + let _ = send_reset_stream( + error_code, + &mut hdpm.hb.scrp, + &mut hdpm.hb.sorp, + hdpm.stream_writer, + self.stream_id, + ) + .await; } } diff --git a/wtx/src/http2/frame_reader.rs b/wtx/src/http2/frame_reader.rs new file mode 100644 index 00000000..106be71c --- /dev/null +++ b/wtx/src/http2/frame_reader.rs @@ -0,0 +1,188 @@ +macro_rules! prft { + ($fi:expr, $hdpm:ident, $is_conn_open:expr, $pfb:expr, $stream_reader:expr) => { + ProcessReceiptFrameTy { + conn_windows: &mut $hdpm.windows, + fi: $fi, + hp: &mut $hdpm.hp, + hpack_dec: &mut $hdpm.hb.hpack_dec, + hps: &mut $hdpm.hps, + is_conn_open: $is_conn_open, + last_stream_id: &mut $hdpm.last_stream_id, + pfb: $pfb, + phantom: PhantomData, + recv_streams_num: &mut $hdpm.recv_streams_num, + stream_reader: $stream_reader, + stream_writer: &mut $hdpm.stream_writer, + uri_buffer: &mut $hdpm.hb.uri_buffer, + } + }; +} + +use crate::{ + http::ReqResBuffer, + http2::{ + misc::{process_higher_operation_err, protocol_err, read_frame_until}, + FrameInitTy, Http2Buffer, Http2Data, Http2Error, IsConnOpenSync, ProcessReceiptFrameTy, + }, + misc::{ + GenericTime, LeaseMut, Lock, PartitionedFilledBuffer, RefCounter, StreamReader, StreamWriter, + }, +}; +use core::{ + future::poll_fn, marker::PhantomData, mem, pin::pin, sync::atomic::AtomicBool, task::Poll, + time::Duration, +}; + +pub(crate) async fn frame_reader( + hd: HD, + is_conn_open: IsConnOpenSync, + max_frame_len: u32, + mut pfb: PartitionedFilledBuffer, + mut stream_reader: SR, +) -> crate::Result<()> +where + HB: LeaseMut>, + HD: RefCounter, + HD::Item: Lock>, + RRB: LeaseMut, + SR: StreamReader, + SW: StreamWriter, +{ + let span = _trace_span!("Starting the reading of frames"); + let _e = span._enter(); + let mut params: Option<(crate::Error, GenericTime)> = None; + loop { + let rslt = if let Some((error, timeout)) = params.take() { + if timeout.elapsed().map_or(true, |elapsed| elapsed >= Duration::from_millis(300)) { + finish(&error, &hd, &mut pfb).await; + return Err(error); + } else { + params = Some((error, timeout)); + } + read(&hd, &is_conn_open, max_frame_len, &mut pfb, &mut stream_reader).await + } else { + read(&hd, &is_conn_open, max_frame_len, &mut pfb, &mut stream_reader).await + }; + match rslt { + Ok(_) => {} + Err(rslt_error @ crate::Error::Http2ErrorGoAway(_, None)) => { + if params.is_none() { + params = Some((rslt_error, GenericTime::now())) + } + } + Err(rslt_error) => { + finish(&rslt_error, &hd, &mut pfb).await; + return Err(rslt_error); + } + } + } +} + +#[inline] +async fn read( + hd: &HD, + is_conn_open: &AtomicBool, + max_frame_len: u32, + mut pfb: &mut PartitionedFilledBuffer, + stream_reader: &mut SR, +) -> crate::Result<()> +where + HB: LeaseMut>, + HD: RefCounter, + HD::Item: Lock>, + RRB: LeaseMut, + SR: StreamReader, + SW: StreamWriter, +{ + let fi = read_frame_until(hd, is_conn_open, max_frame_len, pfb, stream_reader).await?; + match fi.ty { + FrameInitTy::Data => { + let mut lock = hd.lock().await; + let mut hdpm = lock.parts_mut(); + prft!(fi, hdpm, &*is_conn_open, &mut pfb, stream_reader).data(&mut hdpm.hb.sorp).await?; + } + FrameInitTy::Headers => { + let mut lock = hd.lock().await; + let mut hdpm = lock.parts_mut(); + if hdpm.hb.scrp.contains_key(&fi.stream_id) { + return Err(protocol_err(Http2Error::UnexpectedNonControlFrame)); + } + if IS_CLIENT { + prft!(fi, hdpm, &*is_conn_open, &mut pfb, stream_reader) + .header_client(&mut hdpm.hb.sorp) + .await?; + } else { + if let Some(elem) = hdpm.hb.sorp.get_mut(&fi.stream_id) { + prft!(fi, hdpm, &*is_conn_open, &mut pfb, stream_reader) + .header_server_trailer(elem) + .await?; + } else { + if let Some((rrb, waker)) = hdpm.hb.initial_server_header_buffers.pop_front() { + let rslt = prft!(fi, hdpm, &*is_conn_open, &mut pfb, stream_reader) + .header_server_init(&mut hdpm.hb.initial_server_header_params, rrb, &mut hdpm.hb.sorp) + .await; + waker.wake(); + rslt?; + } else { + drop(lock); + let mut lock_pin = pin!(hd.lock()); + let (mut local_lock, rrb, waker) = poll_fn(|cx| { + let mut local_lock = lock_pin!(cx, hd, lock_pin); + let local_hdpm = local_lock.parts_mut(); + let Some((rrb, waker)) = local_hdpm.hb.initial_server_header_buffers.pop_front() + else { + cx.waker().wake_by_ref(); + return Poll::Pending; + }; + Poll::Ready((local_lock, rrb, waker)) + }) + .await; + let mut local_hdpm = local_lock.parts_mut(); + let rslt = prft!(fi, local_hdpm, &*is_conn_open, &mut pfb, stream_reader) + .header_server_init( + &mut local_hdpm.hb.initial_server_header_params, + rrb, + &mut local_hdpm.hb.sorp, + ) + .await; + waker.wake(); + rslt?; + } + } + } + } + FrameInitTy::Reset => { + let mut lock = hd.lock().await; + let mut hdpm = lock.parts_mut(); + let prft = prft!(fi, hdpm, &*is_conn_open, &mut pfb, stream_reader); + prft.reset(&mut hdpm.hb.scrp, &mut hdpm.hb.sorp).await?; + } + FrameInitTy::WindowUpdate if fi.stream_id.is_not_zero() => { + let mut lock = hd.lock().await; + let mut hdpm = lock.parts_mut(); + let prft = prft!(fi, hdpm, &*is_conn_open, &mut pfb, stream_reader); + prft.window_update(&mut hdpm.hb.scrp, &mut hdpm.hb.sorp)?; + } + _ => { + return Err(protocol_err(Http2Error::UnexpectedConnFrame)); + } + } + Ok(()) +} + +#[inline] +async fn finish( + error: &crate::Error, + hd: &HD, + pfb: &mut PartitionedFilledBuffer, +) where + HB: LeaseMut>, + HD: RefCounter, + HD::Item: Lock>, + RRB: LeaseMut, + SW: StreamWriter, +{ + process_higher_operation_err(error, hd).await; + mem::swap(pfb, &mut hd.lock().await.parts_mut().hb.pfb); + _trace!("Finishing the reading of frames"); +} diff --git a/wtx/src/http2/headers_frame.rs b/wtx/src/http2/headers_frame.rs index 42d652ee..6c474c99 100644 --- a/wtx/src/http2/headers_frame.rs +++ b/wtx/src/http2/headers_frame.rs @@ -109,7 +109,12 @@ impl<'uri> HeadersFrame<'uri> { is_malformed = true; } _ => { - let header_name = HeaderName::http2p(name)?; + let header_name = match HeaderName::http2p(name) { + Ok(elem) => elem, + Err(_err) => { + return Err(protocol_err(Http2Error::InvalidHeaderData)); + } + }; has_fields = true; let len = decoded_header_size(name.len(), value.len()); expanded_headers_len = expanded_headers_len.wrapping_add(len); diff --git a/wtx/src/http2/hpack_decoder.rs b/wtx/src/http2/hpack_decoder.rs index fd3d23c6..413ce4c8 100644 --- a/wtx/src/http2/hpack_decoder.rs +++ b/wtx/src/http2/hpack_decoder.rs @@ -6,7 +6,7 @@ use crate::{ hpack_header::{HpackHeaderBasic, HpackHeaderName}, huffman_decode, misc::protocol_err, - Http2Error, + Http2Error, Http2ErrorCode, }, misc::{ArrayVector, Usize}, }; @@ -64,7 +64,10 @@ impl HpackDecoder { } while let [first, ..] = data { self.manage_decode(*first, &mut data, &mut cb, || { - Err(protocol_err(Http2Error::InvalidDynTableSizeUpdate)) + Err(crate::Error::Http2ErrorGoAway( + Http2ErrorCode::CompressionError, + Some(Http2Error::InvalidDynTableSizeUpdate), + )) })?; } Ok(()) @@ -90,12 +93,18 @@ impl HpackDecoder { } rslt } else { - return Err(protocol_err(Http2Error::InsufficientHpackBytes)); + return Err(crate::Error::Http2ErrorGoAway( + Http2ErrorCode::CompressionError, + Some(Http2Error::InsufficientHpackBytes), + )); }; let mut shift: u32 = 0; for _ in 0..3 { let [first, rest @ ..] = data else { - return Err(protocol_err(Http2Error::InsufficientHpackBytes)); + return Err(crate::Error::Http2ErrorGoAway( + Http2ErrorCode::CompressionError, + Some(Http2Error::InsufficientHpackBytes), + )); }; *data = rest; rslt.1 = rslt.1.wrapping_add(u32::from(first & 0b0111_1111) << shift); @@ -161,7 +170,10 @@ impl HpackDecoder { ) -> crate::Result<(&'data [u8], &'data [u8], bool)> { let (first, len) = Self::decode_integer(data, 0b0111_1111)?; let Some((bytes_begin, bytes_end)) = data.split_at_checked(*Usize::from(len)) else { - return Err(protocol_err(Http2Error::InsufficientHpackBytes)); + return Err(crate::Error::Http2ErrorGoAway( + Http2ErrorCode::CompressionError, + Some(Http2Error::InsufficientHpackBytes), + )); }; let is_encoded = first & 0b1000_0000 == 0b1000_0000; Ok((bytes_begin, bytes_end, is_encoded)) @@ -218,7 +230,12 @@ impl HpackDecoder { idx: usize, ) -> crate::Result<(HpackHeaderBasic, (&'static [u8], &[u8]), (&'static [u8], &[u8]))> { Ok(match idx { - 0 => return Err(protocol_err(Http2Error::InvalidHpackIdx(Some(0)))), + 0 => { + return Err(crate::Error::Http2ErrorGoAway( + Http2ErrorCode::CompressionError, + Some(Http2Error::InvalidHpackIdx(Some(0))), + )) + } 1 => (HpackHeaderBasic::Authority, (b":authority", &[]), (&[], &[])), 2 => (HpackHeaderBasic::Method(Method::Get), (b":method", &[]), (b"GET", &[])), 3 => (HpackHeaderBasic::Method(Method::Post), (b":method", &[]), (b"POST", &[])), @@ -309,7 +326,10 @@ impl HpackDecoder { dyn_idx_with_offset => dyn_headers .get_by_idx(dyn_idx_with_offset.wrapping_sub(DYN_IDX_OFFSET)) .ok_or_else(|| { - protocol_err(Http2Error::InvalidHpackIdx(dyn_idx_with_offset.try_into().ok())) + crate::Error::Http2ErrorGoAway( + Http2ErrorCode::CompressionError, + Some(Http2Error::InvalidHpackIdx(dyn_idx_with_offset.try_into().ok())), + ) }) .map(|el| (*el.misc, (&[][..], el.name_bytes), (&[][..], el.value_bytes)))?, }) @@ -344,10 +364,10 @@ impl HpackDecoder { size_update_cb()?; let local_max_bytes: u32 = Self::decode_integer(data, 0b0001_1111)?.1; if local_max_bytes > self.max_bytes.0 { - return Err(crate::Error::MISC_UnboundedNumber { - expected: 0..=self.max_bytes.0, - received: local_max_bytes, - }); + return Err(crate::Error::Http2ErrorGoAway( + Http2ErrorCode::CompressionError, + Some(Http2Error::OutOfBoundsIndex), + )); } self.dyn_headers.set_max_bytes(*Usize::from(local_max_bytes), |_, _| {}); } diff --git a/wtx/src/http2/hpack_encoder.rs b/wtx/src/http2/hpack_encoder.rs index a1a951ff..c34b342a 100644 --- a/wtx/src/http2/hpack_encoder.rs +++ b/wtx/src/http2/hpack_encoder.rs @@ -11,7 +11,7 @@ use crate::{ http::{AbstractHeaders, Header, KnownHeaderName, Method, StatusCode}, http2::{hpack_header::HpackHeaderBasic, huffman_encode, misc::protocol_err, Http2Error}, - misc::{Usize, Vector, _random_state, _shift_bytes, _unreachable}, + misc::{Usize, Vector, _random_state, _shift_copyable_chunks, _unreachable}, rng::Rng, }; use ahash::RandomState; @@ -282,7 +282,7 @@ impl HpackEncoder { } _ => return Ok(()), } - let _ = _shift_bytes( + let _ = _shift_copyable_chunks( before_byte.wrapping_add(octets.into()), buffer, iter::once(after_byte..after_huffman), diff --git a/wtx/src/http2/http2_buffer.rs b/wtx/src/http2/http2_buffer.rs index a8b8a6f8..365e8d71 100644 --- a/wtx/src/http2/http2_buffer.rs +++ b/wtx/src/http2/http2_buffer.rs @@ -1,9 +1,14 @@ use crate::{ - http2::{FrameInit, HpackDecoder, HpackEncoder, Scrp, Sorp, UriBuffer}, + http::Method, + http2::{HpackDecoder, HpackEncoder, IsConnOpenSync, Scrp, Sorp, UriBuffer, U31}, misc::{Lease, LeaseMut, PartitionedFilledBuffer, Vector}, rng::Rng, }; -use alloc::boxed::Box; +use alloc::{boxed::Box, collections::VecDeque, sync::Arc}; +use core::{ + sync::atomic::{AtomicBool, Ordering}, + task::Waker, +}; use hashbrown::HashMap; /// Groups all intermediate structures necessary to perform HTTP/2 connections. @@ -12,7 +17,9 @@ pub struct Http2Buffer { pub(crate) hpack_dec: HpackDecoder, pub(crate) hpack_enc: HpackEncoder, pub(crate) hpack_enc_buffer: Vector, - pub(crate) initial_server_header: Option, + pub(crate) initial_server_header_buffers: VecDeque<(RRB, Waker)>, + pub(crate) initial_server_header_params: VecDeque<(Method, U31)>, + pub(crate) is_conn_open: IsConnOpenSync, pub(crate) pfb: PartitionedFilledBuffer, pub(crate) scrp: Scrp, pub(crate) sorp: Sorp, @@ -30,7 +37,9 @@ impl Http2Buffer { hpack_dec: HpackDecoder::new(), hpack_enc: HpackEncoder::new(rng), hpack_enc_buffer: Vector::new(), - initial_server_header: None, + initial_server_header_buffers: VecDeque::new(), + initial_server_header_params: VecDeque::new(), + is_conn_open: Arc::new(AtomicBool::new(false)), pfb: PartitionedFilledBuffer::new(), scrp: HashMap::new(), sorp: HashMap::new(), @@ -44,7 +53,9 @@ impl Http2Buffer { hpack_dec, hpack_enc, hpack_enc_buffer, - initial_server_header, + initial_server_header_buffers, + initial_server_header_params, + is_conn_open, pfb, scrp, sorp, @@ -53,7 +64,9 @@ impl Http2Buffer { hpack_dec.clear(); hpack_enc.clear(); hpack_enc_buffer.clear(); - *initial_server_header = None; + initial_server_header_buffers.clear(); + initial_server_header_params.clear(); + is_conn_open.store(false, Ordering::Relaxed); pfb._clear(); scrp.clear(); sorp.clear(); diff --git a/wtx/src/http2/http2_data.rs b/wtx/src/http2/http2_data.rs index 9b2ddab2..021c13b8 100644 --- a/wtx/src/http2/http2_data.rs +++ b/wtx/src/http2/http2_data.rs @@ -1,166 +1,83 @@ use crate::{ http::ReqResBuffer, - http2::{ - http2_params_send::Http2ParamsSend, - misc::{protocol_err, read_frame_until}, - FrameInitTy, Http2Buffer, Http2Error, Http2Params, ProcessReceiptFrameTy, Windows, U31, - }, - misc::{Lease, LeaseMut, Stream}, + http2::{http2_params_send::Http2ParamsSend, Http2Buffer, Http2Params, Windows, U31}, + misc::{Lease, LeaseMut, StreamWriter}, }; use core::marker::PhantomData; /// Internal resource used in every new instance of `Http2`. #[derive(Debug)] -pub struct Http2Data { +pub struct Http2Data { hb: HB, hp: Http2Params, hps: Http2ParamsSend, - is_conn_open: bool, last_stream_id: U31, phantom: PhantomData, recv_streams_num: u32, - stream: S, + stream_writer: SW, windows: Windows, } -impl Http2Data +impl Http2Data where HB: LeaseMut>, RRB: LeaseMut, - S: Stream, + SW: StreamWriter, { #[inline] - pub(crate) fn new(hb: HB, hp: Http2Params, stream: S) -> Self { + pub(crate) fn new(hb: HB, hp: Http2Params, stream_writer: SW) -> Self { let hps = Http2ParamsSend::default(); let windows = Windows::initial(&hp, &hps); Self { hb, hp, hps, - is_conn_open: true, last_stream_id: if IS_CLIENT { U31::ONE } else { U31::ZERO }, phantom: PhantomData, recv_streams_num: 0, - stream, + stream_writer, windows, } } #[inline] - pub(crate) fn is_conn_open(&self) -> bool { - self.is_conn_open - } - - #[inline] - pub(crate) fn parts_mut(&mut self) -> Http2DataPartsMut<'_, RRB, S> { + pub(crate) fn parts_mut(&mut self) -> Http2DataPartsMut<'_, RRB, SW> { Http2DataPartsMut { hb: self.hb.lease_mut(), last_stream_id: &mut self.last_stream_id, hp: &mut self.hp, hps: &mut self.hps, - is_conn_open: &mut self.is_conn_open, - stream: &mut self.stream, - windows: &mut self.windows, - } - } - - /// Fetches and evaluates one or more arbitrary frames. - #[inline] - pub(crate) async fn process_receipt(&mut self) -> crate::Result<()> { - let Http2Buffer { - hpack_dec, - hpack_enc, - initial_server_header, - pfb, - scrp, - sorp, - uri_buffer, - .. - } = self.hb.lease_mut(); - if initial_server_header.is_some() { - return Ok(()); - } - let Some(fi) = read_frame_until( - &mut self.windows, - &mut self.hp, - hpack_enc, - &mut self.hps, - &mut self.is_conn_open, - pfb, - scrp, - sorp, - &mut self.stream, - ) - .await? - else { - return Ok(()); - }; - let prft = ProcessReceiptFrameTy { - conn_windows: &mut self.windows, - fi, - hp: &mut self.hp, - hpack_dec, - is_conn_open: &mut self.is_conn_open, - last_stream_id: &mut self.last_stream_id, - pfb, - phantom: PhantomData, recv_streams_num: &mut self.recv_streams_num, - stream: &mut self.stream, - uri_buffer, - }; - match fi.ty { - FrameInitTy::Data => { - prft.data(sorp).await?; - } - FrameInitTy::Headers => { - if scrp.contains_key(&prft.fi.stream_id) { - return Err(protocol_err(Http2Error::UnexpectedNonControlFrame)); - } - if IS_CLIENT { - prft.header_client(sorp).await?; - } else { - prft.header_server(initial_server_header, sorp).await?; - } - } - FrameInitTy::Reset => { - prft.reset(scrp, sorp)?; - return Ok(()); - } - FrameInitTy::WindowUpdate if fi.stream_id.is_not_zero() => { - prft.window_update(scrp, sorp)?; - } - _ => { - return Err(protocol_err(Http2Error::UnexpectedConnFrame)); - } + stream_writer: &mut self.stream_writer, + windows: &mut self.windows, } - Ok(()) } } -impl Lease> - for Http2Data +impl Lease> + for Http2Data { #[inline] - fn lease(&self) -> &Http2Data { + fn lease(&self) -> &Http2Data { self } } -impl LeaseMut> - for Http2Data +impl LeaseMut> + for Http2Data { #[inline] - fn lease_mut(&mut self) -> &mut Http2Data { + fn lease_mut(&mut self) -> &mut Http2Data { self } } -pub(crate) struct Http2DataPartsMut<'instance, RRB, S> { +pub(crate) struct Http2DataPartsMut<'instance, RRB, SW> { pub(crate) hb: &'instance mut Http2Buffer, pub(crate) hp: &'instance mut Http2Params, pub(crate) hps: &'instance mut Http2ParamsSend, - pub(crate) is_conn_open: &'instance mut bool, pub(crate) last_stream_id: &'instance mut U31, - pub(crate) stream: &'instance mut S, + pub(crate) recv_streams_num: &'instance mut u32, + pub(crate) stream_writer: &'instance mut SW, pub(crate) windows: &'instance mut Windows, } diff --git a/wtx/src/http2/http2_error.rs b/wtx/src/http2/http2_error.rs index 83bb59df..95aa3a1f 100644 --- a/wtx/src/http2/http2_error.rs +++ b/wtx/src/http2/http2_error.rs @@ -48,7 +48,7 @@ pub enum Http2Error { InvalidGoAwayFrameNonZeroId, /// A container does not contain an element referred by the given idx InvalidHpackIdx(Option), - /// Header frame has mal formatted content + /// Header frame has mal-formatted content InvalidHeaderData, #[doc = stream_id_must_not_be_zero!()] InvalidHeadersFrameZeroId, @@ -88,6 +88,8 @@ pub enum Http2Error { NoBuffersForNewStream, /// Counter-part did not return the correct bytes of a HTTP2 connection preface NoPreface, + /// Received index is greater than the supported range + OutOfBoundsIndex, /// Frame size must be within 16384 and 16777215 OutOfBoundsMaxFrameSize, /// Window size must be within 0 and 2147483647 @@ -118,6 +120,8 @@ pub enum Http2Error { UnknownHeaderStreamReceiver, /// A stream ID is not locally stored to allow the processing of reset frames. UnknownResetStreamReceiver, + /// A stream ID is not locally stored. + UnknownStreamReceiver, /// A stream ID is not locally stored to allow the processing of window update frames. UnknownWindowUpdateStreamReceiver, /// Length of a header name or value is limited to 127 bytes. diff --git a/wtx/src/http2/huffman.rs b/wtx/src/http2/huffman.rs index b22e1ce5..e930e062 100644 --- a/wtx/src/http2/huffman.rs +++ b/wtx/src/http2/huffman.rs @@ -2,7 +2,7 @@ use crate::{ http2::{ huffman_tables::{DECODED, DECODE_TABLE, ENCODE_TABLE, END_OF_STRING, ERROR}, misc::protocol_err, - Http2Error, + Http2Error, Http2ErrorCode, }, misc::{ArrayVector, Vector, _unreachable}, }; @@ -24,7 +24,10 @@ pub(crate) fn huffman_decode( _unreachable(); }; if flags & ERROR == ERROR { - return Err(protocol_err(Http2Error::UnexpectedEndingHuffman)); + return Err(crate::Error::Http2ErrorGoAway( + Http2ErrorCode::CompressionError, + Some(Http2Error::UnexpectedEndingHuffman), + )); } let rslt = (flags & DECODED == DECODED).then_some(byte); *curr_state = next_state; @@ -63,7 +66,10 @@ pub(crate) fn huffman_decode( let is_final = curr_state == 0 || end_of_string; if !is_final { - return Err(protocol_err(Http2Error::UnexpectedEndingHuffman)); + return Err(crate::Error::Http2ErrorGoAway( + Http2ErrorCode::CompressionError, + Some(Http2Error::UnexpectedEndingHuffman), + )); } Ok(()) diff --git a/wtx/src/http2/macros.rs b/wtx/src/http2/macros.rs index 49843013..c3dbf244 100644 --- a/wtx/src/http2/macros.rs +++ b/wtx/src/http2/macros.rs @@ -1,45 +1,11 @@ -macro_rules! loop_until_some { - ($opt:expr) => {{ - let resource = 'resource: { - for _ in 0.._max_frames_mismatches!() { - match $opt { - None => continue, - Some(elem) => break 'resource elem, - } - } - return Err(crate::http2::misc::protocol_err(Http2Error::VeryLargeAmountOfFrameMismatches)); - }; - resource +macro_rules! lock_pin { + ($cx:expr, $hd:expr, $lock_pin:expr) => {{ + let lock = core::task::ready!($lock_pin.as_mut().poll($cx)); + $lock_pin.set($hd.lock()); + lock }}; } -macro_rules! process_higher_operation { - ( - $hd:expr, - |$guard:ident| $cb:expr, - |$guard_end:ident, $elem_end:ident| $cb_end:expr - ) => { - 'process_receipt: loop { - let err = 'err: { - let mut $guard = $hd.lock().await; - if let Err(err) = $guard.process_receipt().await { - break 'err err; - } - match $cb { - Err(err) => break 'err err, - Ok(None) => continue 'process_receipt, - Ok(Some(elem)) => { - let $elem_end = elem; - let mut $guard_end = $guard; - break 'process_receipt ($cb_end); - } - } - }; - break Err(crate::http2::misc::process_higher_operation_err(err, $hd).await); - } - }; -} - macro_rules! initial_window_len { () => { 65_535 diff --git a/wtx/src/http2/misc.rs b/wtx/src/http2/misc.rs index 7bc2cc0f..0b2c535d 100644 --- a/wtx/src/http2/misc.rs +++ b/wtx/src/http2/misc.rs @@ -1,16 +1,20 @@ use crate::{ http::ReqResBuffer, http2::{ - http2_data::Http2DataPartsMut, http2_params_send::Http2ParamsSend, CommonFlags, FrameInit, - FrameInitTy, GoAwayFrame, HeadersFrame, HpackDecoder, HpackEncoder, Http2Buffer, Http2Data, - Http2Error, Http2ErrorCode, Http2Params, PingFrame, ResetStreamFrame, Scrp, SettingsFrame, - Sorp, StreamOverallRecvParams, StreamState, UriBuffer, WindowUpdateFrame, Windows, U31, + http2_data::Http2DataPartsMut, CommonFlags, FrameInit, FrameInitTy, GoAwayFrame, HeadersFrame, + HpackDecoder, Http2Buffer, Http2Data, Http2Error, Http2ErrorCode, Http2Params, PingFrame, + ResetStreamFrame, Scrp, SettingsFrame, Sorp, StreamOverallRecvParams, StreamState, UriBuffer, + WindowUpdateFrame, U31, }, misc::{ - LeaseMut, Lock, PartitionedFilledBuffer, PollOnce, RefCounter, Stream, Usize, _read_until, + Either, LeaseMut, Lock, PartitionedFilledBuffer, RefCounter, StreamReader, StreamWriter, Usize, + _read_until, }, }; -use core::pin::pin; +use core::{ + sync::atomic::{AtomicBool, Ordering}, + task::{Context, Poll}, +}; #[inline] pub(crate) fn check_content_length( @@ -26,102 +30,134 @@ where Ok(()) } -pub(crate) const fn protocol_err(error: Http2Error) -> crate::Error { - crate::Error::Http2ErrorGoAway(Http2ErrorCode::ProtocolError, Some(error)) +#[inline] +pub(crate) fn manage_initial_stream_receiving( + hdpm: &Http2DataPartsMut<'_, RRB, SW>, + is_conn_open: &AtomicBool, + rrb: &mut RRB, +) -> bool +where + RRB: LeaseMut, +{ + if !is_conn_open.load(Ordering::Relaxed) { + return false; + } + rrb.lease_mut().clear(); + rrb.lease_mut().headers_mut().set_max_bytes(*Usize::from(hdpm.hp.max_headers_len())); + true } #[inline] -pub(crate) async fn process_higher_operation_err( - mut err: crate::Error, - hd: &HD, -) -> crate::Error +pub(crate) fn manage_recurrent_stream_receiving( + cx: &mut Context<'_>, + mut hdpm: Http2DataPartsMut<'_, RRB, SW>, + is_conn_open: &AtomicBool, + stream_id: &U31, + cb: impl FnOnce( + &mut Context<'_>, + &mut Http2DataPartsMut<'_, RRB, SW>, + &StreamOverallRecvParams, + ) -> T, +) -> Poll>> where - HB: LeaseMut>, - HD: RefCounter, - HD::Item: Lock>, RRB: LeaseMut, - S: Stream, { - #[inline] - pub(crate) async fn send_based_on_error( - err: crate::Error, - hdpm: Http2DataPartsMut<'_, RRB, S>, - ) -> crate::Error - where - RRB: LeaseMut, - S: Stream, - { - match &err { - crate::Error::Http2ErrorGoAway(http2_error_code, _) => { - send_go_away(*http2_error_code, hdpm.is_conn_open, *hdpm.last_stream_id, hdpm.stream).await; + let Some(sorp) = hdpm.hb.sorp.get_mut(stream_id) else { + return Poll::Ready(Err(protocol_err(Http2Error::UnknownStreamReceiver))); + }; + 'block: { + let rrb_opt = match (is_conn_open.load(Ordering::Relaxed), sorp.is_stream_open) { + (false, false) => { + let _opt = hdpm.hb.scrp.remove(stream_id); + hdpm.hb.sorp.remove(stream_id).map(|el| el.rrb) } - crate::Error::Http2ErrorReset(http2_error_code, _, stream_id) => { - send_reset_stream(*http2_error_code, hdpm.hb, hdpm.stream, stream_id.into()).await; + (false, true) => hdpm.hb.sorp.remove(stream_id).map(|el| el.rrb), + (true, false) => { + let _opt = hdpm.hb.scrp.remove(stream_id); + hdpm.hb.sorp.remove(stream_id).map(|el| el.rrb) } - _ => { - send_go_away( - Http2ErrorCode::InternalError, - hdpm.is_conn_open, - *hdpm.last_stream_id, - hdpm.stream, - ) - .await; + (true, true) => { + break 'block; + } + }; + if let Some(elem) = rrb_opt { + return Poll::Ready(Ok(Either::Left(elem))); + } else { + return Poll::Ready(Err(protocol_err(Http2Error::UnknownStreamReceiver))); + } + } + if sorp.stream_state.recv_eos() { + if let Some(sorp) = hdpm.hb.sorp.remove(stream_id) { + if let Some(idx) = sorp.content_length { + check_content_length(idx, &sorp)?; } + let rslt = cb(cx, &mut hdpm, &sorp); + return Poll::Ready(Ok(Either::Right((sorp.rrb, rslt)))); } - err + } else { + sorp.waker.clone_from(cx.waker()); } + Poll::Pending +} - let now = crate::misc::GenericTime::now(); - let mut idx: u8 = 0; - let mut has_reset_err = false; - loop { - let mut guard = hd.lock().await; - if idx >= crate::http2::MAX_FINAL_FETCHES { - err = send_based_on_error(err, guard.parts_mut()).await; - return err; +#[inline] +pub(crate) const fn protocol_err(error: Http2Error) -> crate::Error { + crate::Error::Http2ErrorGoAway(Http2ErrorCode::ProtocolError, Some(error)) +} + +#[inline] +pub(crate) async fn process_higher_operation_err( + err: &crate::Error, + hd: &HD, +) where + HB: LeaseMut>, + HD: RefCounter, + HD::Item: Lock>, + RRB: LeaseMut, + SW: StreamWriter, +{ + let mut lock = hd.lock().await; + let mut hdpm = lock.parts_mut(); + match err { + crate::Error::Http2ErrorGoAway(http2_error_code, _) => { + send_go_away(*http2_error_code, &mut hdpm).await; } - has_reset_err |= matches!(&err, crate::Error::Http2ErrorReset(..)); - let local_rslt = guard.process_receipt().await; - let hdpm = guard.parts_mut(); - if has_reset_err { - if let Err(mut local_err) = local_rslt { - local_err = send_based_on_error(local_err, hdpm).await; - return local_err; - } + crate::Error::Http2ErrorReset(http2_error_code, _, stream_id) => { + let _ = send_reset_stream( + *http2_error_code, + &mut hdpm.hb.scrp, + &mut hdpm.hb.sorp, + hdpm.stream_writer, + stream_id.into(), + ) + .await; } - if now.elapsed().ok().map_or(true, |el| el >= crate::http2::MAX_FINAL_DURATION) { - err = send_based_on_error(err, hdpm).await; - return err; + _ => { + send_go_away(Http2ErrorCode::InternalError, &mut hdpm).await; } - idx = idx.wrapping_add(1); } } #[inline] -pub(crate) async fn read_frame( - hp: &mut Http2Params, - is_conn_open: &mut bool, +pub(crate) async fn read_frame( + max_frame_len: u32, pfb: &mut PartitionedFilledBuffer, - stream: &mut S, -) -> crate::Result> + stream_reader: &mut SR, +) -> crate::Result where - S: Stream, + SR: StreamReader, { - if !*is_conn_open { - return Err(crate::Error::Http2ErrorGoAway(Http2ErrorCode::Cancel, None)); - } for _ in 0.._max_frames_mismatches!() { pfb._clear_if_following_is_empty(); let mut read = pfb._following_len(); let buffer = pfb._following_trail_mut(); - let Some(array_rslt) = PollOnce(pin!(_read_until::<9, _>(buffer, &mut read, 0, stream))).await - else { - return Ok(None); - }; - let array = array_rslt?; + let array = _read_until::<9, _>(buffer, &mut read, 0, stream_reader).await?; let (fi_opt, data_len) = FrameInit::from_array(array); - if data_len > hp.max_frame_len() { - return Err(protocol_err(Http2Error::LargeArbitraryFrameLen)); + if data_len > max_frame_len { + return Err(crate::Error::Http2ErrorGoAway( + Http2ErrorCode::FrameSizeError, + Some(Http2Error::LargeArbitraryFrameLen), + )); } let frame_len = *Usize::from_u32(data_len.wrapping_add(9)); let Some(fi) = fi_opt else { @@ -132,7 +168,7 @@ where return Err(protocol_err(Http2Error::LargeIgnorableFrameLen)); } let (antecedent_len, following_len) = if let Some(to_read) = frame_len.checked_sub(read) { - stream.read_skip(to_read).await?; + stream_reader.read_skip(to_read).await?; (pfb._buffer().len(), 0) } else { (pfb._current_end_idx().wrapping_add(frame_len), read.wrapping_sub(frame_len)) @@ -149,7 +185,7 @@ where break; } read = read.wrapping_add( - stream.read(pfb._following_trail_mut().get_mut(read..).unwrap_or_default()).await?, + stream_reader.read(pfb._following_trail_mut().get_mut(read..).unwrap_or_default()).await?, ); } if !is_fulfilled { @@ -160,31 +196,30 @@ where *Usize::from(data_len), read.wrapping_sub(frame_len), )?; - return Ok(Some(fi)); + return Ok(fi); } Err(protocol_err(Http2Error::VeryLargeAmountOfFrameMismatches)) } /// Reads frames and return the first that is NOT related to the connection #[inline] -pub(crate) async fn read_frame_until( - conn_windows: &mut Windows, - hp: &mut Http2Params, - hpack_enc: &mut HpackEncoder, - hps: &mut Http2ParamsSend, - is_conn_open: &mut bool, +pub(crate) async fn read_frame_until( + hd: &HD, + is_conn_open: &AtomicBool, + max_frame_len: u32, pfb: &mut PartitionedFilledBuffer, - scrp: &mut Scrp, - sorp: &mut Sorp, - stream: &mut S, -) -> crate::Result> + stream_reader: &mut SR, +) -> crate::Result where - S: Stream, + HB: LeaseMut>, + HD: RefCounter, + HD::Item: Lock>, + RRB: LeaseMut, + SR: StreamReader, + SW: StreamWriter, { for _ in 0.._max_frames_mismatches!() { - let Some(fi) = read_frame::<_, false>(hp, is_conn_open, pfb, stream).await? else { - return Ok(None); - }; + let fi = read_frame::<_, false>(max_frame_len, pfb, stream_reader).await?; match fi.ty { FrameInitTy::GoAway => { let gaf = GoAwayFrame::read(pfb._current(), fi)?; @@ -194,21 +229,32 @@ where let mut pf = PingFrame::read(pfb._current(), fi)?; if !pf.has_ack() { pf.set_ack(); - write_array([&pf.bytes()], *is_conn_open, stream).await?; + let mut lock = hd.lock().await; + write_array([&pf.bytes()], is_conn_open, lock.parts_mut().stream_writer).await?; } continue; } FrameInitTy::Settings => { let sf = SettingsFrame::read(pfb._current(), fi)?; if !sf.has_ack() { - hps.update(hpack_enc, scrp, &sf, sorp)?; - write_array([SettingsFrame::ack().bytes(&mut [0; 45])], *is_conn_open, stream).await?; + let mut lock = hd.lock().await; + let hdpm = lock.parts_mut(); + hdpm.hps.update(&mut hdpm.hb.hpack_enc, &mut hdpm.hb.scrp, &sf, &mut hdpm.hb.sorp)?; + let array = &mut [0; 45]; + write_array( + [SettingsFrame::ack().bytes(array)], + is_conn_open, + lock.parts_mut().stream_writer, + ) + .await?; } continue; } FrameInitTy::WindowUpdate if fi.stream_id.is_zero() => { let wuf = WindowUpdateFrame::read(pfb._current(), fi)?; - conn_windows.send.deposit(None, wuf.size_increment().i32())?; + let mut lock = hd.lock().await; + let hdpm = lock.parts_mut(); + hdpm.windows.send.deposit(None, wuf.size_increment().i32())?; continue; } _ => { @@ -217,7 +263,7 @@ where } } } - return Ok(Some(fi)); + return Ok(fi); } Err(protocol_err(Http2Error::VeryLargeAmountOfFrameMismatches)) } @@ -225,22 +271,21 @@ where #[inline] pub(crate) async fn read_header_and_continuations< H, - S, + SR, const IS_CLIENT: bool, const IS_TRAILER: bool, >( fi: FrameInit, hp: &mut Http2Params, hpack_dec: &mut HpackDecoder, - is_conn_open: &mut bool, pfb: &mut PartitionedFilledBuffer, rrb: &mut ReqResBuffer, - stream: &mut S, + stream_reader: &mut SR, uri_buffer: &mut UriBuffer, mut headers_cb: impl FnMut(&HeadersFrame<'_>) -> crate::Result, ) -> crate::Result<(Option, bool, H)> where - S: Stream, + SR: StreamReader, { if IS_TRAILER && !fi.cf.has_eos() { return Err(protocol_err(Http2Error::MissingEOSInTrailer)); @@ -259,7 +304,10 @@ where )?; if hf.is_over_size() { - return Err(protocol_err(Http2Error::VeryLargeHeadersLen)); + return Err(crate::Error::Http2ErrorGoAway( + Http2ErrorCode::FrameSizeError, + Some(Http2Error::VeryLargeHeadersLen), + )); } return Ok((content_length, hf.has_eos(), headers_cb(&hf)?)); } @@ -268,7 +316,7 @@ where 'continuation_frames: { for _ in 0.._max_continuation_frames!() { - let frame_fi = loop_until_some!(read_frame::<_, true>(hp, is_conn_open, pfb, stream).await?); + let frame_fi = read_frame::<_, true>(hp.max_frame_len(), pfb, stream_reader).await?; let has_diff_id = fi.stream_id != frame_fi.stream_id; let is_not_continuation = frame_fi.ty != FrameInitTy::Continuation; if has_diff_id || is_not_continuation { @@ -286,41 +334,66 @@ where HeadersFrame::read::(None, fi, hp, hpack_dec, rrb, uri_buffer)?; rrb.clear_body(); if hf.is_over_size() { - return Err(protocol_err(Http2Error::VeryLargeHeadersLen)); + return Err(crate::Error::Http2ErrorGoAway( + Http2ErrorCode::FrameSizeError, + Some(Http2Error::VeryLargeHeadersLen), + )); } Ok((content_length, hf.has_eos(), headers_cb(&hf)?)) } #[inline] -pub(crate) async fn send_go_away( +pub(crate) async fn send_go_away( error_code: Http2ErrorCode, - is_conn_open: &mut bool, - last_stream_id: U31, - stream: &mut S, + hdpm: &mut Http2DataPartsMut<'_, RRB, SW>, ) where - S: Stream, + SW: StreamWriter, { - *is_conn_open = false; - let _rslt = stream.write_all(&GoAwayFrame::new(error_code, last_stream_id).bytes()).await; + hdpm.hb.is_conn_open.store(false, Ordering::Relaxed); + let gaf = GoAwayFrame::new(error_code, *hdpm.last_stream_id); + let _rslt = hdpm.stream_writer.write_all(&gaf.bytes()).await; + for (_, waker) in hdpm.hb.initial_server_header_buffers.iter() { + waker.wake_by_ref(); + } + for scrp in hdpm.hb.scrp.values() { + scrp.waker.wake_by_ref(); + } + for sorp in hdpm.hb.sorp.values() { + sorp.waker.wake_by_ref(); + } } #[inline] -pub(crate) async fn send_reset_stream( +pub(crate) async fn send_reset_stream( error_code: Http2ErrorCode, - hb: &mut Http2Buffer, - stream: &mut S, + scrp: &mut Scrp, + sorp: &mut Sorp, + stream_writer: &mut SW, stream_id: U31, -) where - S: Stream, +) -> bool +where + SW: StreamWriter, { - let _opt = hb.scrp.remove(&stream_id); - let _opt = hb.sorp.remove(&stream_id); - let _rslt = stream.write_all(&ResetStreamFrame::new(error_code, stream_id).bytes()).await; + let mut has_stored = false; + let _rslt = stream_writer.write_all(&ResetStreamFrame::new(error_code, stream_id).bytes()).await; + if let Some(scrp) = scrp.get_mut(&stream_id) { + has_stored = true; + scrp.is_stream_open = false; + scrp.stream_state = StreamState::Closed; + scrp.waker.wake_by_ref(); + } + if let Some(sorp) = sorp.get_mut(&stream_id) { + has_stored = true; + sorp.is_stream_open = false; + sorp.stream_state = StreamState::Closed; + sorp.waker.wake_by_ref(); + } + has_stored } #[inline] -pub(crate) fn server_header_stream_state(is_eos: bool) -> StreamState { - if is_eos { +pub(crate) fn server_header_stream_state(has_eos: bool) -> StreamState { + if has_eos { StreamState::HalfClosedRemote } else { StreamState::Open @@ -345,15 +418,15 @@ pub(crate) fn trim_frame_pad(cf: CommonFlags, data: &mut &[u8]) -> crate::Result } #[inline] -pub(crate) async fn write_array( +pub(crate) async fn write_array( array: [&[u8]; N], - is_conn_open: bool, - stream: &mut S, + is_conn_open: &AtomicBool, + stream_writer: &mut SW, ) -> crate::Result<()> where - S: Stream, + SW: StreamWriter, { - if !is_conn_open { + if !is_conn_open.load(Ordering::Relaxed) { return Ok(()); } _trace!("Sending frame(s): {:?}", { @@ -371,6 +444,6 @@ where } rslt }); - stream.write_all_vectored(&array).await?; + stream_writer.write_all_vectored(&array).await?; Ok(()) } diff --git a/wtx/src/http2/ping_frame.rs b/wtx/src/http2/ping_frame.rs index 10e9e64c..f8c7a7b1 100644 --- a/wtx/src/http2/ping_frame.rs +++ b/wtx/src/http2/ping_frame.rs @@ -1,6 +1,4 @@ -use crate::http2::{ - misc::protocol_err, CommonFlags, FrameInit, FrameInitTy, Http2Error, Http2ErrorCode, U31, -}; +use crate::http2::{CommonFlags, FrameInit, FrameInitTy, Http2Error, Http2ErrorCode, U31}; #[derive(Debug, Eq, PartialEq)] pub(crate) struct PingFrame { @@ -17,7 +15,10 @@ impl PingFrame { #[inline] pub(crate) fn read(bytes: &[u8], mut fi: FrameInit) -> crate::Result { if fi.stream_id.is_not_zero() { - return Err(protocol_err(Http2Error::InvalidPingFrameNonZeroId)); + return Err(crate::Error::Http2ErrorGoAway( + Http2ErrorCode::FrameSizeError, + Some(Http2Error::InvalidPingFrameNonZeroId), + )); } fi.cf.only_ack(); let [a, b, c, d, e, f, g, h] = bytes else { diff --git a/wtx/src/http2/process_receipt_frame_ty.rs b/wtx/src/http2/process_receipt_frame_ty.rs index b48a9cc4..0c9f3e47 100644 --- a/wtx/src/http2/process_receipt_frame_ty.rs +++ b/wtx/src/http2/process_receipt_frame_ty.rs @@ -1,46 +1,53 @@ -macro_rules! trace_frame { - ($this:expr, $span:expr) => { - let _e = $span._enter(); - _trace!("Receiving frame: {:?}", $this.fi); - }; -} - use crate::{ - http::{HttpError, ReqResBuffer}, + http::{HttpError, Method, ReqResBuffer, StatusCode}, http2::{ - misc::{protocol_err, read_header_and_continuations, server_header_stream_state}, + http2_params_send::Http2ParamsSend, + misc::{ + protocol_err, read_header_and_continuations, send_reset_stream, server_header_stream_state, + }, window::WindowsPair, DataFrame, FrameInit, HpackDecoder, Http2Error, Http2ErrorCode, Http2Params, ResetStreamFrame, - Scrp, Sorp, StreamState, UriBuffer, WindowUpdateFrame, Windows, U31, + Scrp, Sorp, StreamOverallRecvParams, StreamState, UriBuffer, WindowUpdateFrame, Windows, U31, }, - misc::{LeaseMut, PartitionedFilledBuffer, Stream, _Span}, + misc::{LeaseMut, PartitionedFilledBuffer, StreamReader, StreamWriter, Usize}, }; -use core::marker::PhantomData; +use alloc::collections::VecDeque; +use core::{marker::PhantomData, sync::atomic::AtomicBool, task::Waker}; #[derive(Debug)] -pub(crate) struct ProcessReceiptFrameTy<'instance, RRB, S> { +pub(crate) struct ProcessReceiptFrameTy<'instance, RRB, SR, SW> { pub(crate) conn_windows: &'instance mut Windows, pub(crate) fi: FrameInit, pub(crate) hp: &'instance mut Http2Params, pub(crate) hpack_dec: &'instance mut HpackDecoder, - pub(crate) is_conn_open: &'instance mut bool, + pub(crate) hps: &'instance mut Http2ParamsSend, + pub(crate) is_conn_open: &'instance AtomicBool, pub(crate) last_stream_id: &'instance mut U31, pub(crate) pfb: &'instance mut PartitionedFilledBuffer, pub(crate) phantom: PhantomData, pub(crate) recv_streams_num: &'instance mut u32, - pub(crate) stream: &'instance mut S, + pub(crate) stream_reader: &'instance mut SR, + pub(crate) stream_writer: &'instance mut SW, pub(crate) uri_buffer: &'instance mut UriBuffer, } -impl<'instance, RRB, S> ProcessReceiptFrameTy<'instance, RRB, S> +impl<'instance, RRB, SR, SW> ProcessReceiptFrameTy<'instance, RRB, SR, SW> where RRB: LeaseMut, - S: Stream, + SR: StreamReader, + SW: StreamWriter, { #[inline] pub(crate) async fn data(self, sorp: &mut Sorp) -> crate::Result<()> { let Some(elem) = sorp.get_mut(&self.fi.stream_id) else { - return Err(protocol_err(Http2Error::UnknownDataStreamReceiver)); + if self.fi.stream_id <= *self.last_stream_id { + return Err(crate::Error::Http2ErrorGoAway( + Http2ErrorCode::StreamClosed, + Some(Http2Error::UnknownDataStreamReceiver), + )); + } else { + return Err(protocol_err(Http2Error::UnknownDataStreamReceiver)); + } }; if elem.stream_state.recv_eos() { return Err(crate::Error::Http2ErrorGoAway( @@ -48,7 +55,6 @@ where Some(Http2Error::InvalidReceivedFrameAfterEos), )); } - trace_frame!(self, elem.span); let local_body_len_opt = elem.body_len.checked_add(self.fi.data_len); let Some(local_body_len) = local_body_len_opt.filter(|el| *el <= self.hp.max_body_len()) else { return Err(protocol_err(Http2Error::LargeBodyLen( @@ -60,10 +66,17 @@ where let (df, body_bytes) = DataFrame::read(self.pfb._current(), self.fi)?; elem.rrb.lease_mut().extend_body(body_bytes)?; WindowsPair::new(self.conn_windows, &mut elem.windows) - .withdrawn_recv(self.hp, *self.is_conn_open, self.stream, self.fi.stream_id, df.data_len()) + .withdrawn_recv( + self.hp, + self.is_conn_open, + self.stream_writer, + self.fi.stream_id, + df.data_len(), + ) .await?; if df.has_eos() { elem.stream_state = StreamState::HalfClosedRemote; + elem.waker.wake_by_ref(); } Ok(()) } @@ -73,16 +86,14 @@ where let Some(elem) = sorp.get_mut(&self.fi.stream_id) else { return Err(protocol_err(Http2Error::UnknownHeaderStreamReceiver)); }; - trace_frame!(self, elem.span); let has_eos = if elem.has_initial_header { read_header_and_continuations::<_, _, true, true>( self.fi, self.hp, self.hpack_dec, - self.is_conn_open, self.pfb, elem.rrb.lease_mut(), - self.stream, + self.stream_reader, self.uri_buffer, |_| Ok(()), ) @@ -93,10 +104,9 @@ where self.fi, self.hp, self.hpack_dec, - self.is_conn_open, self.pfb, elem.rrb.lease_mut(), - self.stream, + self.stream_reader, self.uri_buffer, |hf| hf.hsresh().status_code.ok_or_else(|| HttpError::MissingResponseStatusCode.into()), ) @@ -107,83 +117,111 @@ where }; if has_eos { elem.stream_state = StreamState::Closed; + elem.waker.wake_by_ref(); } Ok(()) } #[inline] - pub(crate) async fn header_server( - self, - initial_server_header: &mut Option, + pub(crate) async fn header_server_init( + mut self, + initial_server_header_params: &mut VecDeque<(Method, U31)>, + mut rrb: RRB, sorp: &mut Sorp, ) -> crate::Result<()> { - // Trailer - if let Some(elem) = sorp.get_mut(&self.fi.stream_id) { - if elem.stream_state.recv_eos() { - return Err(protocol_err(Http2Error::UnexpectedHeaderFrame)); - } - let (_, has_eos, _) = read_header_and_continuations::<_, _, false, true>( - self.fi, - self.hp, - self.hpack_dec, - self.is_conn_open, - self.pfb, - elem.rrb.lease_mut(), - self.stream, - self.uri_buffer, - |_| Ok(()), - ) - .await?; - elem.stream_state = server_header_stream_state(has_eos); + if self.fi.stream_id <= *self.last_stream_id || self.fi.stream_id.u32() % 2 == 0 { + return Err(protocol_err(Http2Error::UnexpectedStreamId)); } - // Initial header - else { - if self.fi.stream_id.u32() % 2 == 0 || self.fi.stream_id <= *self.last_stream_id { - return Err(protocol_err(Http2Error::UnexpectedStreamId)); - } - if *self.recv_streams_num >= self.hp.max_recv_streams_num() { - return Err(protocol_err(Http2Error::ExceedAmountOfActiveConcurrentStreams)); - } - *self.recv_streams_num = self.recv_streams_num.wrapping_add(1); - *self.last_stream_id = self.fi.stream_id; - *initial_server_header = Some(self.fi); + if *self.recv_streams_num >= self.hp.max_recv_streams_num() { + return Err(protocol_err(Http2Error::ExceedAmountOfActiveConcurrentStreams)); } + *self.recv_streams_num = self.recv_streams_num.wrapping_add(1); + *self.last_stream_id = self.fi.stream_id; + rrb.lease_mut().headers_mut().set_max_bytes(*Usize::from(self.hp.max_headers_len())); + let (content_length, has_eos, method) = read_header_and_continuations::<_, _, false, false>( + self.fi, + self.hp, + &mut self.hpack_dec, + &mut self.pfb, + rrb.lease_mut(), + self.stream_reader, + &mut self.uri_buffer, + |hf| hf.hsreqh().method.ok_or_else(|| HttpError::MissingRequestMethod.into()), + ) + .await?; + initial_server_header_params.push_back((method, self.fi.stream_id)); + let stream_state = server_header_stream_state(has_eos); + drop(sorp.insert( + self.fi.stream_id, + StreamOverallRecvParams { + body_len: 0, + content_length, + has_initial_header: true, + is_stream_open: true, + rrb, + status_code: StatusCode::Ok, + stream_state, + waker: Waker::noop().clone(), + windows: Windows::initial(self.hp, self.hps), + }, + )); Ok(()) } #[inline] - pub(crate) fn reset(self, scrp: &mut Scrp, sorp: &mut Sorp) -> crate::Result<()> { - if let Some(elem) = scrp.get_mut(&self.fi.stream_id) { - return self.do_reset(&elem.span, &mut elem.stream_state); - }; - if let Some(elem) = sorp.get_mut(&self.fi.stream_id) { - return self.do_reset(&elem.span, &mut elem.stream_state); - }; - Err(protocol_err(Http2Error::UnknownResetStreamReceiver)) + pub(crate) async fn header_server_trailer( + self, + sorp: &mut StreamOverallRecvParams, + ) -> crate::Result<()> { + if sorp.stream_state.recv_eos() { + return Err(protocol_err(Http2Error::UnexpectedHeaderFrame)); + } + let (_, has_eos, _) = read_header_and_continuations::<_, _, false, true>( + self.fi, + self.hp, + self.hpack_dec, + self.pfb, + sorp.rrb.lease_mut(), + self.stream_reader, + self.uri_buffer, + |_| Ok(()), + ) + .await?; + sorp.stream_state = server_header_stream_state(has_eos); + if has_eos { + sorp.waker.wake_by_ref(); + } + Ok(()) + } + + #[inline] + pub(crate) async fn reset(self, scrp: &mut Scrp, sorp: &mut Sorp) -> crate::Result<()> { + let rsf = ResetStreamFrame::read(self.pfb._current(), self.fi)?; + if !send_reset_stream(rsf.error_code(), scrp, sorp, self.stream_writer, self.fi.stream_id).await + { + return Err(protocol_err(Http2Error::UnknownResetStreamReceiver)); + } + Ok(()) } #[inline] pub(crate) fn window_update(self, scrp: &mut Scrp, sorp: &mut Sorp) -> crate::Result<()> { if let Some(elem) = scrp.get_mut(&self.fi.stream_id) { - return self.do_window_update(&elem.span, &mut elem.windows); + self.do_window_update(&mut elem.windows, &elem.waker)?; + return Ok(()); }; if let Some(elem) = sorp.get_mut(&self.fi.stream_id) { - return self.do_window_update(&elem.span, &mut elem.windows); + self.do_window_update(&mut elem.windows, &elem.waker)?; + return Ok(()); }; Err(protocol_err(Http2Error::UnknownWindowUpdateStreamReceiver)) } - fn do_reset(self, span: &_Span, stream_state: &mut StreamState) -> crate::Result<()> { - trace_frame!(self, span); - let rsf = ResetStreamFrame::read(self.pfb._current(), self.fi)?; - *stream_state = StreamState::Closed; - Err(crate::Error::Http2ErrorReset(rsf.error_code(), None, self.fi.stream_id.into())) - } - - fn do_window_update(self, span: &_Span, windows: &mut Windows) -> crate::Result<()> { - trace_frame!(self, span); + #[inline] + fn do_window_update(self, windows: &mut Windows, waker: &Waker) -> crate::Result<()> { let wuf = WindowUpdateFrame::read(self.pfb._current(), self.fi)?; windows.send.deposit(Some(self.fi.stream_id), wuf.size_increment().i32())?; + waker.wake_by_ref(); Ok(()) } } diff --git a/wtx/src/http2/reset_stream_frame.rs b/wtx/src/http2/reset_stream_frame.rs index 744baf2b..39f126fd 100644 --- a/wtx/src/http2/reset_stream_frame.rs +++ b/wtx/src/http2/reset_stream_frame.rs @@ -26,7 +26,9 @@ impl ResetStreamFrame { )); }; Ok(Self { - error_code: u32::from_be_bytes([*a, *b, *c, *d]).try_into()?, + error_code: u32::from_be_bytes([*a, *b, *c, *d]) + .try_into() + .unwrap_or(Http2ErrorCode::InternalError), stream_id: fi.stream_id, }) } diff --git a/wtx/src/http2/send_msg.rs b/wtx/src/http2/send_msg.rs index 14325723..4ccd4d85 100644 --- a/wtx/src/http2/send_msg.rs +++ b/wtx/src/http2/send_msg.rs @@ -29,45 +29,76 @@ use crate::{ http::{Headers, ReqResBuffer}, http2::{ http2_data::Http2DataPartsMut, - misc::{protocol_err, write_array}, + misc::{process_higher_operation_err, protocol_err, write_array}, window::WindowsPair, ContinuationFrame, DataFrame, HeadersFrame, HpackEncoder, HpackStaticRequestHeaders, HpackStaticResponseHeaders, Http2Buffer, Http2Data, Http2Error, StreamState, U31, }, - misc::{LeaseMut, Lock, RefCounter, Stream, Usize, Vector}, + misc::{LeaseMut, Lock, RefCounter, StreamWriter, Usize, Vector}, +}; +use core::{ + future::poll_fn, + pin::pin, + sync::atomic::{AtomicBool, Ordering}, + task::{Poll, Waker}, }; #[inline] -pub(crate) async fn send_msg( +pub(crate) async fn send_msg( data_bytes: &[u8], hd: &HD, headers: &Headers, (hsreqh, hsresh): (HpackStaticRequestHeaders<'_>, HpackStaticResponseHeaders), + is_conn_open: &AtomicBool, stream_id: U31, - mut cb: impl FnMut(Http2DataPartsMut<'_, RRB, S>), -) -> crate::Result<()> + mut cb: impl FnMut(Http2DataPartsMut<'_, RRB, SW>), +) -> crate::Result> where HB: LeaseMut>, HD: RefCounter, - HD::Item: Lock>, + HD::Item: Lock>, RRB: LeaseMut, - S: Stream, + SW: StreamWriter, { let (mut has_headers, mut has_data) = (false, false); - process_higher_operation!( - hd, - |guard| do_send_msg::<_, _, IS_CLIENT>( + + let mut lock_pin = pin!(hd.lock()); + let rslt = poll_fn(move |cx| { + if !is_conn_open.load(Ordering::Relaxed) { + return Poll::Ready(Ok(None)); + } + let mut lock = lock_pin!(cx, hd, lock_pin); + let fut = do_send_msg::<_, _, IS_CLIENT>( data_bytes, (&mut has_headers, &mut has_data), headers, - guard.parts_mut(), + lock.parts_mut(), (hsreqh, hsresh), stream_id, + cx.waker(), &mut cb, - ) - .await, - |_guard, elem| Ok(elem) - ) + ); + if let Poll::Ready(rslt) = pin!(fut).poll(cx) { + if let Some(is_fully_sent) = rslt? { + if is_fully_sent { + if IS_CLIENT { + _trace!("Request has been sent") + } else { + _trace!("Response has been sent") + }; + return Poll::Ready(Ok(Some(()))); + } + } else { + return Poll::Ready(Ok(None)); + } + } + Poll::Pending + }) + .await; + if let Err(err) = &rslt { + process_higher_operation_err(&err, hd).await; + } + rslt } #[inline] @@ -89,41 +120,46 @@ fn data_frame_len(bytes: &[u8]) -> U31 { // Tries to at least send initial headers when the windows size does not allow sending data frames #[inline] -async fn do_send_msg( +async fn do_send_msg( mut data_bytes: &[u8], (has_headers, has_data): (&mut bool, &mut bool), headers: &Headers, - mut hdpm: Http2DataPartsMut<'_, RRB, S>, + mut hdpm: Http2DataPartsMut<'_, RRB, SW>, (hsreqh, hsresh): (HpackStaticRequestHeaders<'_>, HpackStaticResponseHeaders), stream_id: U31, - cb: &mut impl FnMut(Http2DataPartsMut<'_, RRB, S>), -) -> crate::Result> + waker: &Waker, + cb: &mut impl FnMut(Http2DataPartsMut<'_, RRB, SW>), +) -> crate::Result> where RRB: LeaseMut, - S: Stream, + SW: StreamWriter, { - let Http2Buffer { hpack_enc, hpack_enc_buffer, scrp, .. } = &mut hdpm.hb; + let Http2Buffer { hpack_enc, hpack_enc_buffer, is_conn_open, scrp, .. } = &mut hdpm.hb; let Some(scrp) = scrp.get_mut(&stream_id) else { return Err(protocol_err(Http2Error::BadLocalFlow)); }; + if !scrp.is_stream_open { + return Ok(None); + } if !scrp.stream_state.can_send_stream::() { return Err(protocol_err(Http2Error::InvalidSendStreamState)); } let mut wp = WindowsPair::new(hdpm.windows, &mut scrp.windows); + 'msg: { let available_send = if let Ok(elem @ 1..=u32::MAX) = u32::try_from(wp.available_send()) { elem } else { if !*has_headers { - if write_standalone_headers::( + if write_standalone_headers::( data_bytes, headers, (hpack_enc, hpack_enc_buffer), (hsreqh, hsresh), - *hdpm.is_conn_open, + is_conn_open, hdpm.hps.max_frame_len, - hdpm.stream, + hdpm.stream_writer, stream_id, ) .await? @@ -133,19 +169,20 @@ where change_initial_stream_state::(&mut scrp.stream_state); *has_headers = true; } - return Ok(None); + scrp.waker.clone_from(waker); + return Ok(Some(false)); }; if !*has_headers { - if fast_path::( + if fast_path::( available_send, data_bytes, headers, (hpack_enc, hpack_enc_buffer), (hsreqh, hsresh), - *hdpm.is_conn_open, + is_conn_open, hdpm.hps.max_frame_len, - hdpm.stream, + hdpm.stream_writer, stream_id, &mut wp, ) @@ -163,9 +200,9 @@ where has_data, &mut data_bytes, headers.has_trailers(), - *hdpm.is_conn_open, + is_conn_open, hdpm.hps.max_frame_len, - hdpm.stream, + hdpm.stream_writer, stream_id, &mut wp, ) @@ -173,16 +210,17 @@ where { break 'msg; } - return Ok(None); + scrp.waker.clone_from(waker); + return Ok(Some(false)); } write_standalone_trailers( headers, (hpack_enc, hpack_enc_buffer), (hsreqh, hsresh), - *hdpm.is_conn_open, + is_conn_open, hdpm.hps.max_frame_len, - hdpm.stream, + hdpm.stream_writer, stream_id, ) .await?; @@ -190,7 +228,7 @@ where change_final_stream_state::(&mut scrp.stream_state); cb(hdpm); - Ok(Some(())) + Ok(Some(true)) } #[inline] @@ -227,20 +265,20 @@ fn encode_trailers( // Tries to send everything in a single round trip. If not possible, will at least send headers. #[inline] -async fn fast_path( +async fn fast_path( available_send: u32, data_bytes: &[u8], headers: &Headers, (hpack_enc, hpack_enc_buffer): (&mut HpackEncoder, &mut Vector), (hsreqh, hsresh): (HpackStaticRequestHeaders<'_>, HpackStaticResponseHeaders), - is_conn_open: bool, + is_conn_open: &AtomicBool, max_frame_len: u32, - stream: &mut S, + stream: &mut SW, stream_id: U31, wp: &mut WindowsPair<'_>, ) -> crate::Result where - S: Stream, + SW: StreamWriter, { #[inline] fn has_valid(slice: &[u8], len: u32) -> Option { @@ -251,7 +289,6 @@ where } encode_headers::(headers, (hpack_enc, hpack_enc_buffer), (hsreqh, hsresh))?; - 'headers_with_others: { let Some(data_len) = has_valid(data_bytes, available_send) else { break 'headers_with_others; @@ -335,16 +372,16 @@ fn split_frame_bytes(bytes: &[u8], len: u32) -> (&[u8], &[u8]) { } #[inline] -async fn write_headers_or_trailers( +async fn write_headers_or_trailers( frame0: &mut HeadersFrame<'_>, - is_conn_open: bool, + is_conn_open: &AtomicBool, (left0, right0): (&[u8], &[u8]), max_frame_len: u32, - stream: &mut S, + stream: &mut SW, stream_id: U31, ) -> crate::Result<()> where - S: Stream, + SW: StreamWriter, { if let (left1 @ [_, ..], right1) = split_frame_bytes(right0, max_frame_len) { let mut frame1 = ContinuationFrame::new(stream_id); @@ -363,19 +400,19 @@ where /// Tries to send up two data frames in a single round trip. If exhausted, returns `true`. #[inline] -async fn write_standalone_data( +async fn write_standalone_data( available_send: u32, has_data: &mut bool, data_bytes: &mut &[u8], has_trailers: bool, - is_conn_open: bool, + is_conn_open: &AtomicBool, max_frame_len: u32, - stream: &mut S, + stream: &mut SW, stream_id: U31, wp: &mut WindowsPair<'_>, ) -> crate::Result where - S: Stream, + SW: StreamWriter, { #[inline] fn should_stop( @@ -442,18 +479,18 @@ where // Tries to send all initial headers #[inline] -async fn write_standalone_headers( +async fn write_standalone_headers( data_bytes: &[u8], headers: &Headers, (hpack_enc, hpack_enc_buffer): (&mut HpackEncoder, &mut Vector), (hsreqh, hsresh): (HpackStaticRequestHeaders<'_>, HpackStaticResponseHeaders), - is_conn_open: bool, + is_conn_open: &AtomicBool, max_frame_len: u32, - stream: &mut S, + stream: &mut SW, stream_id: U31, ) -> crate::Result where - S: Stream, + SW: StreamWriter, { encode_headers::(headers, (hpack_enc, hpack_enc_buffer), (hsreqh, hsresh))?; let (left0, right0) = split_frame_bytes(hpack_enc_buffer, max_frame_len); @@ -478,17 +515,17 @@ where /// Tries to send all trailer headers #[inline] -async fn write_standalone_trailers( +async fn write_standalone_trailers( headers: &Headers, (hpack_enc, hpack_enc_buffer): (&mut HpackEncoder, &mut Vector), (hsreqh, hsresh): (HpackStaticRequestHeaders<'_>, HpackStaticResponseHeaders), - is_conn_open: bool, + is_conn_open: &AtomicBool, max_frame_len: u32, - stream: &mut S, + stream: &mut SW, stream_id: U31, ) -> crate::Result<()> where - S: Stream, + SW: StreamWriter, { hpack_enc_buffer.clear(); encode_trailers(headers, (hpack_enc, hpack_enc_buffer))?; diff --git a/wtx/src/http2/server_stream.rs b/wtx/src/http2/server_stream.rs index 27c4597b..e78b18ef 100644 --- a/wtx/src/http2/server_stream.rs +++ b/wtx/src/http2/server_stream.rs @@ -1,18 +1,23 @@ use crate::{ http::{Method, ReqResBuffer, ReqResData, Response}, http2::{ - misc::{check_content_length, send_go_away, send_reset_stream}, + misc::{ + manage_recurrent_stream_receiving, process_higher_operation_err, send_go_away, + send_reset_stream, + }, send_msg::send_msg, HpackStaticRequestHeaders, HpackStaticResponseHeaders, Http2Buffer, Http2Data, Http2ErrorCode, - StreamControlRecvParams, U31, + IsConnOpenSync, StreamControlRecvParams, U31, }, - misc::{Lease, LeaseMut, Lock, RefCounter, Stream, _Span}, + misc::{Either, Lease, LeaseMut, Lock, RefCounter, StreamWriter, _Span}, }; +use core::{future::poll_fn, pin::pin}; /// Created when a server receives an initial stream. #[derive(Debug)] pub struct ServerStream { hd: HD, + is_conn_open: IsConnOpenSync, method: Method, span: _Span, stream_id: U31, @@ -20,78 +25,87 @@ pub struct ServerStream { impl ServerStream { #[inline] - pub(crate) const fn new(hd: HD, method: Method, span: _Span, stream_id: U31) -> Self { - Self { hd, method, span, stream_id } + pub(crate) const fn new( + hd: HD, + is_conn_open: IsConnOpenSync, + method: Method, + span: _Span, + stream_id: U31, + ) -> Self { + Self { hd, is_conn_open, method, span, stream_id } } } -impl ServerStream +impl ServerStream where HB: LeaseMut>, HD: RefCounter, - HD::Item: Lock>, + HD::Item: Lock>, RRB: LeaseMut, - S: Stream, + SW: StreamWriter, { /// Receive request /// /// Higher operation that awaits for the data necessary to build a request. /// + /// Returns [`Either::Left`] if the network/stream connection has been closed, either locally + /// or externally. + /// /// Shouldn't be called more than once. #[inline] - pub async fn recv_req(&mut self) -> crate::Result<(RRB, Method)> { - let _e = self.span._enter(); + pub async fn recv_req(&mut self) -> crate::Result> { + let Self { hd, is_conn_open, method, span, stream_id } = self; + let _e = span._enter(); _trace!("Receiving request"); - process_higher_operation!( - &self.hd, - |guard| { - let rslt = 'rslt: { - let hdpm = guard.parts_mut(); - if hdpm.hb.sorp.get(&self.stream_id).map_or(false, |el| el.stream_state.recv_eos()) { - if let Some(sorp) = hdpm.hb.sorp.remove(&self.stream_id) { - if let Some(idx) = sorp.content_length { - if let Err(err) = check_content_length(idx, &sorp) { - break 'rslt Err(err); - } - } - drop(hdpm.hb.scrp.insert( - self.stream_id, - StreamControlRecvParams { - span: self.span.clone(), - stream_state: sorp.stream_state, - windows: sorp.windows, - }, - )); - break 'rslt Ok(Some((sorp.rrb, self.method))); - } - } - Ok(None) - }; - rslt - }, - |_guard, elem| Ok(elem) - ) + let mut lock_pin = pin!(hd.lock()); + let rslt = poll_fn(|cx| { + let mut lock = lock_pin!(cx, hd, lock_pin); + manage_recurrent_stream_receiving( + cx, + lock.parts_mut(), + is_conn_open, + stream_id, + |local_cx, hdpm, sorp| { + drop(hdpm.hb.scrp.insert( + *stream_id, + StreamControlRecvParams { + is_stream_open: true, + stream_state: sorp.stream_state, + waker: local_cx.waker().clone(), + windows: sorp.windows, + }, + )); + *method + }, + ) + }) + .await; + if let Err(err) = &rslt { + process_higher_operation_err(&err, hd).await; + } + rslt } /// Sends a GOAWAY frame to the peer, which cancels the connection and consequently all ongoing /// streams. #[inline] pub async fn send_go_away(self, error_code: Http2ErrorCode) { - let mut guard = self.hd.lock().await; - let hdpm = guard.parts_mut(); - send_go_away(error_code, hdpm.is_conn_open, *hdpm.last_stream_id, hdpm.stream).await; + send_go_away(error_code, &mut self.hd.lock().await.parts_mut()).await; } /// Send Response /// /// Higher operation that sends all data related to a response and then closes the stream. /// + /// Returns [`Option::None`] if the network/stream connection has been closed, either locally + /// or externally. + /// /// Should be called after [`Self::recv_req`] is successfully executed. #[inline] - pub async fn send_res(self, res: Response) -> crate::Result<()> + pub async fn send_res(self, res: Response) -> crate::Result> where - D: ReqResData, - D::Body: Lease<[u8]>, + RRD: ReqResData, + RRD::Body: Lease<[u8]>, { let _e = self.span._enter(); _trace!("Sending response"); @@ -103,6 +117,7 @@ where HpackStaticRequestHeaders::EMPTY, HpackStaticResponseHeaders { status_code: Some(res.status_code) }, ), + &self.is_conn_open, self.stream_id, |hdpm| { drop(hdpm.hb.scrp.remove(&self.stream_id)); @@ -115,6 +130,13 @@ where pub async fn send_reset(self, error_code: Http2ErrorCode) { let mut guard = self.hd.lock().await; let hdpm = guard.parts_mut(); - send_reset_stream(error_code, hdpm.hb, hdpm.stream, self.stream_id).await; + let _ = send_reset_stream( + error_code, + &mut hdpm.hb.scrp, + &mut hdpm.hb.sorp, + hdpm.stream_writer, + self.stream_id, + ) + .await; } } diff --git a/wtx/src/http2/stream_receiver.rs b/wtx/src/http2/stream_receiver.rs index e4ccbc99..7496dd24 100644 --- a/wtx/src/http2/stream_receiver.rs +++ b/wtx/src/http2/stream_receiver.rs @@ -1,24 +1,30 @@ use crate::{ http::StatusCode, http2::{StreamState, Windows}, - misc::_Span, }; +use core::task::Waker; +/// Parameters used when a stream should receive any type of frame, including `HEADER` or +/// `DATA` frames. #[derive(Debug)] pub(crate) struct StreamOverallRecvParams { pub(crate) content_length: Option, pub(crate) body_len: u32, pub(crate) has_initial_header: bool, + pub(crate) is_stream_open: bool, pub(crate) rrb: RRB, - pub(crate) span: _Span, pub(crate) status_code: StatusCode, pub(crate) stream_state: StreamState, pub(crate) windows: Windows, + pub(crate) waker: Waker, } +/// Parameters used when a stream should only receive control frames like `RST_STREAM` or +/// `WINDOW_UPDATE`. This can happen when the stream finishes or when the stream is sending data. #[derive(Debug)] pub(crate) struct StreamControlRecvParams { - pub(crate) span: _Span, + pub(crate) is_stream_open: bool, pub(crate) stream_state: StreamState, + pub(crate) waker: Waker, pub(crate) windows: Windows, } diff --git a/wtx/src/http2/tests.rs b/wtx/src/http2/tests.rs index 3df8801b..82c16956 100644 --- a/wtx/src/http2/tests.rs +++ b/wtx/src/http2/tests.rs @@ -1,4 +1,3 @@ -#[cfg(feature = "tokio")] mod connections; #[cfg(all(feature = "_integration-tests", feature = "serde_json"))] mod hpack; diff --git a/wtx/src/http2/tests/connections.rs b/wtx/src/http2/tests/connections.rs index c90a8223..81e995b0 100644 --- a/wtx/src/http2/tests/connections.rs +++ b/wtx/src/http2/tests/connections.rs @@ -1,16 +1,16 @@ use crate::{ http::{Headers, Method, ReqResBuffer, ReqResData, Request, StatusCode}, http2::{Http2Buffer, Http2ErrorCode, Http2Params, Http2Tokio}, - misc::{UriRef, UriString, _uri}, + misc::{Either, UriRef, UriString, _uri}, rng::NoStdRng, }; use core::time::Duration; -use tokio::net::{TcpListener, TcpStream}; +use tokio::net::{tcp::OwnedWriteHalf, TcpListener, TcpStream}; #[tokio::test] async fn connections() { - #[cfg(feature = "_tracing-subscriber")] - let _rslt = crate::misc::tracing_subscriber_init(); + #[cfg(feature = "_tracing-tree")] + let _rslt = crate::misc::tracing_tree_init(); let uri = _uri(); server(&uri).await; client(uri).await; @@ -20,36 +20,41 @@ async fn client(uri: UriString) { let mut rrb = ReqResBuffer::default(); rrb.headers_mut().set_max_bytes(6); rrb.headers_mut().reserve(6, 1).unwrap(); - let mut client = Http2Tokio::connect( + let (frame_header, mut http2) = Http2Tokio::connect( Http2Buffer::new(NoStdRng::default()), Http2Params::default(), - TcpStream::connect(uri.host()).await.unwrap(), + TcpStream::connect(uri.host()).await.unwrap().into_split(), ) .await .unwrap(); + let _jh = tokio::spawn(async { + if let Err(err) = frame_header.await { + panic!("{:?}", err); + } + }); let uri_ref = uri.to_ref(); - rrb = stream_client(&mut client, rrb, &uri_ref).await; + rrb = stream_client(&mut http2, rrb, &uri_ref).await; _0(rrb.body(), rrb.headers()); rrb.clear(); rrb.headers_mut().push_front((b"123", b"456").into(), &[]).unwrap(); - rrb = stream_client(&mut client, rrb, &uri_ref).await; + rrb = stream_client(&mut http2, rrb, &uri_ref).await; _1(rrb.body(), rrb.headers()); rrb.clear(); rrb.extend_body(b"123").unwrap(); - rrb = stream_client(&mut client, rrb, &uri_ref).await; + rrb = stream_client(&mut http2, rrb, &uri_ref).await; _2(rrb.body(), rrb.headers()); rrb.clear(); rrb.extend_body(b"123").unwrap(); rrb.headers_mut().push_front((b"123", b"456").into(), &[]).unwrap(); - rrb = stream_client(&mut client, rrb, &uri_ref).await; + rrb = stream_client(&mut http2, rrb, &uri_ref).await; _3(rrb.body(), rrb.headers()); - client.send_go_away(Http2ErrorCode::NoError).await; + http2.send_go_away(Http2ErrorCode::NoError).await; tokio::time::sleep(Duration::from_millis(100)).await; } @@ -59,24 +64,28 @@ async fn server(uri: &UriString) { let _server_jh = tokio::spawn(async move { let (stream, _) = listener.accept().await.unwrap(); let mut rrb = ReqResBuffer::default(); - let mut server = - Http2Tokio::accept(Http2Buffer::new(NoStdRng::default()), Http2Params::default(), stream) - .await - .unwrap(); + let (frame_header, mut http2) = Http2Tokio::accept( + Http2Buffer::new(NoStdRng::default()), + Http2Params::default(), + stream.into_split(), + ) + .await + .unwrap(); + let _jh = tokio::spawn(frame_header); - rrb = stream_server(&mut server, rrb, |req| { + rrb = stream_server(&mut http2, rrb, |req| { _0(req.rrd.body(), req.rrd.headers()); }) .await; - rrb = stream_server(&mut server, rrb, |req| { + rrb = stream_server(&mut http2, rrb, |req| { _1(req.rrd.body(), req.rrd.headers()); }) .await; - rrb = stream_server(&mut server, rrb, |req| { + rrb = stream_server(&mut http2, rrb, |req| { _2(req.rrd.body(), req.rrd.headers()); }) .await; - let _rrb = stream_server(&mut server, rrb, |req| { + let _rrb = stream_server(&mut http2, rrb, |req| { _3(req.rrd.body(), req.rrd.headers()); }) .await; @@ -84,27 +93,34 @@ async fn server(uri: &UriString) { } async fn stream_server( - server: &mut Http2Tokio, ReqResBuffer, TcpStream, false>, + server: &mut Http2Tokio, ReqResBuffer, OwnedWriteHalf, false>, rrb: ReqResBuffer, mut cb: impl FnMut(Request<&mut ReqResBuffer>), ) -> ReqResBuffer { loop { - let mut stream = server.stream(rrb).await.unwrap(); - let (mut req_rrb, method) = stream.recv_req().await.unwrap(); + let Either::Right(mut stream) = server.stream(rrb).await else { + panic!(); + }; + let Ok(Either::Right((mut req_rrb, method))) = stream.recv_req().await else { + panic!(); + }; cb(req_rrb.as_http2_request_mut(method)); - stream.send_res(req_rrb.as_http2_response(StatusCode::Ok)).await.unwrap(); + stream.send_res(req_rrb.as_http2_response(StatusCode::Ok)).await.unwrap().unwrap(); break req_rrb; } } async fn stream_client( - client: &mut Http2Tokio, ReqResBuffer, TcpStream, true>, + client: &mut Http2Tokio, ReqResBuffer, OwnedWriteHalf, true>, rrb: ReqResBuffer, uri: &UriRef<'_>, ) -> ReqResBuffer { let mut stream = client.stream().await.unwrap(); - stream.send_req(rrb.as_http2_request(Method::Get), uri).await.unwrap(); - stream.recv_res(rrb).await.unwrap().0 + stream.send_req(rrb.as_http2_request(Method::Get), uri).await.unwrap().unwrap(); + match stream.recv_res(rrb).await.unwrap() { + Either::Left(_) => panic!(), + Either::Right(elem) => elem.0, + } } #[track_caller] diff --git a/wtx/src/http2/window.rs b/wtx/src/http2/window.rs index 85d80d94..1f573b5d 100644 --- a/wtx/src/http2/window.rs +++ b/wtx/src/http2/window.rs @@ -3,8 +3,9 @@ use crate::{ http2_params_send::Http2ParamsSend, misc::write_array, Http2Error, Http2ErrorCode, Http2Params, WindowUpdateFrame, U31, }, - misc::Stream, + misc::StreamWriter, }; +use core::sync::atomic::AtomicBool; /// A "credit" system used to restrain the exchange of data. #[derive(Clone, Copy, Debug)] @@ -122,16 +123,16 @@ impl<'any> WindowsPair<'any> { /// Controls window sizes received from external sources. Invalid or negative values trigger a /// frame dispatch to return to the default window size. #[inline] - pub(crate) async fn withdrawn_recv( + pub(crate) async fn withdrawn_recv( &mut self, hp: &Http2Params, - is_conn_open: bool, - stream: &mut S, + is_conn_open: &AtomicBool, + stream_writer: &mut SW, stream_id: U31, value: U31, ) -> crate::Result<()> where - S: Stream, + SW: StreamWriter, { let iwl = U31::from_u32(hp.initial_window_len()).i32(); self.conn.recv.withdrawn(None, value.i32())?; @@ -144,7 +145,7 @@ impl<'any> WindowsPair<'any> { write_array( [&WindowUpdateFrame::new(U31::from_i32(stream_value), stream_id)?.bytes()], is_conn_open, - stream, + stream_writer, ) .await?; } @@ -154,7 +155,7 @@ impl<'any> WindowsPair<'any> { write_array( [&WindowUpdateFrame::new(U31::from_i32(conn_value), U31::ZERO)?.bytes()], is_conn_open, - stream, + stream_writer, ) .await?; } @@ -169,7 +170,7 @@ impl<'any> WindowsPair<'any> { &WindowUpdateFrame::new(U31::from_i32(stream_value), stream_id)?.bytes(), ], is_conn_open, - stream, + stream_writer, ) .await?; } diff --git a/wtx/src/lib.rs b/wtx/src/lib.rs index 181cd006..d5824d6f 100644 --- a/wtx/src/lib.rs +++ b/wtx/src/lib.rs @@ -2,7 +2,7 @@ #![cfg_attr(feature = "_bench", allow(soft_unstable))] #![cfg_attr(feature = "_bench", feature(test))] #![doc = include_str!("../README.md")] -#![feature(macro_metavar_expr, return_type_notation)] +#![feature(macro_metavar_expr, noop_waker, return_type_notation)] #![no_std] extern crate alloc; diff --git a/wtx/src/macros.rs b/wtx/src/macros.rs index 7dd9b662..6f922118 100644 --- a/wtx/src/macros.rs +++ b/wtx/src/macros.rs @@ -228,7 +228,7 @@ macro_rules! _max_frames_mismatches { macro_rules! _trace { ($($tt:tt)+) => { #[cfg(feature = "tracing")] - tracing::trace!($($tt)+); + tracing::trace!($($tt)+) }; } diff --git a/wtx/src/misc.rs b/wtx/src/misc.rs index ba776c16..d74f00f8 100644 --- a/wtx/src/misc.rs +++ b/wtx/src/misc.rs @@ -9,7 +9,6 @@ mod either; mod enum_var_strings; mod filled_buffer_writer; mod fn_fut; -mod fx_hasher; mod generic_time; mod incomplete_utf8_char; mod iter_wrapper; @@ -18,7 +17,6 @@ mod lock; mod mem_transfer; mod optimization; mod partitioned_filled_buffer; -mod poll_once; mod query_writer; mod queue; mod queue_utils; @@ -46,20 +44,18 @@ pub use either::Either; pub use enum_var_strings::EnumVarStrings; pub use filled_buffer_writer::FilledBufferWriter; pub use fn_fut::{FnFut, FnMutFut, FnOnceFut}; -pub use fx_hasher::FxHasher; pub use generic_time::GenericTime; pub use incomplete_utf8_char::{CompletionErr, IncompleteUtf8Char}; pub use iter_wrapper::IterWrapper; pub use lease::{Lease, LeaseMut}; pub use lock::{Lock, SyncLock}; pub use optimization::*; -pub use poll_once::PollOnce; pub use query_writer::QueryWriter; pub use queue::{Queue, QueueError}; pub use ref_counter::RefCounter; pub use role::Role; pub use single_type_storage::SingleTypeStorage; -pub use stream::{BytesStream, Stream, TlsStream}; +pub use stream::{BytesStream, Stream, StreamReader, StreamWithTls, StreamWriter}; pub use uri::{Uri, UriArrayString, UriRef, UriString}; pub use usize::Usize; pub use utf8_errors::{BasicUtf8Error, ExtUtf8Error, StdUtf8Error}; @@ -67,7 +63,7 @@ pub use vector::{Vector, VectorError}; #[allow(unused_imports, reason = "used in other features")] pub(crate) use { blocks_queue::{Block, BlocksQueue}, - mem_transfer::_shift_bytes, + mem_transfer::_shift_copyable_chunks, partitioned_filled_buffer::PartitionedFilledBuffer, span::{_Entered, _Span}, }; @@ -84,34 +80,28 @@ pub fn into_rslt(opt: Option) -> crate::Result { #[allow(clippy::unused_async, reason = "depends on the selected set of features")] #[inline] pub async fn sleep(duration: Duration) -> crate::Result<()> { - #[cfg(all(feature = "async-std", not(feature = "tokio")))] - { - async_std::task::sleep(duration).await; - Ok(()) - } - #[cfg(all(feature = "tokio", not(feature = "async-std")))] + #[cfg(feature = "tokio")] { tokio::time::sleep(duration).await; Ok(()) } - #[cfg(any( - all(feature = "async-std", feature = "tokio"), - all(not(feature = "tokio"), not(feature = "async-std")) - ))] + #[cfg(not(feature = "tokio"))] { - // Open to better alternatives let now = GenericTime::now(); - loop { + core::future::poll_fn(|cx| { if now.elapsed()? >= duration { - return Ok(()); + return core::task::Poll::Ready(Ok(())); } - } + cx.waker().wake_by_ref(); + core::task::Poll::Pending + }) + .await } } /// A tracing register with optioned parameters. -#[cfg(feature = "_tracing-subscriber")] -pub fn tracing_subscriber_init() -> Result<(), tracing_subscriber::util::TryInitError> { +#[cfg(feature = "_tracing-tree")] +pub fn tracing_tree_init() -> Result<(), tracing_subscriber::util::TryInitError> { use tracing_subscriber::{ prelude::__tracing_subscriber_SubscriberExt, util::SubscriberInitExt, EnvFilter, }; @@ -217,15 +207,15 @@ pub(crate) fn _random_state(mut rng: impl crate::rng::Rng) -> ahash::RandomState ahash::RandomState::with_seeds(seed0, seed1, seed2, seed3) } -pub(crate) async fn _read_until( +pub(crate) async fn _read_until( buffer: &mut [u8], read: &mut usize, start: usize, - stream: &mut S, + stream_reader: &mut SR, ) -> crate::Result<[u8; LEN]> where [u8; LEN]: Default, - S: Stream, + SR: StreamReader, { let until = start.wrapping_add(LEN); for _ in 0..LEN { @@ -234,7 +224,7 @@ where break; } let actual_buffer = buffer.get_mut(*read..).unwrap_or_default(); - let local_read = stream.read(actual_buffer).await?; + let local_read = stream_reader.read(actual_buffer).await?; if local_read == 0 { return Err(crate::Error::MISC_UnexpectedStreamEOF); } diff --git a/wtx/src/misc/array_chunks.rs b/wtx/src/misc/array_chunks.rs index 0267bdd7..ecc3b534 100644 --- a/wtx/src/misc/array_chunks.rs +++ b/wtx/src/misc/array_chunks.rs @@ -24,7 +24,7 @@ macro_rules! create_and_impl { } impl<'slice, T, const N: usize> $name<'slice, T, N> { - #[expect(clippy::arithmetic_side_effects, reason = "`N` is not zero, therefore, no following arithmetic will panic")] + #[expect(clippy::arithmetic_side_effects, reason = "`N` is not zero")] #[inline] /// Returns an iterator over N elements of the slice at a time, starting at the beginning of /// the slice. diff --git a/wtx/src/misc/fx_hasher.rs b/wtx/src/misc/fx_hasher.rs deleted file mode 100644 index 5a4b101d..00000000 --- a/wtx/src/misc/fx_hasher.rs +++ /dev/null @@ -1,46 +0,0 @@ -use core::{hash::Hasher, ops::BitXor}; - -const K: u64 = 0x517c_c1b7_2722_0a95; - -/// -/// -/// Has a fixed output standard, as such, it can be used in algorithms where a hash needs to be -/// sent over the network, or persisted. -#[derive(Debug)] -pub struct FxHasher(u64); - -impl FxHasher { - /// Creates a default instance. - #[inline] - pub const fn new() -> FxHasher { - Self(0) - } - - /// Creates a instance with a given seed. - #[inline] - pub const fn with_seed(seed: u64) -> FxHasher { - Self(seed) - } -} - -impl Default for FxHasher { - #[inline] - fn default() -> Self { - Self::new() - } -} - -impl Hasher for FxHasher { - #[inline] - fn finish(&self) -> u64 { - self.0 - } - - #[inline] - fn write(&mut self, bytes: &[u8]) { - for byte in bytes.iter().copied() { - let into: u64 = byte.into(); - self.0 = self.0.rotate_left(5).bitxor(into).wrapping_mul(K); - } - } -} diff --git a/wtx/src/misc/generic_time.rs b/wtx/src/misc/generic_time.rs index 8f8ca274..273e922f 100644 --- a/wtx/src/misc/generic_time.rs +++ b/wtx/src/misc/generic_time.rs @@ -7,9 +7,7 @@ use core::time::Duration; pub struct GenericTime { #[cfg(feature = "std")] inner: std::time::SystemTime, - #[cfg(all(feature = "embassy-time", not(any(feature = "std"))))] - inner: embassy_time::Instant, - #[cfg(not(any(feature = "std", feature = "embassy-time")))] + #[cfg(not(feature = "std"))] _inner: (), } @@ -21,11 +19,7 @@ impl GenericTime { { Self { inner: std::time::SystemTime::now() } } - #[cfg(all(feature = "embassy-time", not(any(feature = "std"))))] - { - Self { inner: embassy_time::Instant::now() } - } - #[cfg(not(any(feature = "std", feature = "embassy-time")))] + #[cfg(not(feature = "std"))] Self { _inner: () } } @@ -40,17 +34,7 @@ impl GenericTime { .duration_since(_earlier.inner) .map_err(|_err| crate::Error::MISC_InvalidHardwareTime) } - #[cfg(all(feature = "embassy-time", not(any(feature = "std"))))] - { - Ok(Duration::from_micros( - self - .inner - .checked_duration_since(_earlier.inner) - .ok_or(crate::Error::MISC_InvalidHardwareTime)? - .as_micros(), - )) - } - #[cfg(not(any(feature = "std", feature = "embassy-time")))] + #[cfg(not(feature = "std"))] { Err(crate::Error::MISC_GenericTimeNeedsBackend) } @@ -69,11 +53,7 @@ impl GenericTime { { Self::now().duration_since(Self { inner: std::time::UNIX_EPOCH }) } - #[cfg(all(feature = "embassy-time", not(any(feature = "std"))))] - { - Self::now().duration_since(Self { inner: embassy_time::Instant::from_micros(0) }) - } - #[cfg(not(any(feature = "std", feature = "embassy-time")))] + #[cfg(not(feature = "std"))] { Err(crate::Error::MISC_GenericTimeNeedsBackend) } diff --git a/wtx/src/misc/lease.rs b/wtx/src/misc/lease.rs index 5b26e43c..1359b427 100644 --- a/wtx/src/misc/lease.rs +++ b/wtx/src/misc/lease.rs @@ -210,26 +210,6 @@ mod str { } } -#[cfg(feature = "parking_lot")] -mod parking_lot { - use crate::misc::{Lease, LeaseMut}; - use parking_lot::MutexGuard; - - impl Lease for MutexGuard<'_, T> { - #[inline] - fn lease(&self) -> &T { - self - } - } - - impl LeaseMut for MutexGuard<'_, T> { - #[inline] - fn lease_mut(&mut self) -> &mut T { - self - } - } -} - #[cfg(feature = "tokio")] mod tokio { use crate::misc::{Lease, LeaseMut}; diff --git a/wtx/src/misc/lock.rs b/wtx/src/misc/lock.rs index 2d9d8d50..82ad76f7 100644 --- a/wtx/src/misc/lock.rs +++ b/wtx/src/misc/lock.rs @@ -145,58 +145,6 @@ where } } -#[cfg(feature = "embassy-sync")] -mod embassy { - use crate::misc::Lock; - use embassy_sync::{ - blocking_mutex::raw::RawMutex, - mutex::{Mutex, MutexGuard}, - }; - - impl Lock for Mutex - where - M: RawMutex, - { - type Guard<'guard> = MutexGuard<'guard, M, Self::Resource> - where - Self: 'guard; - type Resource = T; - - #[inline] - fn new(resource: Self::Resource) -> Self { - Mutex::new(resource) - } - - #[inline] - async fn lock(&self) -> Self::Guard<'_> { - (*self).lock().await - } - } -} - -#[cfg(feature = "parking_lot")] -mod parking_lot { - use crate::misc::SyncLock; - use parking_lot::{Mutex, MutexGuard}; - - impl SyncLock for Mutex { - type Guard<'guard> = MutexGuard<'guard, Self::Resource> - where - Self: 'guard; - type Resource = T; - - #[inline] - fn new(resource: Self::Resource) -> Self { - Mutex::new(resource) - } - - #[inline] - fn lock(&self) -> Self::Guard<'_> { - (*self).lock() - } - } -} - #[cfg(feature = "std")] mod std { use crate::misc::SyncLock; diff --git a/wtx/src/misc/mem_transfer.rs b/wtx/src/misc/mem_transfer.rs index 79b573b1..97dc8743 100644 --- a/wtx/src/misc/mem_transfer.rs +++ b/wtx/src/misc/mem_transfer.rs @@ -2,30 +2,25 @@ use core::{ops::Range, ptr}; /// Transfers sequential `iter` chunks delimited by indices to a region starting at `begin`. /// -/// ```ignore -/// // For example, a vector fragmented in 3 pieces where the last two digits of each piece are -/// // shifted to the left +/// ### Three delimited chunks shifted to the left /// -/// | | | | -/// A: |00|01|02|03|04|05|06|07|08|09|10|11| -/// | << <<| | | +/// ```ignore +/// |00|01|02|03|04|05|06|07|08|09|10|11| +/// << << /// -/// | | | | -/// A: |02|03|02|03|04|05|06|07|08|09|10|11| -/// |^^ ^^ | << <<| | +/// |02|03|02|03|04|05|06|07|08|09|10|11| +/// ^^ ^^ << << /// -/// | | | | -/// A: |02|03|06|07|04|05|06|07|08|09|10|11| -/// |^^ ^^ ^^ ^^| | << <<| +/// |02|03|06|07|04|05|06|07|08|09|10|11| +/// ^^ ^^ ^^ ^^ << << /// -/// | | | | -/// A: |02|03|06|07|10|11|06|07|08|09|10|11| -/// |^^ ^^ ^^ ^^|^^ ^^ | | +/// |02|03|06|07|10|11|06|07|08|09|10|11| +/// ^^ ^^ ^^ ^^ ^^ ^^ /// -/// A: |02|03|06|07|10|11| +/// |02|03|06|07|10|11| /// ``` #[inline] -pub(crate) fn _shift_bytes( +pub(crate) fn _shift_copyable_chunks( begin: usize, slice: &mut [T], iter: impl IntoIterator>, @@ -66,7 +61,7 @@ where #[cfg(feature = "_proptest")] #[cfg(test)] mod proptest { - use crate::misc::_shift_bytes; + use crate::misc::_shift_copyable_chunks; use alloc::vec::Vec; use core::ops::Range; @@ -77,7 +72,7 @@ mod proptest { let mut data_clone = data.clone(); begin = begin.min(data.len()); end = end.min(data.len()); - let rslt = _shift_bytes(0, &mut data, [begin..end]); + let rslt = _shift_copyable_chunks(0, &mut data, [begin..end]); data_clone.rotate_left(begin); data_clone.truncate(rslt.len()); assert_eq!(rslt, &data_clone); @@ -86,12 +81,12 @@ mod proptest { #[cfg(test)] mod test { - use crate::misc::mem_transfer::_shift_bytes; + use crate::misc::mem_transfer::_shift_copyable_chunks; #[test] fn _shift_bytes_has_correct_outputs() { let bytes = &mut [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; - assert_eq!(_shift_bytes(2, bytes, [4..6, 8..10]), &mut [0, 1, 4, 5, 8, 9]); + assert_eq!(_shift_copyable_chunks(2, bytes, [4..6, 8..10]), &mut [0, 1, 4, 5, 8, 9]); assert_eq!(bytes, &mut [0, 1, 4, 5, 8, 9, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]); } } diff --git a/wtx/src/misc/poll_once.rs b/wtx/src/misc/poll_once.rs deleted file mode 100644 index c53b491b..00000000 --- a/wtx/src/misc/poll_once.rs +++ /dev/null @@ -1,33 +0,0 @@ -use core::{ - fmt::{Debug, Formatter}, - pin::Pin, - task::{Context, Poll}, -}; - -/// Pools a future in only one try. -pub struct PollOnce( - /// Future - pub F, -); - -impl Debug for PollOnce { - #[inline] - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), core::fmt::Error> { - f.debug_tuple("PollOnce").finish() - } -} - -impl Future for PollOnce -where - F: Future + Unpin, -{ - type Output = Option; - - #[inline] - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - match Pin::new(&mut self.0).poll(cx) { - Poll::Ready(t) => Poll::Ready(Some(t)), - Poll::Pending => Poll::Ready(None), - } - } -} diff --git a/wtx/src/misc/queue.rs b/wtx/src/misc/queue.rs index 65bdbf80..85c32a18 100644 --- a/wtx/src/misc/queue.rs +++ b/wtx/src/misc/queue.rs @@ -40,7 +40,7 @@ pub enum QueueError { WithCapacityOverflow, } -/// A circular buffer where elements are added in only one-way. +/// A circular buffer. pub struct Queue { data: Vector, head: usize, diff --git a/wtx/src/misc/queue_utils.rs b/wtx/src/misc/queue_utils.rs index 369f57bf..81f1f29f 100644 --- a/wtx/src/misc/queue_utils.rs +++ b/wtx/src/misc/queue_utils.rs @@ -1,4 +1,4 @@ -use crate::misc::{Vector, _shift_bytes}; +use crate::misc::{Vector, _shift_copyable_chunks}; use core::{hint::assert_unchecked, iter, ptr}; /// If memory is allocated, tail elements are shifted to the right. @@ -41,7 +41,7 @@ where unsafe { assert_unchecked(allocated.len() >= curr_head || prev_cap >= prev_head); } - let _ = _shift_bytes(curr_head, allocated, iter::once(prev_head..prev_cap)); + let _ = _shift_copyable_chunks(curr_head, allocated, iter::once(prev_head..prev_cap)); *head = curr_head; Ok(Some(cap_diff)) } diff --git a/wtx/src/misc/stream.rs b/wtx/src/misc/stream.rs index 18e1c24c..880a68e9 100644 --- a/wtx/src/misc/stream.rs +++ b/wtx/src/misc/stream.rs @@ -1,15 +1,3 @@ -macro_rules! _local_write_all { - ($bytes:expr, $write:expr) => {{ - while !$bytes.is_empty() { - match $write { - Err(e) => return Err(e.into()), - Ok(0) => return { Err(crate::Error::MISC_UnexpectedStreamEOF) }, - Ok(n) => $bytes = $bytes.get(n..).unwrap_or_default(), - } - } - }}; -} - macro_rules! _local_write_all_vectored { ($bytes:expr, |$io_slices:ident| $write:expr) => {{ let mut buffer = [std::io::IoSlice::new(&[]); 8]; @@ -24,627 +12,33 @@ macro_rules! _local_write_all_vectored { }}; } -use crate::misc::Lease; -use alloc::vec::Vec; -use core::cmp::Ordering; - -/// A stream of values produced asynchronously. -pub trait Stream { - /// Pulls some bytes from this source into the specified buffer, returning how many bytes - /// were read. - fn read(&mut self, bytes: &mut [u8]) -> impl Future>; - - /// Reads the exact number of bytes required to fill `bytes`. - #[inline] - fn read_exact(&mut self, bytes: &mut [u8]) -> impl Future> { - async move { - let mut idx = 0; - for _ in 0..bytes.len() { - if idx >= bytes.len() { - break; - } - let read = self.read(bytes.get_mut(idx..).unwrap_or_default()).await?; - if read == 0 { - return Err(crate::Error::MISC_UnexpectedStreamEOF); - } - idx = idx.wrapping_add(read); - } - Ok(()) - } - } - - /// Reads and at the same time discards exactly `len` bytes. - #[inline] - fn read_skip(&mut self, len: usize) -> impl Future> { - async move { - let mut buffer = [0; 32]; - let mut counter = len; - for _ in 0..len { - if counter == 0 { - break; - } - let slice = if let Some(el) = buffer.get_mut(..counter) { el } else { &mut buffer[..] }; - let read = self.read(slice).await?; - if read == 0 { - return Err(crate::Error::MISC_UnexpectedStreamEOF); - } - counter = counter.wrapping_sub(read); - } - Ok(()) - } - } - - /// Attempts to write ***all*** `bytes`. - fn write_all(&mut self, bytes: &[u8]) -> impl Future>; - - /// Attempts to write ***all*** `bytes` of all slices in a single syscall. - /// - /// # Panics - /// - /// If the length of the outermost slice is greater than 8. - - fn write_all_vectored(&mut self, bytes: &[&[u8]]) -> impl Future>; -} - -/// Transport Layer Security -pub trait TlsStream: Stream { - /// Channel binding data defined in [RFC 5929]. - /// - /// [RFC 5929]: https://tools.ietf.org/html/rfc5929 - type TlsServerEndPoint: Lease<[u8]>; - - /// See `Self::TlsServerEndPoint`. - fn tls_server_end_point(&self) -> crate::Result>; -} - -impl Stream for () { - #[inline] - async fn read(&mut self, _: &mut [u8]) -> crate::Result { - Ok(0) - } - - #[inline] - async fn write_all(&mut self, _: &[u8]) -> crate::Result<()> { - Ok(()) - } - - #[inline] - async fn write_all_vectored(&mut self, _: &[&[u8]]) -> crate::Result<()> { - Ok(()) - } -} - -impl Stream for &mut T -where - T: Stream, -{ - #[inline] - async fn read(&mut self, bytes: &mut [u8]) -> crate::Result { - (**self).read(bytes).await - } - - #[inline] - async fn write_all(&mut self, bytes: &[u8]) -> crate::Result<()> { - (**self).write_all(bytes).await - } - - #[inline] - async fn write_all_vectored(&mut self, bytes: &[&[u8]]) -> crate::Result<()> { - (**self).write_all_vectored(bytes).await - } -} - -/// Stores written data to transfer when read. -#[derive(Debug, Default)] -pub struct BytesStream { - buffer: Vec, - idx: usize, -} - -impl BytesStream { - /// Empties the internal buffer. - #[inline] - pub fn clear(&mut self) { - self.buffer.clear(); - self.idx = 0; - } -} - -impl Stream for BytesStream { - #[inline] - async fn read(&mut self, bytes: &mut [u8]) -> crate::Result { - let working_buffer = self.buffer.get(self.idx..).unwrap_or_default(); - let working_buffer_len = working_buffer.len(); - Ok(match working_buffer_len.cmp(&bytes.len()) { - Ordering::Less => { - bytes.get_mut(..working_buffer_len).unwrap_or_default().copy_from_slice(working_buffer); - self.clear(); - working_buffer_len - } - Ordering::Equal => { - bytes.copy_from_slice(working_buffer); - self.clear(); - working_buffer_len - } - Ordering::Greater => { - bytes.copy_from_slice(working_buffer.get(..bytes.len()).unwrap_or_default()); - self.idx = self.idx.wrapping_add(bytes.len()); - bytes.len() - } - }) - } - - #[inline] - async fn write_all(&mut self, bytes: &[u8]) -> crate::Result<()> { - self.buffer.extend_from_slice(bytes); - Ok(()) - } - - #[inline] - async fn write_all_vectored(&mut self, bytes: &[&[u8]]) -> crate::Result<()> { - for elem in bytes { - self.buffer.extend_from_slice(elem); - } - Ok(()) - } -} - -#[cfg(feature = "async-std")] -mod async_std { - use crate::misc::Stream; - use async_std::{ - io::{ReadExt, WriteExt}, - net::TcpStream, - }; - - impl Stream for TcpStream { - #[inline] - async fn read(&mut self, bytes: &mut [u8]) -> crate::Result { - Ok(::read(self, bytes).await?) - } - - #[inline] - async fn write_all(&mut self, bytes: &[u8]) -> crate::Result<()> { - ::write_all(self, bytes).await?; - Ok(()) - } - - #[inline] - async fn write_all_vectored(&mut self, bytes: &[&[u8]]) -> crate::Result<()> { - _local_write_all_vectored!(bytes, |io_slices| self.write_vectored(io_slices).await); - Ok(()) - } - } - - #[cfg(unix)] - impl Stream for async_std::os::unix::net::UnixStream { - #[inline] - async fn read(&mut self, bytes: &mut [u8]) -> crate::Result { - Ok(::read(self, bytes).await?) - } - - #[inline] - async fn write_all(&mut self, bytes: &[u8]) -> crate::Result<()> { - ::write_all(self, bytes).await?; - Ok(()) - } - - #[inline] - async fn write_all_vectored(&mut self, bytes: &[&[u8]]) -> crate::Result<()> { - _local_write_all_vectored!(bytes, |io_slices| self.write_vectored(io_slices).await); - Ok(()) - } - } -} - -#[cfg(feature = "embassy-net")] -mod embassy_net { - use crate::misc::Stream; - use embassy_net::tcp::TcpSocket; - - impl Stream for TcpSocket<'_> { - #[inline] - async fn read(&mut self, bytes: &mut [u8]) -> crate::Result { - Ok((*self).read(bytes).await?) - } - - #[inline] - async fn write_all(&mut self, mut bytes: &[u8]) -> crate::Result<()> { - _local_write_all!(bytes, Self::write(self, bytes).await); - Ok(()) - } - - #[inline] - async fn write_all_vectored(&mut self, bytes: &[&[u8]]) -> crate::Result<()> { - for elem in bytes { - self.write_all(elem).await?; - } - Ok(()) - } - } -} - -#[cfg(feature = "embedded-tls")] -mod embedded_tls { - use crate::misc::{stream::TlsStream, Stream}; - use embedded_io_async::{Read, Write}; - use embedded_tls::{TlsCipherSuite, TlsConnection}; - - impl<'any, S, C> Stream for TlsConnection<'any, S, C> - where - C: TlsCipherSuite + 'static, - S: Read + Write + 'any, - { - #[inline] - async fn read(&mut self, bytes: &mut [u8]) -> crate::Result { - Ok(::read(self, bytes).await?) - } - - #[inline] - async fn write_all(&mut self, bytes: &[u8]) -> crate::Result<()> { - ::write_all(self, bytes).await?; - self.flush().await?; - Ok(()) - } - - #[inline] - async fn write_all_vectored(&mut self, bytes: &[&[u8]]) -> crate::Result<()> { - for elem in bytes { - ::write_all(self, elem).await?; - } - Ok(()) - } - } - - impl<'any, S, C> TlsStream for TlsConnection<'any, S, C> - where - C: TlsCipherSuite + 'static, - S: Read + Write + 'any, - { - type TlsServerEndPoint = [u8; 0]; - - #[inline] - fn tls_server_end_point(&self) -> crate::Result> { - Ok(None) - } - } -} - -#[cfg(feature = "glommio")] -mod glommio { - use crate::misc::Stream; - use futures_lite::io::{AsyncReadExt, AsyncWriteExt}; - use glommio::net::TcpStream; - - impl Stream for TcpStream { - #[inline] - async fn read(&mut self, bytes: &mut [u8]) -> crate::Result { - Ok(::read(self, bytes).await?) - } - - #[inline] - async fn write_all(&mut self, bytes: &[u8]) -> crate::Result<()> { - ::write_all(self, bytes).await?; - Ok(()) - } - - #[inline] - async fn write_all_vectored(&mut self, bytes: &[&[u8]]) -> crate::Result<()> { - for elem in bytes { - ::write_all(self, elem).await?; - } - Ok(()) - } - } - - #[cfg(unix)] - impl Stream for glommio::net::UnixStream { - #[inline] - async fn read(&mut self, bytes: &mut [u8]) -> crate::Result { - Ok(::read(self, bytes).await?) - } - - #[inline] - async fn write_all(&mut self, bytes: &[u8]) -> crate::Result<()> { - ::write_all(self, bytes).await?; - Ok(()) - } - - #[inline] - async fn write_all_vectored(&mut self, bytes: &[&[u8]]) -> crate::Result<()> { - for elem in bytes { - ::write_all(self, elem).await?; - } - Ok(()) - } - } -} - -#[cfg(feature = "smol")] -mod smol { - use crate::misc::Stream; - use smol::{ - io::{AsyncReadExt, AsyncWriteExt}, - net::TcpStream, - }; - - impl Stream for TcpStream { - #[inline] - async fn read(&mut self, bytes: &mut [u8]) -> crate::Result { - Ok(::read(self, bytes).await?) - } - - #[inline] - async fn write_all(&mut self, bytes: &[u8]) -> crate::Result<()> { - ::write_all(self, bytes).await?; - Ok(()) - } - - #[inline] - async fn write_all_vectored(&mut self, bytes: &[&[u8]]) -> crate::Result<()> { - _local_write_all_vectored!(bytes, |io_slices| self.write_vectored(io_slices).await); - Ok(()) - } - } - - #[cfg(unix)] - impl Stream for smol::net::unix::UnixStream { - #[inline] - async fn read(&mut self, bytes: &mut [u8]) -> crate::Result { - Ok(::read(self, bytes).await?) - } - - #[inline] - async fn write_all(&mut self, bytes: &[u8]) -> crate::Result<()> { - ::write_all(self, bytes).await?; - Ok(()) - } - - #[inline] - async fn write_all_vectored(&mut self, bytes: &[&[u8]]) -> crate::Result<()> { - _local_write_all_vectored!(bytes, |io_slices| self.write_vectored(io_slices).await); - Ok(()) - } - } -} - -#[cfg(feature = "smoltcp")] -mod smoltcp { - use crate::misc::Stream; - use smoltcp::socket::tcp::Socket; - - impl Stream for Socket<'_> { - #[inline] - async fn read(&mut self, bytes: &mut [u8]) -> crate::Result { - Ok(self.recv_slice(bytes)?) - } - - #[inline] - async fn write_all(&mut self, mut bytes: &[u8]) -> crate::Result<()> { - _local_write_all!(bytes, self.send_slice(bytes)); - Ok(()) - } - - #[inline] - async fn write_all_vectored(&mut self, bytes: &[&[u8]]) -> crate::Result<()> { - for elem in bytes { - self.write_all(elem).await?; - } - Ok(()) - } - } -} - +mod bytes_stream; #[cfg(feature = "std")] -mod _std { - use crate::misc::Stream; - use std::{ - io::{Read, Write}, - net::TcpStream, - }; - - impl Stream for TcpStream { - #[inline] - async fn read(&mut self, bytes: &mut [u8]) -> crate::Result { - Ok(::read(self, bytes)?) - } - - #[inline] - async fn write_all(&mut self, bytes: &[u8]) -> crate::Result<()> { - ::write_all(self, bytes)?; - Ok(()) - } - - #[inline] - async fn write_all_vectored(&mut self, bytes: &[&[u8]]) -> crate::Result<()> { - _local_write_all_vectored!(bytes, |io_slices| self.write_vectored(io_slices)); - Ok(()) - } - } - - #[cfg(unix)] - impl Stream for std::os::unix::net::UnixStream { - #[inline] - async fn read(&mut self, bytes: &mut [u8]) -> crate::Result { - Ok(::read(self, bytes)?) - } - - #[inline] - async fn write_all(&mut self, bytes: &[u8]) -> crate::Result<()> { - ::write_all(self, bytes)?; - Ok(()) - } - - #[inline] - async fn write_all_vectored(&mut self, bytes: &[&[u8]]) -> crate::Result<()> { - _local_write_all_vectored!(bytes, |io_slices| self.write_vectored(io_slices)); - Ok(()) - } - } -} - +mod std; +mod stream_reader; +mod stream_with_tls; +mod stream_writer; #[cfg(feature = "tokio")] -mod tokio { - use crate::misc::Stream; - use tokio::{ - io::{AsyncReadExt, AsyncWriteExt}, - net::TcpStream, - }; - - impl Stream for TcpStream { - #[inline] - async fn read(&mut self, bytes: &mut [u8]) -> crate::Result { - Ok(::read(self, bytes).await?) - } - - #[inline] - async fn write_all(&mut self, bytes: &[u8]) -> crate::Result<()> { - ::write_all(self, bytes).await?; - Ok(()) - } - - #[inline] - async fn write_all_vectored(&mut self, bytes: &[&[u8]]) -> crate::Result<()> { - _local_write_all_vectored!(bytes, |io_slices| self.write_vectored(io_slices).await); - Ok(()) - } - } - - #[cfg(unix)] - impl Stream for tokio::net::UnixStream { - #[inline] - async fn read(&mut self, bytes: &mut [u8]) -> crate::Result { - Ok(::read(self, bytes).await?) - } - - #[inline] - async fn write_all(&mut self, bytes: &[u8]) -> crate::Result<()> { - ::write_all(self, bytes).await?; - Ok(()) - } - - #[inline] - async fn write_all_vectored(&mut self, bytes: &[&[u8]]) -> crate::Result<()> { - _local_write_all_vectored!(bytes, |io_slices| self.write_vectored(io_slices).await); - Ok(()) - } - } -} - +mod tokio; #[cfg(feature = "tokio-rustls")] -mod tokio_rustls { - use crate::misc::{stream::TlsStream, Stream}; - use ring::digest::{self, Digest}; - use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; - - impl Stream for tokio_rustls::client::TlsStream - where - T: AsyncRead + AsyncWrite + Unpin, - { - #[inline] - async fn read(&mut self, bytes: &mut [u8]) -> crate::Result { - Ok(::read(self, bytes).await?) - } - - #[inline] - async fn write_all(&mut self, bytes: &[u8]) -> crate::Result<()> { - ::write_all(self, bytes).await?; - Ok(()) - } - - #[inline] - async fn write_all_vectored(&mut self, bytes: &[&[u8]]) -> crate::Result<()> { - _local_write_all_vectored!(bytes, |io_slices| self.write_vectored(io_slices).await); - Ok(()) - } - } - - impl TlsStream for tokio_rustls::client::TlsStream - where - T: AsyncRead + AsyncWrite + Unpin, - { - type TlsServerEndPoint = Digest; - - #[inline] - fn tls_server_end_point(&self) -> crate::Result> { - let (_, conn) = self.get_ref(); - Ok(match conn.peer_certificates() { - Some([cert, ..]) => { - #[cfg(feature = "x509-certificate")] - let algorithm = { - use x509_certificate::{DigestAlgorithm, SignatureAlgorithm}; - let x509_cer = x509_certificate::X509Certificate::from_der(cert)?; - let Some(sa) = x509_cer.signature_algorithm() else { - return Ok(None); - }; - match sa { - SignatureAlgorithm::EcdsaSha256 - | SignatureAlgorithm::RsaSha1 - | SignatureAlgorithm::RsaSha256 => &digest::SHA256, - SignatureAlgorithm::EcdsaSha384 | SignatureAlgorithm::RsaSha384 => &digest::SHA384, - SignatureAlgorithm::Ed25519 => &digest::SHA512, - SignatureAlgorithm::NoSignature(da) => match da { - DigestAlgorithm::Sha1 | DigestAlgorithm::Sha256 => &digest::SHA256, - DigestAlgorithm::Sha384 => &digest::SHA384, - DigestAlgorithm::Sha512 => &digest::SHA512, - }, - SignatureAlgorithm::RsaSha512 => &digest::SHA512, - } - }; - #[cfg(not(feature = "x509-certificate"))] - let algorithm = &digest::SHA256; - Some(digest::digest(algorithm, cert.as_ref())) - } - _ => None, - }) - } - } - - impl Stream for tokio_rustls::server::TlsStream - where - T: AsyncRead + AsyncWrite + Unpin, - { - #[inline] - async fn read(&mut self, bytes: &mut [u8]) -> crate::Result { - Ok(::read(self, bytes).await?) - } - - #[inline] - async fn write_all(&mut self, bytes: &[u8]) -> crate::Result<()> { - ::write_all(self, bytes).await?; - Ok(()) - } +mod tokio_rustls; - #[inline] - async fn write_all_vectored(&mut self, bytes: &[&[u8]]) -> crate::Result<()> { - _local_write_all_vectored!(bytes, |io_slices| self.write_vectored(io_slices).await); - Ok(()) - } - } +pub use bytes_stream::BytesStream; +pub use stream_reader::StreamReader; +pub use stream_with_tls::StreamWithTls; +pub use stream_writer::StreamWriter; - impl TlsStream for tokio_rustls::server::TlsStream - where - T: AsyncRead + AsyncWrite + Unpin, - { - type TlsServerEndPoint = Digest; +/// A stream of values produced asynchronously. +pub trait Stream: StreamReader + StreamWriter {} - #[inline] - fn tls_server_end_point(&self) -> crate::Result> { - let (_, conn) = self.get_ref(); - Ok(match conn.peer_certificates() { - Some([cert, ..]) => Some(digest::digest(&digest::SHA256, cert)), - _ => None, - }) - } - } -} +impl Stream for T where T: StreamReader + StreamWriter {} #[expect(clippy::mut_mut, reason = "false-positive")] #[cfg(feature = "std")] #[inline] fn advance_slices<'bytes>( bytes: &mut &[&'bytes [u8]], - io_slices: &mut &mut [std::io::IoSlice<'bytes>], + io_slices: &mut &mut [::std::io::IoSlice<'bytes>], written: usize, ) { let mut first_slice_idx = written; @@ -667,16 +61,17 @@ fn advance_slices<'bytes>( let [first_io_slices, ..] = io_slices else { return; }; - *first_io_slices = std::io::IoSlice::new(first_bytes.get(first_slice_idx..).unwrap_or_default()); + let slice = first_bytes.get(first_slice_idx..).unwrap_or_default(); + *first_io_slices = ::std::io::IoSlice::new(slice); } #[cfg(feature = "std")] #[inline] fn convert_to_io_slices<'buffer, 'bytes>( - buffer: &'buffer mut [std::io::IoSlice<'bytes>; 8], + buffer: &'buffer mut [::std::io::IoSlice<'bytes>; 8], elems: &[&'bytes [u8]], -) -> &'buffer mut [std::io::IoSlice<'bytes>] { - use std::io::IoSlice; +) -> &'buffer mut [::std::io::IoSlice<'bytes>] { + use ::std::io::IoSlice; match elems { [a] => { buffer[0] = IoSlice::new(a); diff --git a/wtx/src/misc/stream/bytes_stream.rs b/wtx/src/misc/stream/bytes_stream.rs new file mode 100644 index 00000000..8ab36da7 --- /dev/null +++ b/wtx/src/misc/stream/bytes_stream.rs @@ -0,0 +1,60 @@ +use crate::misc::{StreamReader, StreamWriter}; +use alloc::vec::Vec; +use core::cmp::Ordering; + +/// Stores written data to transfer when read. +#[derive(Debug, Default)] +pub struct BytesStream { + buffer: Vec, + idx: usize, +} + +impl BytesStream { + /// Empties the internal buffer. + #[inline] + pub fn clear(&mut self) { + self.buffer.clear(); + self.idx = 0; + } +} + +impl StreamReader for BytesStream { + #[inline] + async fn read(&mut self, bytes: &mut [u8]) -> crate::Result { + let working_buffer = self.buffer.get(self.idx..).unwrap_or_default(); + let working_buffer_len = working_buffer.len(); + Ok(match working_buffer_len.cmp(&bytes.len()) { + Ordering::Less => { + bytes.get_mut(..working_buffer_len).unwrap_or_default().copy_from_slice(working_buffer); + self.clear(); + working_buffer_len + } + Ordering::Equal => { + bytes.copy_from_slice(working_buffer); + self.clear(); + working_buffer_len + } + Ordering::Greater => { + bytes.copy_from_slice(working_buffer.get(..bytes.len()).unwrap_or_default()); + self.idx = self.idx.wrapping_add(bytes.len()); + bytes.len() + } + }) + } +} + +impl StreamWriter for BytesStream { + #[inline] + async fn write_all(&mut self, bytes: &[u8]) -> crate::Result<()> { + self.buffer.extend_from_slice(bytes); + Ok(()) + } + + #[inline] + async fn write_all_vectored(&mut self, bytes: &[&[u8]]) -> crate::Result<()> { + for elem in bytes { + self.buffer.extend_from_slice(elem); + } + Ok(()) + } +} diff --git a/wtx/src/misc/stream/std.rs b/wtx/src/misc/stream/std.rs new file mode 100644 index 00000000..ab08c16b --- /dev/null +++ b/wtx/src/misc/stream/std.rs @@ -0,0 +1,26 @@ +use crate::misc::{StreamReader, StreamWriter}; +use std::{ + io::{Read, Write}, + net::TcpStream, +}; + +impl StreamReader for TcpStream { + #[inline] + async fn read(&mut self, bytes: &mut [u8]) -> crate::Result { + Ok(::read(self, bytes)?) + } +} + +impl StreamWriter for TcpStream { + #[inline] + async fn write_all(&mut self, bytes: &[u8]) -> crate::Result<()> { + ::write_all(self, bytes)?; + Ok(()) + } + + #[inline] + async fn write_all_vectored(&mut self, bytes: &[&[u8]]) -> crate::Result<()> { + _local_write_all_vectored!(bytes, |io_slices| self.write_vectored(io_slices)); + Ok(()) + } +} diff --git a/wtx/src/misc/stream/stream_reader.rs b/wtx/src/misc/stream/stream_reader.rs new file mode 100644 index 00000000..a4b639a1 --- /dev/null +++ b/wtx/src/misc/stream/stream_reader.rs @@ -0,0 +1,63 @@ +/// A stream of values sent asynchronously. +pub trait StreamReader { + /// Pulls some bytes from this source into the specified buffer, returning how many bytes + /// were read. + fn read(&mut self, bytes: &mut [u8]) -> impl Future>; + + /// Reads the exact number of bytes required to fill `bytes`. + #[inline] + fn read_exact(&mut self, bytes: &mut [u8]) -> impl Future> { + async move { + let mut idx = 0; + for _ in 0..bytes.len() { + if idx >= bytes.len() { + break; + } + let read = self.read(bytes.get_mut(idx..).unwrap_or_default()).await?; + if read == 0 { + return Err(crate::Error::MISC_UnexpectedStreamEOF); + } + idx = idx.wrapping_add(read); + } + Ok(()) + } + } + + /// Reads and at the same time discards exactly `len` bytes. + #[inline] + fn read_skip(&mut self, len: usize) -> impl Future> { + async move { + let mut buffer = [0; 32]; + let mut counter = len; + for _ in 0..len { + if counter == 0 { + break; + } + let slice = if let Some(el) = buffer.get_mut(..counter) { el } else { &mut buffer[..] }; + let read = self.read(slice).await?; + if read == 0 { + return Err(crate::Error::MISC_UnexpectedStreamEOF); + } + counter = counter.wrapping_sub(read); + } + Ok(()) + } + } +} + +impl StreamReader for &mut T +where + T: StreamReader, +{ + #[inline] + async fn read(&mut self, bytes: &mut [u8]) -> crate::Result { + (**self).read(bytes).await + } +} + +impl StreamReader for () { + #[inline] + async fn read(&mut self, _: &mut [u8]) -> crate::Result { + Ok(0) + } +} diff --git a/wtx/src/misc/stream/stream_with_tls.rs b/wtx/src/misc/stream/stream_with_tls.rs new file mode 100644 index 00000000..53a3f676 --- /dev/null +++ b/wtx/src/misc/stream/stream_with_tls.rs @@ -0,0 +1,24 @@ +use crate::misc::Lease; + +/// Transport Layer Security +pub trait StreamWithTls { + /// Channel binding data defined in [RFC 5929]. + /// + /// [RFC 5929]: https://tools.ietf.org/html/rfc5929 + type TlsServerEndPoint: Lease<[u8]>; + + /// See `Self::TlsServerEndPoint`. + fn tls_server_end_point(&self) -> crate::Result>; +} + +impl StreamWithTls for &T +where + T: StreamWithTls, +{ + type TlsServerEndPoint = T::TlsServerEndPoint; + + #[inline] + fn tls_server_end_point(&self) -> crate::Result> { + (*self).tls_server_end_point() + } +} diff --git a/wtx/src/misc/stream/stream_writer.rs b/wtx/src/misc/stream/stream_writer.rs new file mode 100644 index 00000000..e69524e4 --- /dev/null +++ b/wtx/src/misc/stream/stream_writer.rs @@ -0,0 +1,39 @@ +/// A stream of values written asynchronously. +pub trait StreamWriter { + /// Attempts to write ***all*** `bytes`. + fn write_all(&mut self, bytes: &[u8]) -> impl Future>; + + /// Attempts to write ***all*** `bytes` of all slices in a single syscall. + /// + /// # Panics + /// + /// If the length of the outermost slice is greater than 8. + fn write_all_vectored(&mut self, bytes: &[&[u8]]) -> impl Future>; +} + +impl StreamWriter for &mut T +where + T: StreamWriter, +{ + #[inline] + async fn write_all(&mut self, bytes: &[u8]) -> crate::Result<()> { + (**self).write_all(bytes).await + } + + #[inline] + async fn write_all_vectored(&mut self, bytes: &[&[u8]]) -> crate::Result<()> { + (**self).write_all_vectored(bytes).await + } +} + +impl StreamWriter for () { + #[inline] + async fn write_all(&mut self, _: &[u8]) -> crate::Result<()> { + Ok(()) + } + + #[inline] + async fn write_all_vectored(&mut self, _: &[&[u8]]) -> crate::Result<()> { + Ok(()) + } +} diff --git a/wtx/src/misc/stream/tokio.rs b/wtx/src/misc/stream/tokio.rs new file mode 100644 index 00000000..e6aba6a1 --- /dev/null +++ b/wtx/src/misc/stream/tokio.rs @@ -0,0 +1,77 @@ +use crate::misc::{StreamReader, StreamWriter}; +use tokio::{ + io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt, ReadHalf, WriteHalf}, + net::{ + tcp::{OwnedReadHalf, OwnedWriteHalf}, + TcpStream, + }, +}; + +impl StreamReader for OwnedReadHalf { + #[inline] + async fn read(&mut self, bytes: &mut [u8]) -> crate::Result { + Ok(::read(self, bytes).await?) + } +} + +impl StreamReader for ReadHalf +where + T: AsyncRead, +{ + #[inline] + async fn read(&mut self, bytes: &mut [u8]) -> crate::Result { + Ok(::read(self, bytes).await?) + } +} + +impl StreamReader for TcpStream { + #[inline] + async fn read(&mut self, bytes: &mut [u8]) -> crate::Result { + Ok(::read(self, bytes).await?) + } +} + +impl StreamWriter for OwnedWriteHalf { + #[inline] + async fn write_all(&mut self, bytes: &[u8]) -> crate::Result<()> { + ::write_all(self, bytes).await?; + Ok(()) + } + + #[inline] + async fn write_all_vectored(&mut self, bytes: &[&[u8]]) -> crate::Result<()> { + _local_write_all_vectored!(bytes, |io_slices| self.write_vectored(io_slices).await); + Ok(()) + } +} + +impl StreamWriter for WriteHalf +where + T: AsyncWrite, +{ + #[inline] + async fn write_all(&mut self, bytes: &[u8]) -> crate::Result<()> { + ::write_all(self, bytes).await?; + Ok(()) + } + + #[inline] + async fn write_all_vectored(&mut self, bytes: &[&[u8]]) -> crate::Result<()> { + _local_write_all_vectored!(bytes, |io_slices| self.write_vectored(io_slices).await); + Ok(()) + } +} + +impl StreamWriter for TcpStream { + #[inline] + async fn write_all(&mut self, bytes: &[u8]) -> crate::Result<()> { + ::write_all(self, bytes).await?; + Ok(()) + } + + #[inline] + async fn write_all_vectored(&mut self, bytes: &[&[u8]]) -> crate::Result<()> { + _local_write_all_vectored!(bytes, |io_slices| self.write_vectored(io_slices).await); + Ok(()) + } +} diff --git a/wtx/src/misc/stream/tokio_rustls.rs b/wtx/src/misc/stream/tokio_rustls.rs new file mode 100644 index 00000000..4df65963 --- /dev/null +++ b/wtx/src/misc/stream/tokio_rustls.rs @@ -0,0 +1,114 @@ +use crate::misc::{StreamReader, StreamWithTls, StreamWriter}; +use ring::digest::{self, Digest}; +use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; + +impl StreamReader for tokio_rustls::client::TlsStream +where + T: AsyncRead + AsyncWrite + Unpin, +{ + #[inline] + async fn read(&mut self, bytes: &mut [u8]) -> crate::Result { + Ok(::read(self, bytes).await?) + } +} + +impl StreamWithTls for tokio_rustls::client::TlsStream +where + T: AsyncRead + AsyncWrite + Unpin, +{ + type TlsServerEndPoint = Digest; + + #[inline] + fn tls_server_end_point(&self) -> crate::Result> { + let (_, conn) = self.get_ref(); + Ok(match conn.peer_certificates() { + Some([cert, ..]) => { + #[cfg(feature = "x509-certificate")] + let algorithm = { + use x509_certificate::{DigestAlgorithm, SignatureAlgorithm}; + let x509_cer = x509_certificate::X509Certificate::from_der(cert)?; + let Some(sa) = x509_cer.signature_algorithm() else { + return Ok(None); + }; + match sa { + SignatureAlgorithm::EcdsaSha256 + | SignatureAlgorithm::RsaSha1 + | SignatureAlgorithm::RsaSha256 => &digest::SHA256, + SignatureAlgorithm::EcdsaSha384 | SignatureAlgorithm::RsaSha384 => &digest::SHA384, + SignatureAlgorithm::Ed25519 => &digest::SHA512, + SignatureAlgorithm::NoSignature(da) => match da { + DigestAlgorithm::Sha1 | DigestAlgorithm::Sha256 => &digest::SHA256, + DigestAlgorithm::Sha384 => &digest::SHA384, + DigestAlgorithm::Sha512 => &digest::SHA512, + }, + SignatureAlgorithm::RsaSha512 => &digest::SHA512, + } + }; + #[cfg(not(feature = "x509-certificate"))] + let algorithm = &digest::SHA256; + Some(digest::digest(algorithm, cert.as_ref())) + } + _ => None, + }) + } +} + +impl StreamWriter for tokio_rustls::client::TlsStream +where + T: AsyncRead + AsyncWrite + Unpin, +{ + #[inline] + async fn write_all(&mut self, bytes: &[u8]) -> crate::Result<()> { + ::write_all(self, bytes).await?; + Ok(()) + } + + #[inline] + async fn write_all_vectored(&mut self, bytes: &[&[u8]]) -> crate::Result<()> { + _local_write_all_vectored!(bytes, |io_slices| self.write_vectored(io_slices).await); + Ok(()) + } +} + +impl StreamReader for tokio_rustls::server::TlsStream +where + T: AsyncRead + AsyncWrite + Unpin, +{ + #[inline] + async fn read(&mut self, bytes: &mut [u8]) -> crate::Result { + Ok(::read(self, bytes).await?) + } +} + +impl StreamWithTls for tokio_rustls::server::TlsStream +where + T: AsyncRead + AsyncWrite + Unpin, +{ + type TlsServerEndPoint = Digest; + + #[inline] + fn tls_server_end_point(&self) -> crate::Result> { + let (_, conn) = self.get_ref(); + Ok(match conn.peer_certificates() { + Some([cert, ..]) => Some(digest::digest(&digest::SHA256, cert)), + _ => None, + }) + } +} + +impl StreamWriter for tokio_rustls::server::TlsStream +where + T: AsyncRead + AsyncWrite + Unpin, +{ + #[inline] + async fn write_all(&mut self, bytes: &[u8]) -> crate::Result<()> { + ::write_all(self, bytes).await?; + Ok(()) + } + + #[inline] + async fn write_all_vectored(&mut self, bytes: &[&[u8]]) -> crate::Result<()> { + _local_write_all_vectored!(bytes, |io_slices| self.write_vectored(io_slices).await); + Ok(()) + } +} diff --git a/wtx/src/misc/tokio_rustls.rs b/wtx/src/misc/tokio_rustls.rs index 8aadd35a..b1193afe 100644 --- a/wtx/src/misc/tokio_rustls.rs +++ b/wtx/src/misc/tokio_rustls.rs @@ -1,86 +1,94 @@ -use alloc::{boxed::Box, string::String, vec::Vec}; +use alloc::{boxed::Box, string::String, sync::Arc, vec::Vec}; use rustls_pki_types::ServerName; -use std::sync::Arc; -use tokio::{ - io::{AsyncRead, AsyncWrite}, - net::TcpStream, -}; +use tokio::io::{AsyncRead, AsyncWrite}; use tokio_rustls::{ client::TlsStream, - rustls::{server::WantsServerCert, ClientConfig, ConfigBuilder, RootCertStore, ServerConfig}, - TlsConnector, + rustls::{ + client::WantsClientCert, server::WantsServerCert, ClientConfig, ConfigBuilder, RootCertStore, + ServerConfig, + }, + TlsAcceptor, TlsConnector, }; /// TLS client using `tokio-rustls` and associated crates. #[derive(Debug)] pub struct TokioRustlsConnector { - _alpn_protocols: Vec>, - _store: RootCertStore, + alpn_protocols: Vec>, + store: RootCertStore, } impl TokioRustlsConnector { - /// From the certificates of the `webpkis-roots` project. - #[cfg(feature = "webpki-roots")] - pub fn from_webpki_roots() -> Self { - let mut this = Self::default(); - this._store.extend(webpki_roots::TLS_SERVER_ROOTS.iter().cloned()); - this + /// From the automatic selection of dependencies. + /// + /// An error will be returned if no dependency that provides CA certificates is selected. + #[inline] + pub fn from_auto() -> crate::Result { + #[cfg(feature = "webpki-roots")] + { + let mut this = Self::default(); + this.store.extend(webpki_roots::TLS_SERVER_ROOTS.iter().cloned()); + Ok(this) + } + #[cfg(not(feature = "webpki-roots"))] + return Err(crate::Error::MISC_MissingCaProviders); + } + + /// Connects using a generic stream without client authentication. + #[inline] + pub async fn connect_without_client_auth( + self, + hostname: &str, + stream: S, + ) -> crate::Result> + where + S: AsyncRead + AsyncWrite + Unpin, + { + Ok( + self + .tls_connector(|elem| elem.with_no_client_auth()) + .connect(Self::server_name(hostname)?, stream) + .await?, + ) } /// Erases the current set of ALPN protocols and then pushes the expected ALPN value for a HTTP2 /// connection. + #[inline] pub fn http2(mut self) -> Self { - self._alpn_protocols.clear(); - self._alpn_protocols.push("h2".into()); + self.alpn_protocols.clear(); + self.alpn_protocols.push("h2".into()); self } /// Avoids additional round trips by specifying in advance which protocols should be used. + #[inline] pub fn push_alpn_protocol(mut self, protocol: &[u8]) -> Self { - self._alpn_protocols.push(protocol.into()); + self.alpn_protocols.push(protocol.into()); self } /// Pushes a sequence of certificates. - #[cfg(feature = "rustls-pemfile")] - pub fn push_certs(mut self, bytes: &[u8]) -> crate::Result { - for rslt in rustls_pemfile::certs(&mut &*bytes) { + #[inline] + pub fn push_certs(mut self, mut bytes: &[u8]) -> crate::Result { + for rslt in rustls_pemfile::certs(&mut bytes) { let cert = rslt?; - self._store.add(cert)?; + self.store.add(cert)?; } Ok(self) } - /// Connects using a generic stream. - pub async fn with_generic_stream( - self, - hostname: &str, - stream: S, - ) -> crate::Result> - where - S: AsyncRead + AsyncWrite + Unpin, - { - Ok(self.tls_connector().connect(Self::server_name(hostname)?, stream).await?) - } - - /// Connects using a [TcpStream] stream. - pub async fn with_tcp_stream( - self, - host: &str, - hostname: &str, - ) -> crate::Result> { - let stream = TcpStream::connect(host).await?; - Ok(self.tls_connector().connect(Self::server_name(hostname)?, stream).await?) - } - + #[inline] fn server_name(hostname: &str) -> crate::Result> { Ok(ServerName::try_from(String::from(hostname)).map_err(invalid_input_err)?) } - fn tls_connector(self) -> TlsConnector { - let mut config = - ClientConfig::builder().with_root_certificates(self._store).with_no_client_auth(); - config.alpn_protocols = self._alpn_protocols; + #[inline] + fn tls_connector( + self, + cb: impl FnOnce(ConfigBuilder) -> ClientConfig, + ) -> TlsConnector { + let mut config = cb(ClientConfig::builder().with_root_certificates(self.store)); + config.alpn_protocols = self.alpn_protocols; TlsConnector::from(Arc::new(config)) } } @@ -88,52 +96,53 @@ impl TokioRustlsConnector { impl Default for TokioRustlsConnector { #[inline] fn default() -> Self { - Self { _alpn_protocols: Vec::new(), _store: RootCertStore::empty() } + Self { alpn_protocols: Vec::new(), store: RootCertStore::empty() } } } /// TLS server using `tokio-rustls` and associated crates. #[derive(Debug)] pub struct TokioRustlsAcceptor { - _builder: ConfigBuilder, - _is_http2: bool, + builder: ConfigBuilder, + is_http2: bool, } impl TokioRustlsAcceptor { - /// Erases the set of ALPN protocols when building and then pushes the expected ALPN value for a - /// HTTP2 connection. - pub fn http2(mut self) -> Self { - self._is_http2 = true; - self + /// New instance without client authentication. + #[inline] + pub fn without_client_auth() -> Self { + Self { builder: ServerConfig::builder().with_no_client_auth(), is_http2: false } } - /// Sets a single certificate chain and matching private key. - #[cfg(feature = "rustls-pemfile")] - pub fn with_cert_chain_and_priv_key( + /// Creates a [`tokio_rustls::TlsAcceptor`] with a single certificate chain and matching private + /// key. + #[inline] + pub fn build_with_cert_chain_and_priv_key( self, cert_chain: &[u8], priv_key: &[u8], - ) -> crate::Result { - let mut config = self._builder.with_single_cert( + ) -> crate::Result { + let mut config = self.builder.with_single_cert( rustls_pemfile::certs(&mut &*cert_chain).collect::>()?, - rustls_pemfile::private_key(&mut &*priv_key)? - .ok_or_else(|| invalid_input_err("No private key found"))?, + rustls_pemfile::private_key(&mut &*priv_key)?.ok_or_else(|| invalid_input_err("No key"))?, )?; - if self._is_http2 { + if self.is_http2 { config.alpn_protocols.clear(); config.alpn_protocols.push("h2".into()); } - Ok(tokio_rustls::TlsAcceptor::from(Arc::new(config))) + Ok(TlsAcceptor::from(Arc::new(config))) } -} -impl Default for TokioRustlsAcceptor { + /// Erases the set of ALPN protocols when building and then pushes the expected ALPN value for an + /// HTTP2 connection. #[inline] - fn default() -> Self { - Self { _builder: ServerConfig::builder().with_no_client_auth(), _is_http2: false } + pub fn http2(mut self) -> Self { + self.is_http2 = true; + self } } +#[inline] fn invalid_input_err(err: E) -> std::io::Error where E: Into>, diff --git a/wtx/src/misc/vector.rs b/wtx/src/misc/vector.rs index 67544d3e..16539c8c 100644 --- a/wtx/src/misc/vector.rs +++ b/wtx/src/misc/vector.rs @@ -339,17 +339,6 @@ impl LeaseMut> for Vector { } } -#[cfg(feature = "miniserde")] -impl miniserde::Serialize for Vector -where - D: miniserde::Serialize, -{ - #[inline] - fn begin(&self) -> miniserde::ser::Fragment<'_> { - self.data.begin() - } -} - #[cfg(feature = "serde")] impl serde::Serialize for Vector where diff --git a/wtx/src/pool/resource_manager.rs b/wtx/src/pool/resource_manager.rs index cdbf4601..d9654004 100644 --- a/wtx/src/pool/resource_manager.rs +++ b/wtx/src/pool/resource_manager.rs @@ -120,8 +120,7 @@ pub(crate) mod database { pool::{PostgresRM, ResourceManager}, rng::StdRngSync, }; - use core::mem; - use std::marker::PhantomData; + use core::{marker::PhantomData, mem}; use tokio::net::TcpStream; impl PostgresRM { @@ -189,8 +188,7 @@ pub(crate) mod database { pool::{PostgresRM, ResourceManager}, rng::StdRngSync, }; - use core::mem; - use std::marker::PhantomData; + use core::{marker::PhantomData, mem}; use tokio::net::TcpStream; use tokio_rustls::client::TlsStream; @@ -226,13 +224,11 @@ pub(crate) mod database { TcpStream::connect(uri.host()).await.map_err(Into::into)?, &mut &self.rng, |stream| async { - #[allow(unused_mut, reason = "features")] - let mut rslt = TokioRustlsConnector::from_webpki_roots(); - #[cfg(feature = "rustls-pemfile")] + let mut rslt = TokioRustlsConnector::from_auto()?; if let Some(elem) = self._certs { rslt = rslt.push_certs(elem)?; } - Ok(rslt.with_generic_stream(uri.hostname(), stream).await?) + Ok(rslt.connect_without_client_auth(uri.hostname(), stream).await?) }, ) }) @@ -258,13 +254,11 @@ pub(crate) mod database { TcpStream::connect(uri.host()).await.map_err(Into::into)?, &mut &self.rng, |stream| async { - #[allow(unused_mut, reason = "features")] - let mut rslt = TokioRustlsConnector::from_webpki_roots(); - #[cfg(feature = "rustls-pemfile")] + let mut rslt = TokioRustlsConnector::from_auto()?; if let Some(elem) = self._certs { rslt = rslt.push_certs(elem)?; } - Ok(rslt.with_generic_stream(uri.hostname(), stream).await?) + Ok(rslt.connect_without_client_auth(uri.hostname(), stream).await?) }, ) })?; diff --git a/wtx/src/pool/simple_pool.rs b/wtx/src/pool/simple_pool.rs index 1a7ddf7b..25d0a280 100644 --- a/wtx/src/pool/simple_pool.rs +++ b/wtx/src/pool/simple_pool.rs @@ -59,7 +59,7 @@ where } #[inline] - pub(crate) async fn into_for_each(&self, mut cb: impl FnMut(R) -> FUN) + pub(crate) async fn _into_for_each(&self, mut cb: impl FnMut(R) -> FUN) where FUN: Future, { @@ -208,7 +208,7 @@ mod _tokio { } } -#[cfg(all(feature = "tokio", test))] +#[cfg(test)] mod tests { use crate::pool::{simple_pool::SimplePoolTokio, Pool, SimpleRM}; diff --git a/wtx/src/web_socket/handshake.rs b/wtx/src/web_socket/handshake.rs index cbb85fec..6a022f23 100644 --- a/wtx/src/web_socket/handshake.rs +++ b/wtx/src/web_socket/handshake.rs @@ -1,4 +1,4 @@ -#[cfg(all(feature = "tokio", test))] +#[cfg(test)] mod tests; use crate::{ diff --git a/wtx/src/web_socket/handshake/tests.rs b/wtx/src/web_socket/handshake/tests.rs index f1cde868..79b115d4 100644 --- a/wtx/src/web_socket/handshake/tests.rs +++ b/wtx/src/web_socket/handshake/tests.rs @@ -27,8 +27,8 @@ static HAS_SERVER_FINISHED: AtomicBool = AtomicBool::new(false); #[tokio::test] async fn client_and_server_frames() { - #[cfg(feature = "_tracing-subscriber")] - let _rslt = crate::misc::tracing_subscriber_init(); + #[cfg(feature = "_tracing-tree")] + let _rslt = crate::misc::tracing_tree_init(); do_test_client_and_server_frames((), ()).await; } @@ -36,8 +36,8 @@ async fn client_and_server_frames() { #[tokio::test] async fn client_and_server_frames_compression() { use crate::web_socket::compression::Flate2; - #[cfg(feature = "_tracing-subscriber")] - let _rslt = crate::misc::tracing_subscriber_init(); + #[cfg(feature = "_tracing-tree")] + let _rslt = crate::misc::tracing_tree_init(); do_test_client_and_server_frames((), Flate2::default()).await; tokio::time::sleep(Duration::from_millis(200)).await; do_test_client_and_server_frames(Flate2::default(), ()).await;