From b0d1038a3c5fe67fc109cba995377106000a3d05 Mon Sep 17 00:00:00 2001 From: Toshit Chawda Date: Fri, 12 Apr 2024 17:18:56 -0700 Subject: [PATCH] call wisp v2 extension packet handlers --- Cargo.lock | 693 +++++++++++++++++++++++++++++++++++++- Cargo.toml | 2 +- certs-grabber/Cargo.toml | 13 + certs-grabber/src/main.rs | 64 ++++ client/Cargo.toml | 2 +- client/build.sh | 9 + client/demo.js | 9 +- client/src/lib.rs | 42 +-- client/src/utils.rs | 23 +- client/tests/fetch.rs | 32 +- wisp/src/lib.rs | 196 ++++++----- wisp/src/packet.rs | 30 +- 12 files changed, 974 insertions(+), 141 deletions(-) create mode 100644 certs-grabber/Cargo.toml create mode 100644 certs-grabber/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index fb57868..8fa37cd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -41,6 +41,21 @@ dependencies = [ "alloc-no-stdlib", ] +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "anstream" version = "0.6.13" @@ -95,6 +110,84 @@ version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519" +[[package]] +name = "asn1-rs" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6fd5ddaf0351dff5b8da21b2fb4ff8e08ddd02857f0bf69c47639106c0fff0" +dependencies = [ + "asn1-rs-derive 0.4.0", + "asn1-rs-impl 0.1.0", + "displaydoc", + "nom", + "num-traits", + "rusticata-macros", + "thiserror", + "time", +] + +[[package]] +name = "asn1-rs" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ad1373757efa0f70ec53939aabc7152e1591cb485208052993070ac8d2429d" +dependencies = [ + "asn1-rs-derive 0.5.0", + "asn1-rs-impl 0.2.0", + "displaydoc", + "nom", + "num-traits", + "rusticata-macros", + "thiserror", + "time", +] + +[[package]] +name = "asn1-rs-derive" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" +dependencies = [ + "proc-macro2 1.0.79", + "quote 1.0.36", + "syn 1.0.109", + "synstructure 0.12.6", +] + +[[package]] +name = "asn1-rs-derive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7378575ff571966e99a744addeff0bff98b8ada0dedf1956d59e634db95eaac1" +dependencies = [ + "proc-macro2 1.0.79", + "quote 1.0.36", + "syn 2.0.58", + "synstructure 0.13.1", +] + +[[package]] +name = "asn1-rs-impl" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" +dependencies = [ + "proc-macro2 1.0.79", + "quote 1.0.36", + "syn 1.0.109", +] + +[[package]] +name = "asn1-rs-impl" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" +dependencies = [ + "proc-macro2 1.0.79", + "quote 1.0.36", + "syn 2.0.58", +] + [[package]] name = "async-compression" version = "0.4.8" @@ -231,6 +324,12 @@ version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +[[package]] +name = "base64" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51" + [[package]] name = "bitflags" version = "1.3.2" @@ -297,12 +396,37 @@ version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2678b2e3449475e95b0aa6f9b506a28e61b3dc8996592b983695e8ebb58a8b41" +[[package]] +name = "certs-grabber" +version = "0.1.0" +dependencies = [ + "hex", + "ring", + "rustls-pki-types", + "rustls-webpki 0.102.2", + "tokio", + "webpki-ccadb", + "x509-parser 0.16.0", +] + [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chrono" +version = "0.4.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a0d04d43504c61aa6c7531f1871dd0d418d91130162063b789da00fd7057a5e" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "num-traits", + "windows-targets 0.52.4", +] + [[package]] name = "clap" version = "4.5.4" @@ -480,6 +604,27 @@ dependencies = [ "typenum", ] +[[package]] +name = "csv" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac574ff4d437a7b5ad237ef331c17ccca63c46479e5b5453eb8e10bb99a759fe" +dependencies = [ + "csv-core", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70" +dependencies = [ + "memchr", +] + [[package]] name = "dashmap" version = "5.5.3" @@ -493,6 +638,12 @@ dependencies = [ "parking_lot_core", ] +[[package]] +name = "data-encoding" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" + [[package]] name = "default-env" version = "0.1.1" @@ -504,6 +655,43 @@ dependencies = [ "syn 0.15.44", ] +[[package]] +name = "der-parser" +version = "8.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbd676fbbab537128ef0278adb5576cf363cff6aa22a7b24effe97347cfab61e" +dependencies = [ + "asn1-rs 0.5.2", + "displaydoc", + "nom", + "num-bigint", + "num-traits", + "rusticata-macros", +] + +[[package]] +name = "der-parser" +version = "9.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cd0a5c643689626bec213c4d8bd4d96acc8ffdb4ad4bb6bc16abf27d5f4b553" +dependencies = [ + "asn1-rs 0.6.1", + "displaydoc", + "nom", + "num-bigint", + "num-traits", + "rusticata-macros", +] + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + [[package]] name = "digest" version = "0.10.7" @@ -514,12 +702,32 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "displaydoc" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" +dependencies = [ + "proc-macro2 1.0.79", + "quote 1.0.36", + "syn 2.0.58", +] + [[package]] name = "either" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" +[[package]] +name = "encoding_rs" +version = "0.8.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" +dependencies = [ + "cfg-if", +] + [[package]] name = "epoxy-client" version = "1.5.1" @@ -527,7 +735,7 @@ dependencies = [ "async-compression", "async-trait", "async_io_stream", - "base64", + "base64 0.21.7", "bytes", "console_error_panic_hook", "default-env", @@ -545,7 +753,7 @@ dependencies = [ "rustls-pki-types", "send_wrapper 0.6.0", "tokio", - "tokio-rustls", + "tokio-rustls 0.25.0", "tokio-util", "tower-service", "wasm-bindgen", @@ -629,7 +837,7 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ac14c1f19ff7eab47c9ee7263a088296bec2abd1f9345964c863b5134da40a1" dependencies = [ - "base64", + "base64 0.21.7", "bytes", "http-body-util", "hyper 1.2.0", @@ -674,6 +882,15 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + [[package]] name = "futures" version = "0.3.30" @@ -870,7 +1087,7 @@ version = "7.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "765c9198f173dd59ce26ff9f95ef0aafd0a0fe01fb9d72841bc5066a4c06511d" dependencies = [ - "base64", + "base64 0.21.7", "byteorder", "flate2", "nom", @@ -889,6 +1106,12 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "http" version = "0.2.12" @@ -1008,6 +1231,20 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-rustls" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +dependencies = [ + "futures-util", + "http 0.2.12", + "hyper 0.14.28", + "rustls 0.21.10", + "tokio", + "tokio-rustls 0.24.1", +] + [[package]] name = "hyper-timeout" version = "0.4.1" @@ -1020,6 +1257,19 @@ dependencies = [ "tokio-io-timeout", ] +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper 0.14.28", + "native-tls", + "tokio", + "tokio-native-tls", +] + [[package]] name = "hyper-util" version = "0.1.3" @@ -1056,6 +1306,39 @@ dependencies = [ "wasmtimer", ] +[[package]] +name = "iana-time-zone" +version = "0.1.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "indexmap" version = "1.9.3" @@ -1076,6 +1359,12 @@ dependencies = [ "hashbrown 0.14.3", ] +[[package]] +name = "ipnet" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" + [[package]] name = "is-terminal" version = "0.4.12" @@ -1226,6 +1515,32 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "num-bigint" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.18" @@ -1254,6 +1569,24 @@ dependencies = [ "memchr", ] +[[package]] +name = "oid-registry" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bedf36ffb6ba96c2eb7144ef6270557b52e54b20c0a8e1eb2ff99a6c6959bff" +dependencies = [ + "asn1-rs 0.5.2", +] + +[[package]] +name = "oid-registry" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c958dd45046245b9c3c2547369bb634eb461670b2e7e0de552905801a648d1d" +dependencies = [ + "asn1-rs 0.6.1", +] + [[package]] name = "once_cell" version = "1.19.0" @@ -1377,6 +1710,12 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -1389,7 +1728,7 @@ version = "0.4.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" dependencies = [ - "unicode-xid", + "unicode-xid 0.1.0", ] [[package]] @@ -1534,6 +1873,49 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +[[package]] +name = "reqwest" +version = "0.11.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" +dependencies = [ + "base64 0.21.7", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2 0.3.26", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.28", + "hyper-rustls", + "hyper-tls", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls 0.21.10", + "rustls-pemfile 1.0.4", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "system-configuration", + "tokio", + "tokio-native-tls", + "tokio-rustls 0.24.1", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] + [[package]] name = "ring" version = "0.17.8" @@ -1564,6 +1946,15 @@ dependencies = [ "semver", ] +[[package]] +name = "rusticata-macros" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" +dependencies = [ + "nom", +] + [[package]] name = "rustix" version = "0.38.32" @@ -1577,6 +1968,18 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rustls" +version = "0.21.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" +dependencies = [ + "log", + "ring", + "rustls-webpki 0.101.7", + "sct", +] + [[package]] name = "rustls" version = "0.22.3" @@ -1586,11 +1989,30 @@ dependencies = [ "log", "ring", "rustls-pki-types", - "rustls-webpki", + "rustls-webpki 0.102.2", "subtle", "zeroize", ] +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", +] + +[[package]] +name = "rustls-pemfile" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" +dependencies = [ + "base64 0.22.0", + "rustls-pki-types", +] + [[package]] name = "rustls-pki-types" version = "1.4.1" @@ -1600,6 +2022,16 @@ dependencies = [ "web-time", ] +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "rustls-webpki" version = "0.102.2" @@ -1653,6 +2085,16 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "security-framework" version = "2.10.0" @@ -1725,6 +2167,18 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + [[package]] name = "sha1" version = "0.10.6" @@ -1840,7 +2294,18 @@ checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" dependencies = [ "proc-macro2 0.4.30", "quote 0.6.13", - "unicode-xid", + "unicode-xid 0.1.0", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2 1.0.79", + "quote 1.0.36", + "unicode-ident", ] [[package]] @@ -1860,6 +2325,50 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +[[package]] +name = "synstructure" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +dependencies = [ + "proc-macro2 1.0.79", + "quote 1.0.36", + "syn 1.0.109", + "unicode-xid 0.2.4", +] + +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2 1.0.79", + "quote 1.0.36", + "syn 2.0.58", +] + +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "tempfile" version = "3.10.1" @@ -1912,6 +2421,52 @@ dependencies = [ "once_cell", ] +[[package]] +name = "time" +version = "0.3.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "tokio" version = "1.37.0" @@ -1963,13 +2518,23 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls 0.21.10", + "tokio", +] + [[package]] name = "tokio-rustls" version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" dependencies = [ - "rustls", + "rustls 0.22.3", "rustls-pki-types", "tokio", ] @@ -2008,7 +2573,7 @@ dependencies = [ "async-stream", "async-trait", "axum", - "base64", + "base64 0.21.7", "bytes", "h2 0.3.26", "http 0.2.12", @@ -2118,24 +2683,56 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "unicode-normalization" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +dependencies = [ + "tinyvec", +] + [[package]] name = "unicode-xid" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + [[package]] name = "untrusted" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" +[[package]] +name = "url" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + [[package]] name = "utf-8" version = "0.7.6" @@ -2329,6 +2926,25 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki-ccadb" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90e7a3db4ffc4795bc5d07067eb1cb40cdb8c4ebd9f2e14a5c67ad7f809408ef" +dependencies = [ + "chrono", + "csv", + "hex", + "num-bigint", + "reqwest", + "rustls-pemfile 2.1.2", + "rustls-pki-types", + "rustls-webpki 0.102.2", + "serde", + "x509-parser 0.15.1", + "yasna", +] + [[package]] name = "webpki-roots" version = "0.26.1" @@ -2369,6 +2985,15 @@ 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.4", +] + [[package]] name = "windows-sys" version = "0.42.0" @@ -2558,6 +3183,16 @@ version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + [[package]] name = "wisp-mux" version = "4.0.0" @@ -2575,6 +3210,46 @@ dependencies = [ "tokio", ] +[[package]] +name = "x509-parser" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7069fba5b66b9193bd2c5d3d4ff12b839118f6bcbef5328efafafb5395cf63da" +dependencies = [ + "asn1-rs 0.5.2", + "data-encoding", + "der-parser 8.2.0", + "lazy_static", + "nom", + "oid-registry 0.6.1", + "rusticata-macros", + "thiserror", + "time", +] + +[[package]] +name = "x509-parser" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcbc162f30700d6f3f82a24bf7cc62ffe7caea42c0b2cba8bf7f3ae50cf51f69" +dependencies = [ + "asn1-rs 0.6.1", + "data-encoding", + "der-parser 9.0.0", + "lazy_static", + "nom", + "oid-registry 0.7.0", + "rusticata-macros", + "thiserror", + "time", +] + +[[package]] +name = "yasna" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" + [[package]] name = "zeroize" version = "1.7.0" diff --git a/Cargo.toml b/Cargo.toml index 9c822e0..6ad022d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [workspace] resolver = "2" -members = ["server", "client", "wisp", "simple-wisp-client"] +members = ["server", "client", "wisp", "simple-wisp-client", "certs-grabber"] default-members = ["server"] [profile.release] diff --git a/certs-grabber/Cargo.toml b/certs-grabber/Cargo.toml new file mode 100644 index 0000000..f68fda9 --- /dev/null +++ b/certs-grabber/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "certs-grabber" +version = "0.1.0" +edition = "2021" + +[dependencies] +hex = "0.4.3" +ring = "0.17.8" +rustls-pki-types = "1.4.1" +rustls-webpki = "0.102.2" +tokio = { version = "1.37.0", features = ["full"] } +webpki-ccadb = "0.1.0" +x509-parser = "0.16.0" diff --git a/certs-grabber/src/main.rs b/certs-grabber/src/main.rs new file mode 100644 index 0000000..11574b8 --- /dev/null +++ b/certs-grabber/src/main.rs @@ -0,0 +1,64 @@ +use std::fmt::Write; + +use ring::digest::{digest, SHA256}; +use rustls_pki_types::{CertificateDer, TrustAnchor}; +use webpki::anchor_from_trusted_cert; +use webpki_ccadb::fetch_ccadb_roots; + +#[tokio::main] +async fn main() { + let tls_roots_map = fetch_ccadb_roots().await; + let mut code = String::with_capacity(256 * 1_024); + code.push_str("const ROOTS = ["); + for (_, root) in tls_roots_map { + // Verify the DER FP matches the metadata FP. + let der = root.der(); + let calculated_fp = digest(&SHA256, &der); + let metadata_fp = hex::decode(&root.sha256_fingerprint).expect("malformed fingerprint"); + assert_eq!(calculated_fp.as_ref(), metadata_fp.as_slice()); + + let ta_der = CertificateDer::from(der.as_ref()); + let TrustAnchor { + subject, + subject_public_key_info, + name_constraints, + } = anchor_from_trusted_cert(&ta_der).expect("malformed trust anchor der"); + + /* + let (_, parsed_cert) = + x509_parser::parse_x509_certificate(&der).expect("malformed x509 der"); + let issuer = name_to_string(parsed_cert.issuer()); + let subject_str = name_to_string(parsed_cert.subject()); + let label = root.common_name_or_certificate_name.clone(); + let serial = root.serial().to_string(); + let sha256_fp = root.sha256_fp(); + */ + + code.write_fmt(format_args!( + "{{subject:new Uint8Array([{}]),subject_public_key_info:new Uint8Array([{}]),name_constraints:{}}},", + subject + .as_ref() + .iter() + .map(|x| x.to_string()) + .collect::>().join(","), + subject_public_key_info + .as_ref() + .iter() + .map(|x| x.to_string()) + .collect::>().join(","), + if let Some(constraints) = name_constraints { + format!("new Uint8Array([{}])",constraints + .as_ref() + .iter() + .map(|x| x.to_string()) + .collect::>().join(",")) + } else { + "null".into() + } + )) + .unwrap(); + } + code.pop(); + code.push_str("];"); + println!("{}",code); +} diff --git a/client/Cargo.toml b/client/Cargo.toml index ee1d108..8489e2f 100644 --- a/client/Cargo.toml +++ b/client/Cargo.toml @@ -17,7 +17,6 @@ wasm-bindgen = { version = "0.2.91", features = ["enable-interning"] } wasm-bindgen-futures = "0.4.39" futures-util = "0.3.30" js-sys = "0.3.66" -webpki-roots = "0.26.0" tokio-rustls = "0.25.0" web-sys = { version = "0.3.66", features = ["Request", "RequestInit", "Headers", "Response", "ResponseInit", "WebSocket", "BinaryType", "MessageEvent"] } wasm-streams = "0.4.0" @@ -47,3 +46,4 @@ features = ["web"] default-env = "0.1.1" wasm-bindgen-test = "0.3.42" web-sys = { version = "0.3.69", features = ["FormData", "UrlSearchParams"] } +webpki-roots = "0.26.0" diff --git a/client/build.sh b/client/build.sh index 2d77294..9219e00 100755 --- a/client/build.sh +++ b/client/build.sh @@ -41,5 +41,14 @@ echo "}\ndeclare function epoxy(maybe_memory?: WebAssembly.Memory): Promise pkg/certs.js +cat pkg/certs.js > pkg/certs-module.js +echo "export default ROOTS;" >> pkg/certs-module.js +echo "[epx] fetching certs finished" + rm -r out/ echo "[epx] done!" diff --git a/client/demo.js b/client/demo.js index 67549d0..a5b35a2 100644 --- a/client/demo.js +++ b/client/demo.js @@ -1,4 +1,5 @@ import epoxy from "./pkg/epoxy-module-bundled.js"; +import CERTS from "./pkg/certs-module.js"; onmessage = async (msg) => { console.debug("recieved demo:", msg); @@ -29,13 +30,13 @@ onmessage = async (msg) => { postMessage(JSON.stringify(str, null, 4)); } - const { EpoxyClient, certs } = await epoxy(); + const { EpoxyClient } = await epoxy(); - console.log("certs:", certs()); + console.log("certs:", CERTS); const tconn0 = performance.now(); - // args: websocket url, user agent, redirect limit - let epoxy_client = await new EpoxyClient("ws://localhost:4000", navigator.userAgent, 10); + // args: websocket url, user agent, redirect limit, certs + let epoxy_client = await new EpoxyClient("ws://localhost:4000", navigator.userAgent, 10, CERTS); const tconn1 = performance.now(); log(`conn establish took ${tconn1 - tconn0} ms or ${(tconn1 - tconn0) / 1000} s`); diff --git a/client/src/lib.rs b/client/src/lib.rs index 0f8f678..5f5946d 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -10,6 +10,7 @@ mod wrappers; use tls_stream::EpxTlsStream; use tokioio::TokioIo; use udp_stream::EpxUdpStream; +use utils::object_to_trustanchor; pub use utils::{Boolinator, ReplaceErr, UriExt}; use websocket::EpxWebSocket; use wrappers::{IncomingBody, ServiceWrapper, TlsWispService, WebSocketWrapper}; @@ -70,38 +71,6 @@ fn init() { intern("Content-Type"); } -fn cert_to_jval(cert: &TrustAnchor) -> Result { - let val = Object::new(); - Reflect::set( - &val, - &jval!("subject"), - &Uint8Array::from(cert.subject.as_ref()), - )?; - Reflect::set( - &val, - &jval!("subject_public_key_info"), - &Uint8Array::from(cert.subject_public_key_info.as_ref()), - )?; - Reflect::set( - &val, - &jval!("name_constraints"), - &jval!(cert - .name_constraints - .as_ref() - .map(|x| Uint8Array::from(x.as_ref()))), - )?; - Ok(val.into()) -} - -#[wasm_bindgen] -pub fn certs() -> Result { - Ok(webpki_roots::TLS_SERVER_ROOTS - .iter() - .map(cert_to_jval) - .collect::>()? - .into()) -} - #[wasm_bindgen(inspectable)] pub struct EpoxyClient { rustls_config: Arc, @@ -120,6 +89,7 @@ impl EpoxyClient { ws_url: String, useragent: String, redirect_limit: usize, + certs: Array, ) -> Result { let ws_uri = ws_url .parse::() @@ -137,7 +107,13 @@ impl EpoxyClient { utils::spawn_mux_fut(mux.clone(), fut, ws_url.clone()); let mut certstore = RootCertStore::empty(); - certstore.extend(webpki_roots::TLS_SERVER_ROOTS.iter().cloned()); + let certs: Result, JsValue> = + certs.iter().map(object_to_trustanchor).collect(); + certstore.extend( + certs + .replace_err("Failed to get certificates from cert store")? + .into_iter(), + ); let rustls_config = Arc::new( rustls::ClientConfig::builder() diff --git a/client/src/utils.rs b/client/src/utils.rs index 3b05027..b956d02 100644 --- a/client/src/utils.rs +++ b/client/src/utils.rs @@ -1,5 +1,6 @@ use crate::*; +use rustls_pki_types::Der; use wasm_bindgen::prelude::*; use wasm_bindgen_futures::JsFuture; @@ -195,7 +196,13 @@ pub fn get_url_port(url: &Uri) -> Result { pub async fn make_mux( url: &str, -) -> Result<(ClientMux, impl Future> + Send), WispError> { +) -> Result< + ( + ClientMux, + impl Future> + Send, + ), + WispError, +> { let (wtx, wrx) = WebSocketWrapper::connect(url, vec![]) .await .map_err(|_| WispError::WsImplSocketClosed)?; @@ -264,3 +271,17 @@ pub async fn jval_to_u8_array_req(val: JsValue) -> Result<(Uint8Array, web_sys:: req, )) } + +pub fn object_to_trustanchor(obj: JsValue) -> Result, JsValue> { + let subject: Uint8Array = Reflect::get(&obj, &jval!("subject"))?.dyn_into()?; + let pub_key_info: Uint8Array = + Reflect::get(&obj, &jval!("subject_public_key_info"))?.dyn_into()?; + let name_constraints: Option = Reflect::get(&obj, &jval!("name_constraints")) + .and_then(|x| x.dyn_into()) + .ok(); + Ok(TrustAnchor { + subject: Der::from(subject.to_vec()), + subject_public_key_info: Der::from(pub_key_info.to_vec()), + name_constraints: name_constraints.map(|x| Der::from(x.to_vec())), + }) +} diff --git a/client/tests/fetch.rs b/client/tests/fetch.rs index 02eabb2..c7307fb 100644 --- a/client/tests/fetch.rs +++ b/client/tests/fetch.rs @@ -1,6 +1,7 @@ use default_env::default_env; use epoxy_client::EpoxyClient; -use js_sys::{JsString, Object, Reflect, Uint8Array, JSON}; +use js_sys::{Array, JsString, Object, Reflect, Uint8Array, JSON}; +use rustls_pki_types::TrustAnchor; use tokio::sync::OnceCell; use wasm_bindgen::JsValue; use wasm_bindgen_futures::JsFuture; @@ -12,11 +13,40 @@ wasm_bindgen_test_configure!(run_in_dedicated_worker); static USER_AGENT: &str = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36"; static EPOXY_CLIENT: OnceCell = OnceCell::const_new(); +pub fn trustanchor_to_object(cert: &TrustAnchor) -> Result { + let val = Object::new(); + Reflect::set( + &val, + &JsValue::from("subject"), + &Uint8Array::from(cert.subject.as_ref()), + )?; + Reflect::set( + &val, + &JsValue::from("subject_public_key_info"), + &Uint8Array::from(cert.subject_public_key_info.as_ref()), + )?; + Reflect::set( + &val, + &JsValue::from("name_constraints"), + &JsValue::from( + cert.name_constraints + .as_ref() + .map(|x| Uint8Array::from(x.as_ref())), + ), + )?; + Ok(val.into()) +} + async fn get_client_w_ua(useragent: &str, redirect_limit: usize) -> EpoxyClient { EpoxyClient::new( "ws://localhost:4000".into(), useragent.into(), redirect_limit, + webpki_roots::TLS_SERVER_ROOTS + .iter() + .map(trustanchor_to_object) + .collect::>() + .expect("Failed to create certs"), ) .await .ok() diff --git a/wisp/src/lib.rs b/wisp/src/lib.rs index 076e10c..7458bf4 100644 --- a/wisp/src/lib.rs +++ b/wisp/src/lib.rs @@ -169,17 +169,18 @@ impl MuxInner { pub async fn server_into_future( self, rx: R, + extensions: Vec, close_rx: mpsc::Receiver, muxstream_sender: mpsc::UnboundedSender<(ConnectPacket, MuxStream)>, close_tx: mpsc::Sender, ) -> Result<(), WispError> where - R: ws::WebSocketRead, + R: ws::WebSocketRead + Send, { self.as_future( close_rx, close_tx.clone(), - self.server_loop(rx, muxstream_sender, close_tx), + self.server_loop(rx, extensions, muxstream_sender, close_tx), ) .await } @@ -187,13 +188,14 @@ impl MuxInner { pub async fn client_into_future( self, rx: R, + extensions: Vec, close_rx: mpsc::Receiver, close_tx: mpsc::Sender, ) -> Result<(), WispError> where - R: ws::WebSocketRead, + R: ws::WebSocketRead + Send, { - self.as_future(close_rx, close_tx, self.client_loop(rx)) + self.as_future(close_rx, close_tx, self.client_loop(rx, extensions)) .await } @@ -295,11 +297,12 @@ impl MuxInner { async fn server_loop( &self, mut rx: R, + mut extensions: Vec, muxstream_sender: mpsc::UnboundedSender<(ConnectPacket, MuxStream)>, close_tx: mpsc::Sender, ) -> Result<(), WispError> where - R: ws::WebSocketRead, + R: ws::WebSocketRead + Send, { // will send continues once flow_control is at 10% of max let target_buffer_size = ((self.buffer_size as u64 * 90) / 100) as u32; @@ -309,104 +312,112 @@ impl MuxInner { if frame.opcode == ws::OpCode::Close { break Ok(()); } - let packet = Packet::try_from(frame)?; + if let Some(packet) = + Packet::maybe_handle_extension(frame, &mut extensions, &mut rx, &self.tx).await? + { + use PacketType::*; + match packet.packet_type { + Connect(inner_packet) => { + let (ch_tx, ch_rx) = mpsc::unbounded(); + let stream_type = inner_packet.stream_type; + let flow_control: Arc = AtomicU32::new(self.buffer_size).into(); + let flow_control_event: Arc = Event::new().into(); + let is_closed: Arc = AtomicBool::new(false).into(); - use PacketType::*; - match packet.packet_type { - Connect(inner_packet) => { - let (ch_tx, ch_rx) = mpsc::unbounded(); - let stream_type = inner_packet.stream_type; - let flow_control: Arc = AtomicU32::new(self.buffer_size).into(); - let flow_control_event: Arc = Event::new().into(); - let is_closed: Arc = AtomicBool::new(false).into(); - - self.stream_map.insert( - packet.stream_id, - MuxMapValue { - stream: ch_tx, - stream_type, - flow_control: flow_control.clone(), - flow_control_event: flow_control_event.clone(), - is_closed: is_closed.clone(), - }, - ); - muxstream_sender - .unbounded_send(( - inner_packet, - MuxStream::new( - packet.stream_id, - Role::Server, + self.stream_map.insert( + packet.stream_id, + MuxMapValue { + stream: ch_tx, stream_type, - ch_rx, - close_tx.clone(), - is_closed, - flow_control, - flow_control_event, - target_buffer_size, - ), - )) - .map_err(|x| WispError::Other(Box::new(x)))?; - } - Data(data) => { - if let Some(stream) = self.stream_map.get(&packet.stream_id) { - let _ = stream.stream.unbounded_send(data); - if stream.stream_type == StreamType::Tcp { - stream.flow_control.store( - stream - .flow_control - .load(Ordering::Acquire) - .saturating_sub(1), - Ordering::Release, - ); + flow_control: flow_control.clone(), + flow_control_event: flow_control_event.clone(), + is_closed: is_closed.clone(), + }, + ); + muxstream_sender + .unbounded_send(( + inner_packet, + MuxStream::new( + packet.stream_id, + Role::Server, + stream_type, + ch_rx, + close_tx.clone(), + is_closed, + flow_control, + flow_control_event, + target_buffer_size, + ), + )) + .map_err(|x| WispError::Other(Box::new(x)))?; + } + Data(data) => { + if let Some(stream) = self.stream_map.get(&packet.stream_id) { + let _ = stream.stream.unbounded_send(data); + if stream.stream_type == StreamType::Tcp { + stream.flow_control.store( + stream + .flow_control + .load(Ordering::Acquire) + .saturating_sub(1), + Ordering::Release, + ); + } } } - } - Continue(_) | Info(_) => break Err(WispError::InvalidPacketType), - Close(_) => { - if let Some((_, mut stream)) = self.stream_map.remove(&packet.stream_id) { - stream.is_closed.store(true, Ordering::Release); - stream.stream.disconnect(); - stream.stream.close_channel(); + Continue(_) | Info(_) => break Err(WispError::InvalidPacketType), + Close(_) => { + if let Some((_, mut stream)) = self.stream_map.remove(&packet.stream_id) { + stream.is_closed.store(true, Ordering::Release); + stream.stream.disconnect(); + stream.stream.close_channel(); + } } } } } } - async fn client_loop(&self, mut rx: R) -> Result<(), WispError> + async fn client_loop( + &self, + mut rx: R, + mut extensions: Vec, + ) -> Result<(), WispError> where - R: ws::WebSocketRead, + R: ws::WebSocketRead + Send, { loop { let frame = rx.wisp_read_frame(&self.tx).await?; if frame.opcode == ws::OpCode::Close { break Ok(()); } - let packet = Packet::try_from(frame)?; - - use PacketType::*; - match packet.packet_type { - Connect(_) | Info(_) => break Err(WispError::InvalidPacketType), - Data(data) => { - if let Some(stream) = self.stream_map.get(&packet.stream_id) { - let _ = stream.stream.unbounded_send(data); - } - } - Continue(inner_packet) => { - if let Some(stream) = self.stream_map.get(&packet.stream_id) { - if stream.stream_type == StreamType::Tcp { - stream - .flow_control - .store(inner_packet.buffer_remaining, Ordering::Release); - let _ = stream.flow_control_event.notify(u32::MAX); + if let Some(packet) = + Packet::maybe_handle_extension(frame, &mut extensions, &mut rx, &self.tx).await? + { + use PacketType::*; + match packet.packet_type { + Connect(_) | Info(_) => break Err(WispError::InvalidPacketType), + Data(data) => { + if let Some(stream) = self.stream_map.get(&packet.stream_id) { + let _ = stream.stream.unbounded_send(data); } } - } - Close(_) => { - if let Some((_, mut stream)) = self.stream_map.remove(&packet.stream_id) { - stream.is_closed.store(true, Ordering::Release); - stream.stream.disconnect(); - stream.stream.close_channel(); + Continue(inner_packet) => { + if let Some(stream) = self.stream_map.get(&packet.stream_id) { + if stream.stream_type == StreamType::Tcp { + stream + .flow_control + .store(inner_packet.buffer_remaining, Ordering::Release); + let _ = stream.flow_control_event.notify(u32::MAX); + } + } + } + Close(_) => { + if let Some((_, mut stream)) = self.stream_map.remove(&packet.stream_id) { + stream.is_closed.store(true, Ordering::Release); + stream.stream.disconnect(); + stream.stream.close_channel(); + } } } } @@ -439,7 +450,7 @@ pub struct ServerMux { /// If this variable is true you must assume no extensions are supported. pub downgraded: bool, /// Extensions that are supported by both sides. - pub supported_extensions: Arc<[AnyProtocolExtension]>, + pub supported_extension_ids: Vec, close_tx: mpsc::Sender, muxstream_recv: mpsc::UnboundedReceiver<(ConnectPacket, MuxStream)>, } @@ -503,7 +514,7 @@ impl ServerMux { muxstream_recv: rx, close_tx: close_tx.clone(), downgraded, - supported_extensions: supported_extensions.into(), + supported_extension_ids: supported_extensions.iter().map(|x| x.get_id()).collect(), }, MuxInner { tx: write, @@ -512,6 +523,7 @@ impl ServerMux { } .server_into_future( AppendingWebSocketRead(extra_packet, read), + supported_extensions, close_rx, tx, close_tx, @@ -555,7 +567,7 @@ pub struct ClientMux { /// If this variable is true you must assume no extensions are supported. pub downgraded: bool, /// Extensions that are supported by both sides. - pub supported_extensions: Arc<[AnyProtocolExtension]>, + pub supported_extension_ids: Vec, close_tx: mpsc::Sender, } @@ -619,7 +631,10 @@ impl ClientMux { Self { close_tx: tx.clone(), downgraded, - supported_extensions: supported_extensions.into(), + supported_extension_ids: supported_extensions + .iter() + .map(|x| x.get_id()) + .collect(), }, MuxInner { tx: write, @@ -628,6 +643,7 @@ impl ClientMux { } .client_into_future( AppendingWebSocketRead(extra_packet, read), + supported_extensions, rx, tx, ), @@ -646,9 +662,9 @@ impl ClientMux { ) -> Result { if stream_type == StreamType::Udp && !self - .supported_extensions + .supported_extension_ids .iter() - .any(|x| x.get_id() == UdpProtocolExtension::ID) + .any(|x| *x == UdpProtocolExtension::ID) { return Err(WispError::UdpExtensionNotSupported); } diff --git a/wisp/src/packet.rs b/wisp/src/packet.rs index c2b2459..388fae7 100644 --- a/wisp/src/packet.rs +++ b/wisp/src/packet.rs @@ -1,6 +1,6 @@ use crate::{ extensions::{AnyProtocolExtension, ProtocolExtensionBuilder}, - ws::{self, Frame, OpCode}, + ws::{self, Frame, LockedWebSocketWrite, OpCode, WebSocketRead}, Role, WispError, WISP_VERSION, }; use bytes::{Buf, BufMut, Bytes, BytesMut}; @@ -388,6 +388,34 @@ impl Packet { } } + pub(crate) async fn maybe_handle_extension( + frame: Frame, + extensions: &mut [AnyProtocolExtension], + read: &mut (dyn WebSocketRead + Send), + write: &LockedWebSocketWrite, + ) -> Result, WispError> { + if !frame.finished { + return Err(WispError::WsFrameNotFinished); + } + if frame.opcode != OpCode::Binary { + return Err(WispError::WsFrameInvalidType); + } + let mut bytes = frame.payload; + if bytes.remaining() < 1 { + return Err(WispError::PacketTooSmall); + } + let packet_type = bytes.get_u8(); + if let Some(extension) = extensions + .iter_mut() + .find(|x| x.get_supported_packets().iter().any(|x| *x == packet_type)) + { + extension.handle_packet(bytes, read, write).await?; + Ok(None) + } else { + Ok(Some(Self::parse_packet(packet_type, bytes)?)) + } + } + fn parse_info( mut bytes: Bytes, role: Role,