diff --git a/Cargo.lock b/Cargo.lock index ae2dd9761a..3a063ac33e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -176,6 +176,45 @@ dependencies = [ "winnow", ] +[[package]] +name = "asn1-rs" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56624a96882bb8c26d61312ae18cb45868e5a9992ea73c58e45c3101e56a1e60" +dependencies = [ + "asn1-rs-derive", + "asn1-rs-impl", + "displaydoc", + "nom 7.1.3", + "num-traits", + "rusticata-macros", + "thiserror 2.0.9", + "time", +] + +[[package]] +name = "asn1-rs-derive" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.93", + "synstructure", +] + +[[package]] +name = "asn1-rs-impl" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.93", +] + [[package]] name = "assert-json-diff" version = "2.0.2" @@ -229,6 +268,28 @@ dependencies = [ "sha2 0.9.9", ] +[[package]] +name = "async-stream" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.93", +] + [[package]] name = "async-trait" version = "0.1.83" @@ -266,33 +327,47 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.4.0" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "aws-lc-fips-sys" +version = "0.13.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "2608e5a7965cc9d58c56234d346c9c89b824c4c8652b6f047b3bd0a777c0644f" +dependencies = [ + "bindgen 0.69.5", + "cc", + "cmake", + "dunce", + "fs_extra", + "regex", +] [[package]] name = "aws-lc-rs" -version = "1.12.0" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f409eb70b561706bf8abba8ca9c112729c481595893fd06a2dd9af8ed8441148" +checksum = "94b8ff6c09cd57b16da53641caa860168b88c172a5ee163b0288d3d6eea12786" dependencies = [ + "aws-lc-fips-sys", "aws-lc-sys", - "paste", + "untrusted 0.7.1", "zeroize", ] [[package]] name = "aws-lc-sys" -version = "0.24.1" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "923ded50f602b3007e5e63e3f094c479d9c8a9b42d7f4034e4afe456aa48bfd2" +checksum = "0e44d16778acaf6a9ec9899b92cebd65580b83f685446bf2e1f5d3d732f99dcd" dependencies = [ - "bindgen", + "bindgen 0.72.1", "cc", "cmake", "dunce", "fs_extra", - "paste", ] [[package]] @@ -335,6 +410,7 @@ dependencies = [ "tokio", "tokio-stream", "tokio-tungstenite", + "tokio-util", "tower", "tower-http", "tower-layer", @@ -543,7 +619,7 @@ version = "0.69.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.4", "cexpr", "clang-sys", "itertools 0.12.1", @@ -560,6 +636,26 @@ dependencies = [ "which", ] +[[package]] +name = "bindgen" +version = "0.72.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" +dependencies = [ + "bitflags 2.9.4", + "cexpr", + "clang-sys", + "itertools 0.13.0", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash 2.1.0", + "shlex", + "syn 2.0.93", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -568,9 +664,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.6.0" +version = "2.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" dependencies = [ "serde", ] @@ -620,6 +716,15 @@ dependencies = [ "generic-array", ] +[[package]] +name = "borsh" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad8646f98db542e39fc66e68a20b2144f6a732636df7c2354e74645faaa433ce" +dependencies = [ + "cfg_aliases", +] + [[package]] name = "brotli" version = "8.0.2" @@ -682,10 +787,11 @@ checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" [[package]] name = "cc" -version = "1.2.21" +version = "1.2.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8691782945451c1c383942c4874dbe63814f61cb57ef773cda2972682b7bb3c0" +checksum = "65193589c6404eb80b450d618eaf9a2cafaaafd57ecce47370519ef674a7bd44" dependencies = [ + "find-msvc-tools", "jobserver", "libc", "shlex", @@ -697,7 +803,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" dependencies = [ - "nom", + "nom 7.1.3", ] [[package]] @@ -756,9 +862,9 @@ dependencies = [ [[package]] name = "cmake" -version = "0.1.52" +version = "0.1.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c682c223677e0e5b6b7f63a64b9351844c3f1b1678a68b7ee617e30fb082620e" +checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" dependencies = [ "cc", ] @@ -812,6 +918,26 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "const_format" +version = "0.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126f97965c8ad46d6d9163268ff28432e8f6a1196a55578867832e3049df63dd" +dependencies = [ + "const_format_proc_macros", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + [[package]] name = "constant_time_eq" version = "0.1.5" @@ -891,6 +1017,21 @@ dependencies = [ "cfg-if 1.0.0", ] +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-epoch" version = "0.9.18" @@ -946,6 +1087,27 @@ dependencies = [ "subtle", ] +[[package]] +name = "csv" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf" +dependencies = [ + "csv-core", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d02f3b0da4c6504f86e9cd789d8dbafab48c2321be74e9987593de5a894d93d" +dependencies = [ + "memchr", +] + [[package]] name = "ctr" version = "0.9.2" @@ -1047,6 +1209,20 @@ dependencies = [ "zeroize", ] +[[package]] +name = "der-parser" +version = "10.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07da5016415d5a3c4dd39b11ed26f915f52fc4e0dc197d87908bc916e51bc1a6" +dependencies = [ + "asn1-rs", + "displaydoc", + "nom 7.1.3", + "num-bigint", + "num-traits", + "rusticata-macros", +] + [[package]] name = "deranged" version = "0.3.11" @@ -1087,7 +1263,7 @@ version = "2.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf1bedf64cdb9643204a36dd15b19a6ce8e7aa7f7b105868e9f1fad5ffa7d12" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.4", "byteorder", "diesel_derives", "itoa", @@ -1218,6 +1394,12 @@ dependencies = [ "cfg-if 1.0.0", ] +[[package]] +name = "endian-type" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" + [[package]] name = "enum-as-inner" version = "0.6.1" @@ -1291,7 +1473,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74fef4569247a5f429d9156b9d0a2599914385dd189c539334c625d8099d90ab" dependencies = [ "futures-core", - "nom", + "nom 7.1.3", "pin-project-lite", ] @@ -1717,6 +1899,34 @@ dependencies = [ "tower", ] +[[package]] +name = "example-serve-with-hyper-rustls" +version = "0.1.0" +dependencies = [ + "anyhow", + "axum", + "http-body", + "hyper", + "rustls 0.23.20", + "rustls-pemfile 2.2.0", + "tokio", + "tokio-rustls 0.26.1", + "tokio-util", + "tower", + "tracing", +] + +[[package]] +name = "example-serve-with-rama" +version = "0.1.0" +dependencies = [ + "axum", + "pin-project-lite", + "rama", + "tokio", + "tower", +] + [[package]] name = "example-simple-router-wasm" version = "0.1.0" @@ -1981,13 +2191,20 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "find-msvc-tools" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fd99930f64d146689264c637b5af2f0233a933bef0d8570e2526bf9e083192d" + [[package]] name = "flate2" -version = "1.0.35" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" +checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" dependencies = [ "crc32fast", + "libz-sys", "miniz_oxide", ] @@ -1999,6 +2216,7 @@ checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" dependencies = [ "futures-core", "futures-sink", + "nanorand", "spin", ] @@ -2020,7 +2238,28 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" dependencies = [ - "foreign-types-shared", + "foreign-types-shared 0.1.1", +] + +[[package]] +name = "foreign-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" +dependencies = [ + "foreign-types-macros", + "foreign-types-shared 0.3.1", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.93", ] [[package]] @@ -2029,6 +2268,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" +[[package]] +name = "foreign-types-shared" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" + [[package]] name = "form_urlencoded" version = "1.2.1" @@ -2054,12 +2299,37 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" +[[package]] +name = "fslock" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04412b8935272e3a9bae6f48c7bfff74c2911f60525404edfdd28e49884c3bfb" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "funty" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" +[[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + [[package]] name = "futures-channel" version = "0.3.31" @@ -2139,6 +2409,7 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ + "futures-channel", "futures-core", "futures-io", "futures-macro", @@ -2150,6 +2421,20 @@ dependencies = [ "slab", ] +[[package]] +name = "generator" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "605183a538e3e2a9c1038635cc5c2d194e2ee8fd0d1b66b8349fad7dbacce5a2" +dependencies = [ + "cc", + "cfg-if 1.0.0", + "libc", + "log", + "rustversion", + "windows", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -2336,6 +2621,31 @@ dependencies = [ "url", ] +[[package]] +name = "hickory-proto" +version = "0.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8a6fe56c0038198998a6f217ca4e7ef3a5e51f46163bd6dd60b5c71ca6c6502" +dependencies = [ + "async-trait", + "cfg-if 1.0.0", + "data-encoding", + "enum-as-inner", + "futures-channel", + "futures-io", + "futures-util", + "idna", + "ipnet", + "once_cell", + "rand 0.9.1", + "ring", + "thiserror 2.0.9", + "tinyvec", + "tokio", + "tracing", + "url", +] + [[package]] name = "hickory-resolver" version = "0.24.2" @@ -2344,7 +2654,7 @@ checksum = "0a2e2aba9c389ce5267d31cf1e4dace82390ae276b0b364ea55630b1fa1b44b4" dependencies = [ "cfg-if 1.0.0", "futures-util", - "hickory-proto", + "hickory-proto 0.24.4", "ipconfig", "lru-cache", "once_cell", @@ -2357,6 +2667,27 @@ dependencies = [ "tracing", ] +[[package]] +name = "hickory-resolver" +version = "0.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc62a9a99b0bfb44d2ab95a7208ac952d31060efc16241c87eaf36406fecf87a" +dependencies = [ + "cfg-if 1.0.0", + "futures-util", + "hickory-proto 0.25.2", + "ipconfig", + "moka", + "once_cell", + "parking_lot", + "rand 0.9.1", + "resolv-conf", + "smallvec", + "thiserror 2.0.9", + "tokio", + "tracing", +] + [[package]] name = "hkdf" version = "0.12.4" @@ -2447,9 +2778,9 @@ checksum = "9171a2ea8a68358193d15dd5d70c1c10a2afc3e7e4c5bc92bc9f025cebd7359c" [[package]] name = "httparse" -version = "1.9.5" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] name = "httpdate" @@ -2542,7 +2873,7 @@ dependencies = [ "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows-core", + "windows-core 0.52.0", ] [[package]] @@ -2730,6 +3061,17 @@ dependencies = [ "generic-array", ] +[[package]] +name = "io-uring" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" +dependencies = [ + "bitflags 2.9.4", + "cfg-if 1.0.0", + "libc", +] + [[package]] name = "ipconfig" version = "0.3.2" @@ -2744,9 +3086,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.10.1" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" [[package]] name = "iri-string" @@ -2776,6 +3118,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.14" @@ -2793,9 +3144,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.76" +version = "0.3.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" +checksum = "852f13bec5eba4ba9afbeb93fd7c13fe56147f055939ae21c43a29a0ecb2702e" dependencies = [ "once_cell", "wasm-bindgen", @@ -2864,6 +3215,17 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "libz-sys" +version = "1.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b70e7a7df205e92a1a4cd9aaae7898dac0aa555503cc0a649494d0d60e7651d" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + [[package]] name = "linked-hash-map" version = "0.5.6" @@ -2909,6 +3271,22 @@ version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +[[package]] +name = "loom" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca" +dependencies = [ + "cfg-if 1.0.0", + "generator", + "pin-utils", + "scoped-tls", + "serde", + "serde_json", + "tracing", + "tracing-subscriber", +] + [[package]] name = "lru-cache" version = "0.1.2" @@ -2949,6 +3327,12 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "md5" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae960838283323069879657ca3de837e9f7bbb4c7bf6ea7f1b290d5e9476d2e0" + [[package]] name = "memchr" version = "2.7.4" @@ -3049,9 +3433,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.8.2" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", ] @@ -3067,6 +3451,25 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "moka" +version = "0.12.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9321642ca94a4282428e6ea4af8cc2ca4eac48ac7a6a4ea8f33f76d0ce70926" +dependencies = [ + "crossbeam-channel", + "crossbeam-epoch", + "crossbeam-utils", + "loom", + "parking_lot", + "portable-atomic", + "rustc_version", + "smallvec", + "tagptr", + "thiserror 1.0.69", + "uuid", +] + [[package]] name = "mongodb" version = "3.1.1" @@ -3085,8 +3488,8 @@ dependencies = [ "futures-io", "futures-util", "hex", - "hickory-proto", - "hickory-resolver", + "hickory-proto 0.24.4", + "hickory-resolver 0.24.2", "hmac 0.12.1", "md-5", "mongodb-internal-macros", @@ -3143,6 +3546,15 @@ dependencies = [ "version_check", ] +[[package]] +name = "nanorand" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" +dependencies = [ + "getrandom 0.2.15", +] + [[package]] name = "native-tls" version = "0.2.12" @@ -3160,6 +3572,15 @@ dependencies = [ "tempfile", ] +[[package]] +name = "nibble_vec" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" +dependencies = [ + "smallvec", +] + [[package]] name = "nom" version = "7.1.3" @@ -3170,6 +3591,15 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "nom" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405" +dependencies = [ + "memchr", +] + [[package]] name = "nu-ansi-term" version = "0.50.1" @@ -3281,11 +3711,24 @@ dependencies = [ "memchr", ] +[[package]] +name = "oid-registry" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f40cff3dde1b6087cc5d5f5d4d65712f34016a03ed60e9c08dcc392736b5b7" +dependencies = [ + "asn1-rs", +] + [[package]] name = "once_cell" version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +dependencies = [ + "critical-section", + "portable-atomic", +] [[package]] name = "opaque-debug" @@ -3299,9 +3742,9 @@ version = "0.10.72" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.4", "cfg-if 1.0.0", - "foreign-types", + "foreign-types 0.3.2", "libc", "once_cell", "openssl-macros", @@ -3544,6 +3987,15 @@ dependencies = [ "syn 2.0.93", ] +[[package]] +name = "proc-macro-crate" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" +dependencies = [ + "toml_edit 0.23.5", +] + [[package]] name = "proc-macro-error-attr2" version = "2.0.0" @@ -3598,6 +4050,21 @@ dependencies = [ "syn 2.0.93", ] +[[package]] +name = "psl" +version = "2.1.141" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98c10a4dce9ad24c1fad826cffc79a624cf626bfaddb466e969368a53d877b30" +dependencies = [ + "psl-types", +] + +[[package]] +name = "psl-types" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac" + [[package]] name = "quanta" version = "0.12.4" @@ -3642,77 +4109,523 @@ dependencies = [ ] [[package]] -name = "quinn" -version = "0.11.6" +name = "quinn" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62e96808277ec6f97351a2380e6c25114bc9e67037775464979f3037c92d05ef" +dependencies = [ + "bytes", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash 2.1.0", + "rustls 0.23.20", + "socket2 0.5.8", + "thiserror 2.0.9", + "tokio", + "tracing", +] + +[[package]] +name = "quinn-proto" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d" +dependencies = [ + "bytes", + "getrandom 0.2.15", + "rand 0.8.5", + "ring", + "rustc-hash 2.1.0", + "rustls 0.23.20", + "rustls-pki-types", + "slab", + "thiserror 2.0.9", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c40286217b4ba3a71d644d752e6a0b71f13f1b6a2c5311acfcbe0c2418ed904" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2 0.5.8", + "tracing", + "windows-sys 0.59.0", +] + +[[package]] +name = "quote" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "radix_trie" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" +dependencies = [ + "endian-type", + "nibble_vec", +] + +[[package]] +name = "rama" +version = "0.3.0-alpha.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9abba26d2a4a60eb94a17224755035ce03f06fd1f3448915cbd8bf02dd838d" +dependencies = [ + "pin-project-lite", + "rama-core", + "rama-crypto", + "rama-dns", + "rama-http", + "rama-http-backend", + "rama-http-core", + "rama-net", + "rama-socks5", + "rama-tcp", + "rama-tls-boring", + "rama-tower", + "rama-ua", + "rama-unix", + "rama-utils", + "rama-ws", + "rustversion", + "tokio", +] + +[[package]] +name = "rama-boring" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6c52217ff947d630f3807cde9f8fe4cc69005b17a1e81fc99fa432cb3fb9c78" +dependencies = [ + "bitflags 2.9.4", + "foreign-types 0.5.0", + "libc", + "openssl-macros", + "rama-boring-sys", +] + +[[package]] +name = "rama-boring-sys" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c7fd7057828ca9fa148c704f1bf0fff12f6367891212c9c0caad63ae17902a7" +dependencies = [ + "autocfg", + "bindgen 0.72.1", + "cmake", + "fs_extra", + "fslock", +] + +[[package]] +name = "rama-boring-tokio" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b07c71d66f9fa0b52b02055b94c779e98fc27d228e67105c6e528cfd1f19a7a4" +dependencies = [ + "rama-boring", + "rama-boring-sys", + "tokio", +] + +[[package]] +name = "rama-core" +version = "0.3.0-alpha.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea03771324b3d27a4d5d450bdd288fdeac87638f7cdb5870f3d1da6503542483" +dependencies = [ + "async-stream", + "bytes", + "futures", + "parking_lot", + "pin-project-lite", + "rama-error", + "rama-macros", + "rama-utils", + "tokio", + "tokio-graceful", + "tracing", +] + +[[package]] +name = "rama-crypto" +version = "0.3.0-alpha.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91965fc4cb4bc45bd2980f6388f97dbc955bcf164fdbd81fc0e9155c4e9abe2f" +dependencies = [ + "aws-lc-rs", + "base64 0.22.1", + "rama-core", + "rama-utils", + "rcgen", + "rustls-pki-types", + "serde", + "serde_json", + "x509-parser", +] + +[[package]] +name = "rama-dns" +version = "0.3.0-alpha.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7556de219395b9b170f9fdbff10ee6a1c022749207a2d013c0c89e197bbaae3c" +dependencies = [ + "hickory-resolver 0.25.2", + "rama-core", + "rama-net", + "rama-utils", + "serde", + "tokio", +] + +[[package]] +name = "rama-error" +version = "0.3.0-alpha.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b3236ea868a50937223cbe56130b99725235c001ca8886cc01bf599736c9766" + +[[package]] +name = "rama-http" +version = "0.3.0-alpha.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52279e9b6c364ac8db44209707544eac45a3b79c1953cb3cd3985272565d9818" +dependencies = [ + "async-compression", + "bitflags 2.9.4", + "chrono", + "const_format", + "csv", + "flate2", + "http-range-header", + "httpdate", + "iri-string", + "matchit", + "mime", + "mime_guess", + "percent-encoding", + "pin-project-lite", + "rama-core", + "rama-error", + "rama-http-headers", + "rama-http-types", + "rama-net", + "rama-ua", + "rama-utils", + "rand 0.9.1", + "rawzip", + "regex", + "serde", + "serde_html_form", + "serde_json", + "smol_str", + "tokio", + "tokio-util", + "uuid", +] + +[[package]] +name = "rama-http-backend" +version = "0.3.0-alpha.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f53a4fab6c60854a5d53dccdfdec7b86be697269d523adfff3ff13cca7455a9" +dependencies = [ + "const_format", + "futures", + "h2", + "pin-project-lite", + "rama-core", + "rama-http", + "rama-http-core", + "rama-http-headers", + "rama-http-types", + "rama-net", + "rama-tcp", + "rama-unix", + "rama-utils", + "tokio", +] + +[[package]] +name = "rama-http-core" +version = "0.3.0-alpha.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42d2a4dc0b90d0ff7a2b7eda9993b51c7ad234b343c700f480ff83f7dea46966" +dependencies = [ + "atomic-waker", + "futures-channel", + "httparse", + "httpdate", + "indexmap 2.7.0", + "itoa", + "pin-project-lite", + "rama-core", + "rama-http", + "rama-http-types", + "rama-net", + "slab", + "smallvec", + "tokio", + "tokio-test", + "tokio-util", + "want", +] + +[[package]] +name = "rama-http-headers" +version = "0.3.0-alpha.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c49d5a5f7c95eaffab07609767ed60d52f6c56e7c2115565311545e7141ecd23" +dependencies = [ + "base64 0.22.1", + "httpdate", + "mime", + "rama-core", + "rama-error", + "rama-http-types", + "rama-macros", + "rama-net", + "rama-utils", + "rand 0.9.1", + "serde", + "sha1", +] + +[[package]] +name = "rama-http-types" +version = "0.3.0-alpha.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "020137823b0d45de8eb78d261a45dc92a6d2cf763a948fc01ff922cd23eeabd3" +dependencies = [ + "const_format", + "fnv", + "http", + "http-body", + "http-body-util", + "itoa", + "memchr", + "mime", + "mime_guess", + "nom 8.0.0", + "pin-project-lite", + "rama-core", + "rama-error", + "rama-macros", + "rama-utils", + "rand 0.9.1", + "serde", + "serde_json", + "smallvec", + "smol_str", + "sync_wrapper", + "tokio", + "tokio-util", +] + +[[package]] +name = "rama-macros" +version = "0.3.0-alpha.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8531184c892978544f6799b132e2ff7c00ceaf8b7d68c2d693ad441d351cbf5" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", +] + +[[package]] +name = "rama-net" +version = "0.3.0-alpha.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f2ca3d7c32de50880b81fc7d923fa3d9c9cf8d89c6557abdbd7e58758087926" +dependencies = [ + "const_format", + "flume", + "hex", + "ipnet", + "itertools 0.14.0", + "md5", + "nom 8.0.0", + "parking_lot", + "pin-project-lite", + "psl", + "radix_trie", + "rama-core", + "rama-http-types", + "rama-macros", + "rama-utils", + "serde", + "sha2 0.10.8", + "smol_str", + "socket2 0.6.0", + "tokio", +] + +[[package]] +name = "rama-socks5" +version = "0.3.0-alpha.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2aeb01a3889de2d2a30e2a9143ffd26e1ed805f04fc477b02883dc0b907533b2" +dependencies = [ + "byteorder", + "rama-core", + "rama-dns", + "rama-net", + "rama-tcp", + "rama-udp", + "rama-utils", + "rand 0.9.1", + "smallvec", + "tokio", +] + +[[package]] +name = "rama-tcp" +version = "0.3.0-alpha.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90f6b443f656ccf6d4d3cf5e288f73d5484f92c17dbe9836a1cdf13b4c9a4f67" +dependencies = [ + "rama-core", + "rama-dns", + "rama-http-types", + "rama-net", + "rama-utils", + "rand 0.9.1", + "tokio", +] + +[[package]] +name = "rama-tls-boring" +version = "0.3.0-alpha.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed51b8ae893be304f578b94702f92d564e5d293928349e92d6151d9ab78bf90" +dependencies = [ + "brotli", + "flate2", + "flume", + "itertools 0.14.0", + "moka", + "parking_lot", + "pin-project-lite", + "rama-boring", + "rama-boring-tokio", + "rama-core", + "rama-http-types", + "rama-net", + "rama-ua", + "rama-utils", + "schannel", + "tokio", + "zstd", +] + +[[package]] +name = "rama-tower" +version = "0.3.0-alpha.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62e96808277ec6f97351a2380e6c25114bc9e67037775464979f3037c92d05ef" +checksum = "f2236eed00294ddc68befaaf565e6924d1918c97eaf63d71e2448d6ab961d52c" dependencies = [ - "bytes", - "pin-project-lite", - "quinn-proto", - "quinn-udp", - "rustc-hash 2.1.0", - "rustls 0.23.20", - "socket2 0.5.8", - "thiserror 2.0.9", + "rama-core", + "rama-http-types", "tokio", - "tracing", + "tower-layer", + "tower-service", ] [[package]] -name = "quinn-proto" -version = "0.11.9" +name = "rama-ua" +version = "0.3.0-alpha.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d" +checksum = "e496c2926de78dd36d3190fe852b11e39260079b05590c531b187c997078818c" dependencies = [ - "bytes", - "getrandom 0.2.15", - "rand 0.8.5", - "ring", - "rustc-hash 2.1.0", - "rustls 0.23.20", - "rustls-pki-types", - "slab", - "thiserror 2.0.9", - "tinyvec", - "tracing", - "web-time", + "itertools 0.14.0", + "rama-core", + "rama-http-headers", + "rama-http-types", + "rama-net", + "rama-utils", + "rand 0.9.1", + "serde", + "serde_json", ] [[package]] -name = "quinn-udp" -version = "0.5.9" +name = "rama-udp" +version = "0.3.0-alpha.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c40286217b4ba3a71d644d752e6a0b71f13f1b6a2c5311acfcbe0c2418ed904" +checksum = "0460c8db3b802ffa1d1f91bd375ee431da3780d6625d2503891e881ab115339a" dependencies = [ - "cfg_aliases", - "libc", - "once_cell", - "socket2 0.5.8", - "tracing", - "windows-sys 0.59.0", + "rama-core", + "rama-net", + "tokio", + "tokio-util", ] [[package]] -name = "quote" -version = "1.0.38" +name = "rama-unix" +version = "0.3.0-alpha.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +checksum = "fa5e3efecbd7ba29667df34c9a949ed36da1d7b4f8f7b43b3b45e6234bbd932f" dependencies = [ - "proc-macro2", + "rama-core", + "rama-net", + "tokio", + "tokio-util", ] [[package]] -name = "r-efi" -version = "5.3.0" +name = "rama-utils" +version = "0.3.0-alpha.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +checksum = "02fd73071ddb078866fb7fca5def45bbfa12e7ea1cd819a0e3b701bf09ba2c72" +dependencies = [ + "parking_lot", + "pin-project-lite", + "rama-macros", + "serde", + "smol_str", + "tokio", +] [[package]] -name = "radium" -version = "0.7.0" +name = "rama-ws" +version = "0.3.0-alpha.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" +checksum = "6a6d2cc376163a79bdb2b49e8caad99b6b9c204424f8307c52b04c6627fd8e0b" +dependencies = [ + "flate2", + "rama-core", + "rama-http", + "rama-net", + "rama-utils", + "rand 0.9.1", + "tokio", +] [[package]] name = "rand" @@ -3788,7 +4701,27 @@ version = "11.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ab240315c661615f2ee9f0f2cd32d5a7343a84d5ebcccb99d46e6637565e7b0" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.4", +] + +[[package]] +name = "rawzip" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70171b805bd97a69690df1b634104649ad193430aa60d8305dfb9b470fe690a8" + +[[package]] +name = "rcgen" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c83367ba62b3f1dbd0f086ede4e5ebfb4713fb234dbbc5807772a31245ff46d" +dependencies = [ + "aws-lc-rs", + "pem", + "rustls-pki-types", + "time", + "x509-parser", + "yasna", ] [[package]] @@ -3818,7 +4751,7 @@ version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.4", ] [[package]] @@ -3912,7 +4845,7 @@ dependencies = [ "futures-core", "futures-timer", "mime", - "nom", + "nom 7.1.3", "pin-project-lite", "reqwest", "thiserror 1.0.69", @@ -3938,7 +4871,7 @@ dependencies = [ "cfg-if 1.0.0", "getrandom 0.2.15", "libc", - "untrusted", + "untrusted 0.9.0", "windows-sys 0.52.0", ] @@ -3999,13 +4932,22 @@ dependencies = [ "semver", ] +[[package]] +name = "rusticata-macros" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" +dependencies = [ + "nom 7.1.3", +] + [[package]] name = "rustix" version = "0.38.42" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.4", "errno", "libc", "linux-raw-sys", @@ -4074,7 +5016,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ "ring", - "untrusted", + "untrusted 0.9.0", ] [[package]] @@ -4086,7 +5028,7 @@ dependencies = [ "aws-lc-rs", "ring", "rustls-pki-types", - "untrusted", + "untrusted 0.9.0", ] [[package]] @@ -4119,6 +5061,12 @@ dependencies = [ "pin-project-lite", ] +[[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" @@ -4132,7 +5080,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ "ring", - "untrusted", + "untrusted 0.9.0", ] [[package]] @@ -4141,7 +5089,7 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.4", "core-foundation", "core-foundation-sys", "libc", @@ -4405,10 +5353,20 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.13.2" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +dependencies = [ + "serde", +] + +[[package]] +name = "smol_str" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "9676b89cd56310a87b93dec47b11af744f34d5fc9f367b829474eec0a891350d" dependencies = [ + "borsh", "serde", ] @@ -4457,7 +5415,7 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7bba3a93db0cc4f7bdece8bb09e77e2e785c20bfebf79eb8340ed80708048790" dependencies = [ - "nom", + "nom 7.1.3", "unicode_categories", ] @@ -4563,7 +5521,7 @@ checksum = "64bb4714269afa44aef2755150a0fc19d756fb580a67db8885608cf02f47d06a" dependencies = [ "atoi", "base64 0.22.1", - "bitflags 2.6.0", + "bitflags 2.9.4", "byteorder", "bytes", "crc", @@ -4605,7 +5563,7 @@ checksum = "6fa91a732d854c5d7726349bb4bb879bb9478993ceb764247660aee25f67c2f8" dependencies = [ "atoi", "base64 0.22.1", - "bitflags 2.6.0", + "bitflags 2.9.4", "byteorder", "crc", "dotenvy", @@ -4735,7 +5693,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.4", "core-foundation", "system-configuration-sys", ] @@ -4750,6 +5708,12 @@ dependencies = [ "libc", ] +[[package]] +name = "tagptr" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" + [[package]] name = "take_mut" version = "0.2.2" @@ -4898,20 +5862,35 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.44.2" +version = "1.47.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48" +checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" dependencies = [ "backtrace", "bytes", + "io-uring", "libc", "mio", "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.8", + "slab", + "socket2 0.6.0", "tokio-macros", - "windows-sys 0.52.0", + "windows-sys 0.59.0", +] + +[[package]] +name = "tokio-graceful" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45740b38b48641855471cd402922e89156bdfbd97b69b45eeff170369cc18c7d" +dependencies = [ + "loom", + "pin-project-lite", + "slab", + "tokio", + "tracing", ] [[package]] @@ -5003,6 +5982,19 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-test" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2468baabc3311435b55dd935f702f42cd1b8abb7e754fb7dfb16bd36aa88f9f7" +dependencies = [ + "async-stream", + "bytes", + "futures-core", + "tokio", + "tokio-stream", +] + [[package]] name = "tokio-tungstenite" version = "0.27.0" @@ -5037,8 +6029,8 @@ checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" dependencies = [ "serde", "serde_spanned", - "toml_datetime", - "toml_edit", + "toml_datetime 0.6.8", + "toml_edit 0.22.24", ] [[package]] @@ -5050,6 +6042,15 @@ dependencies = [ "serde", ] +[[package]] +name = "toml_datetime" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a197c0ec7d131bfc6f7e82c8442ba1595aeab35da7adbf05b6b73cd06a16b6be" +dependencies = [ + "serde_core", +] + [[package]] name = "toml_edit" version = "0.22.24" @@ -5059,7 +6060,28 @@ dependencies = [ "indexmap 2.7.0", "serde", "serde_spanned", - "toml_datetime", + "toml_datetime 0.6.8", + "winnow", +] + +[[package]] +name = "toml_edit" +version = "0.23.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2ad0b7ae9cfeef5605163839cb9221f453399f15cfb5c10be9885fcf56611f9" +dependencies = [ + "indexmap 2.7.0", + "toml_datetime 0.7.1", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cf893c33be71572e0e9aa6dd15e6677937abd686b066eac3f8cd3531688a627" +dependencies = [ "winnow", ] @@ -5091,7 +6113,7 @@ checksum = "403fa3b783d4b626a8ad51d766ab03cb6d2dbfc46b1c5d4448395e6628dc9697" dependencies = [ "async-compression", "base64 0.22.1", - "bitflags 2.6.0", + "bitflags 2.9.4", "bytes", "futures-core", "futures-util", @@ -5299,6 +6321,12 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + [[package]] name = "unicode_categories" version = "0.1.1" @@ -5315,6 +6343,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + [[package]] name = "untrusted" version = "0.9.0" @@ -5353,12 +6387,14 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "uuid" -version = "1.11.0" +version = "1.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" +checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.3.3", + "js-sys", "serde", + "wasm-bindgen", ] [[package]] @@ -5441,20 +6477,22 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.99" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" +checksum = "ab10a69fbd0a177f5f649ad4d8d3305499c42bab9aef2f7ff592d0ec8f833819" dependencies = [ "cfg-if 1.0.0", "once_cell", + "rustversion", "wasm-bindgen-macro", + "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.99" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" +checksum = "0bb702423545a6007bbc368fde243ba47ca275e549c8a28617f56f6ba53b1d1c" dependencies = [ "bumpalo", "log", @@ -5466,9 +6504,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.49" +version = "0.4.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38176d9b44ea84e9184eff0bc34cc167ed044f816accfe5922e54d84cf48eca2" +checksum = "a0b221ff421256839509adbb55998214a70d829d3a28c69b4a6672e9d2a42f67" dependencies = [ "cfg-if 1.0.0", "js-sys", @@ -5479,9 +6517,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.99" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" +checksum = "fc65f4f411d91494355917b605e1480033152658d71f722a90647f56a70c88a0" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -5489,9 +6527,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.99" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" +checksum = "ffc003a991398a8ee604a401e194b6b3a39677b3173d6e74495eb51b82e99a32" dependencies = [ "proc-macro2", "quote", @@ -5502,9 +6540,12 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.99" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" +checksum = "293c37f4efa430ca14db3721dfbe48d8c33308096bd44d80ebaa775ab71ba1cf" +dependencies = [ + "unicode-ident", +] [[package]] name = "wasm-streams" @@ -5521,9 +6562,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.76" +version = "0.3.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc" +checksum = "fbe734895e869dc429d78c4b433f8d17d95f8d05317440b4fad5ab2d33e596dc" dependencies = [ "js-sys", "wasm-bindgen", @@ -5614,6 +6655,28 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.61.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" +dependencies = [ + "windows-collections", + "windows-core 0.61.2", + "windows-future", + "windows-link", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" +dependencies = [ + "windows-core 0.61.2", +] + [[package]] name = "windows-core" version = "0.52.0" @@ -5623,14 +6686,76 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-core" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result 0.3.4", + "windows-strings 0.4.2", +] + +[[package]] +name = "windows-future" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" +dependencies = [ + "windows-core 0.61.2", + "windows-link", + "windows-threading", +] + +[[package]] +name = "windows-implement" +version = "0.60.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.93", +] + +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.93", +] + +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-numerics" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" +dependencies = [ + "windows-core 0.61.2", + "windows-link", +] + [[package]] name = "windows-registry" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" dependencies = [ - "windows-result", - "windows-strings", + "windows-result 0.2.0", + "windows-strings 0.1.0", "windows-targets 0.52.6", ] @@ -5643,16 +6768,34 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-strings" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" dependencies = [ - "windows-result", + "windows-result 0.2.0", "windows-targets 0.52.6", ] +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -5711,6 +6854,15 @@ dependencies = [ "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows-threading" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" +dependencies = [ + "windows-link", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -5826,7 +6978,7 @@ version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.4", ] [[package]] @@ -5850,6 +7002,33 @@ dependencies = [ "tap", ] +[[package]] +name = "x509-parser" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb3e137310115a65136898d2079f003ce33331a6c4b0d51f1531d1be082b6425" +dependencies = [ + "asn1-rs", + "data-encoding", + "der-parser", + "lazy_static", + "nom 7.1.3", + "oid-registry", + "ring", + "rusticata-macros", + "thiserror 2.0.9", + "time", +] + +[[package]] +name = "yasna" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" +dependencies = [ + "time", +] + [[package]] name = "yoke" version = "0.7.5" diff --git a/axum/Cargo.toml b/axum/Cargo.toml index 393074f0f7..d9242b895b 100644 --- a/axum/Cargo.toml +++ b/axum/Cargo.toml @@ -121,6 +121,7 @@ serde_urlencoded = { version = "0.7", optional = true } sha1 = { version = "0.10", optional = true } tokio = { package = "tokio", version = "1.44", features = ["time"], optional = true } tokio-tungstenite = { version = "0.27.0", optional = true } +tokio-util = "0.7" tracing = { version = "0.1", default-features = false, optional = true } # doc dependencies diff --git a/axum/src/serve/connection.rs b/axum/src/serve/connection.rs new file mode 100644 index 0000000000..66c185c70d --- /dev/null +++ b/axum/src/serve/connection.rs @@ -0,0 +1,189 @@ +use std::{ + convert::Infallible, + error::Error as StdError, + future::Future, + ops::DerefMut, + pin::Pin, + task::{Context, Poll}, +}; + +use axum_core::{body::Body, extract::Request, response::Response}; +use http_body::Body as HttpBody; +use hyper::{ + body::Incoming, + rt::{Read as HyperRead, Write as HyperWrite}, + service::HttpService as HyperHttpService, + service::Service as HyperService, +}; +#[cfg(feature = "http1")] +use hyper_util::rt::TokioTimer; +use hyper_util::{ + rt::{TokioExecutor, TokioIo}, + server::conn::auto::{HttpServerConnExec, UpgradeableConnection}, +}; +#[cfg(any(feature = "http1", feature = "http2"))] +use hyper_util::{server::conn::auto::Builder, service::TowerToHyperService}; +use pin_project_lite::pin_project; +use tokio::io::{AsyncRead, AsyncWrite}; +use tokio_util::sync::{CancellationToken, WaitForCancellationFutureOwned}; +use tower::{Service, ServiceExt}; + +/// Types that can handle connections accepted by a [`Listener`]. +pub trait ConnectionBuilder: Clone { + /// Take an accepted connection from the [`Listener`] (for example a `TcpStream`) and handle + /// requests on it using the provided service (usually a [`Router`](crate::Router)). + fn build_connection(&mut self, io: Io, service: S) -> impl Connection; + + /// Signal to all ongoing connections that the server is shutting down. + fn graceful_shutdown(&mut self); +} + +/// A connection returned by [`ConnectionBuilder`]. +/// +/// This type must be driven by calling [`Connection::poll_connection`]. +/// +/// Note that each [`Connection`] may handle multiple requests. +pub trait Connection: Send { + /// Poll the connection. + fn poll_connection( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll>>; +} + +impl Connection for Pin +where + Ptr: DerefMut + Send, + Fut: Future>> + Send, +{ + fn poll_connection( + mut self: std::pin::Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> std::task::Poll>> { + self.as_mut().poll(cx) + } +} + +pin_project! { + /// An implementation of [`Connection`] when serving with hyper. + pub struct HyperConnection<'a, I, S: HyperHttpService, E> { + #[pin] + inner: UpgradeableConnection<'a, I, S, E>, + #[pin] + shutdown: Option, + } +} + +impl Connection for HyperConnection<'_, I, S, E> +where + S: HyperService, Response = Response> + Send, + S::Error: Into>, + S::Future: Send + 'static, + I: HyperRead + HyperWrite + Unpin + Send + 'static, + B: HttpBody + Send + 'static, + B::Data: Send, + B::Error: Into>, + E: HttpServerConnExec + Send + Sync, +{ + fn poll_connection( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll>> { + let mut this = self.project(); + if let Some(shutdown) = this.shutdown.as_mut().as_pin_mut() { + if shutdown.poll(cx).is_ready() { + tracing::trace!("signal received in connection, starting graceful shutdown"); + this.inner.as_mut().graceful_shutdown(); + this.shutdown.set(None); + } + } + this.inner.poll(cx) + } +} + +/// An implementation of [`ConnectionBuilder`] when serving with hyper. +#[derive(Debug, Clone)] +pub struct Hyper { + builder: Builder, + shutdown: CancellationToken, +} + +impl Hyper { + /// Create a new [`ConnectionBuilder`] implementation from a + /// [`hyper_util::server::conn::auto::Builder`]. This builder may be set up in any way that the + /// user may need. + /// + /// # Example + /// + /// ```rust + /// # async { + /// # use axum::Router; + /// # use axum::serve::{Hyper, serve_with_connection_builder}; + /// # use hyper_util::server::conn::auto::Builder; + /// # use hyper_util::rt::TokioExecutor; + /// let mut builder = Builder::new(TokioExecutor::new()).http2_only(); + /// builder.http2().enable_connect_protocol(); + /// let connection_builder = Hyper::new(builder); + /// let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap(); + /// serve_with_connection_builder(listener, connection_builder, Router::new()).await.unwrap(); + /// # }; + /// ``` + #[must_use] + pub fn new(builder: Builder) -> Self { + Self { + builder, + shutdown: CancellationToken::new(), + } + } +} + +impl Default for Hyper { + fn default() -> Self { + #[allow(unused_mut)] + let mut builder = Builder::new(TokioExecutor::new()); + + // Enable Hyper's default HTTP/1 request header timeout. + #[cfg(feature = "http1")] + builder.http1().timer(TokioTimer::new()); + + // CONNECT protocol needed for HTTP/2 websockets + #[cfg(feature = "http2")] + builder.http2().enable_connect_protocol(); + + Self::new(builder) + } +} + +impl ConnectionBuilder for Hyper +where + Io: AsyncRead + AsyncWrite + Send + Unpin + 'static, + S: Service, Error = Infallible> + Clone + Send + 'static, + S::Future: Send, + B: HttpBody + Send + 'static, + B::Data: Send, + B::Error: Into>, +{ + fn build_connection(&mut self, io: Io, service: S) -> impl Connection { + fn map_body(req: Request) -> Request { + req.map(Body::new) + } + + let hyper_service = TowerToHyperService::new( + service.map_request(map_body as fn(Request) -> Request), + ); + + let io = TokioIo::new(io); + let hyper_connection = self + .builder + .serve_connection_with_upgrades(io, hyper_service); + + HyperConnection { + inner: hyper_connection, + shutdown: Some(self.shutdown.clone().cancelled_owned()), + } + } + + fn graceful_shutdown(&mut self) { + self.shutdown.cancel(); + } +} diff --git a/axum/src/serve/mod.rs b/axum/src/serve/mod.rs index 412ab82920..b5d57d582d 100644 --- a/axum/src/serve/mod.rs +++ b/axum/src/serve/mod.rs @@ -4,26 +4,23 @@ use std::{ convert::Infallible, error::Error as StdError, fmt::Debug, - future::{Future, IntoFuture}, + future::{poll_fn, Future, IntoFuture}, io, marker::PhantomData, pin::pin, }; -use axum_core::{body::Body, extract::Request, response::Response}; -use futures_util::FutureExt; +use axum_core::{extract::Request, response::Response}; use http_body::Body as HttpBody; -use hyper::body::Incoming; -use hyper_util::rt::{TokioExecutor, TokioIo, TokioTimer}; -#[cfg(any(feature = "http1", feature = "http2"))] -use hyper_util::{server::conn::auto::Builder, service::TowerToHyperService}; use tokio::sync::watch; use tower::ServiceExt as _; use tower_service::Service; +mod connection; mod listener; -pub use self::listener::{Listener, ListenerExt, TapIo}; +pub use connection::{Connection, ConnectionBuilder, Hyper, HyperConnection}; +pub use listener::{Listener, ListenerExt, TapIo}; /// Serve the service with the supplied listener. /// @@ -98,7 +95,7 @@ pub use self::listener::{Listener, ListenerExt, TapIo}; /// [`HandlerWithoutStateExt::into_make_service_with_connect_info`]: crate::handler::HandlerWithoutStateExt::into_make_service_with_connect_info /// [`HandlerService::into_make_service_with_connect_info`]: crate::handler::HandlerService::into_make_service_with_connect_info #[cfg(all(feature = "tokio", any(feature = "http1", feature = "http2")))] -pub fn serve(listener: L, make_service: M) -> Serve +pub fn serve(listener: L, make_service: M) -> Serve where L: Listener, M: for<'a> Service, Error = Infallible, Response = S>, @@ -107,9 +104,41 @@ where B: HttpBody + Send + 'static, B::Data: Send, B::Error: Into>, +{ + serve_with_connection_builder(listener, Hyper::default(), make_service) +} + +/// Serve with a custom [`ConnectionBuilder`] implementation. +/// +/// # Example +/// +/// ```rust +/// # async { +/// # use axum::Router; +/// # use axum::serve::{Hyper, serve_with_connection_builder}; +/// let connection_builder = Hyper::default(); +/// let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap(); +/// serve_with_connection_builder(listener, connection_builder, Router::new()).await.unwrap(); +/// # }; +/// ``` +pub fn serve_with_connection_builder( + listener: L, + connection_builder: C, + make_service: M, +) -> Serve +where + L: Listener, + C: ConnectionBuilder + Send + 'static, + M: for<'a> Service, Error = Infallible, Response = S>, + S: Service, Error = Infallible> + Clone + Send + 'static, + S::Future: Send, + B: HttpBody + Send + 'static, + B::Data: Send, + B::Error: Into>, { Serve { listener, + connection_builder, make_service, _marker: PhantomData, } @@ -118,14 +147,15 @@ where /// Future returned by [`serve`]. #[cfg(all(feature = "tokio", any(feature = "http1", feature = "http2")))] #[must_use = "futures must be awaited or polled"] -pub struct Serve { +pub struct Serve { listener: L, + connection_builder: C, make_service: M, _marker: PhantomData<(S, B)>, } #[cfg(all(feature = "tokio", any(feature = "http1", feature = "http2")))] -impl Serve +impl Serve where L: Listener, { @@ -155,12 +185,13 @@ where /// /// Similarly to [`serve`], although this future resolves to `io::Result<()>`, it will never /// error. It returns `Ok(())` only after the `signal` future completes. - pub fn with_graceful_shutdown(self, signal: F) -> WithGracefulShutdown + pub fn with_graceful_shutdown(self, signal: F) -> WithGracefulShutdown where F: Future + Send + 'static, { WithGracefulShutdown { listener: self.listener, + connection_builder: self.connection_builder, make_service: self.make_service, signal, _marker: PhantomData, @@ -174,10 +205,11 @@ where } #[cfg(all(feature = "tokio", any(feature = "http1", feature = "http2")))] -impl Serve +impl Serve where L: Listener, L::Addr: Debug, + C: ConnectionBuilder + Send + 'static, M: for<'a> Service, Error = Infallible, Response = S> + Send + 'static, for<'a> >>::Future: Send, S: Service, Error = Infallible> + Clone + Send + 'static, @@ -189,46 +221,56 @@ where async fn run(self) -> ! { let Self { mut listener, + connection_builder, mut make_service, _marker, } = self; - let (signal_tx, _signal_rx) = watch::channel(()); let (_close_tx, close_rx) = watch::channel(()); loop { let (io, remote_addr) = listener.accept().await; - handle_connection(&mut make_service, &signal_tx, &close_rx, io, remote_addr).await; + handle_connection( + &mut make_service, + &close_rx, + io, + remote_addr, + connection_builder.clone(), + ) + .await; } } } #[cfg(all(feature = "tokio", any(feature = "http1", feature = "http2")))] -impl Debug for Serve +impl Debug for Serve where - L: Debug + 'static, + L: Debug, + C: Debug, M: Debug, { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let Self { listener, + connection_builder, make_service, _marker: _, } = self; - let mut s = f.debug_struct("Serve"); - s.field("listener", listener) - .field("make_service", make_service); - - s.finish() + f.debug_struct("Serve") + .field("listener", listener) + .field("connection_builder", connection_builder) + .field("make_service", make_service) + .finish() } } #[cfg(all(feature = "tokio", any(feature = "http1", feature = "http2")))] -impl IntoFuture for Serve +impl IntoFuture for Serve where L: Listener, L::Addr: Debug, + C: ConnectionBuilder + Send + 'static, M: for<'a> Service, Error = Infallible, Response = S> + Send + 'static, for<'a> >>::Future: Send, S: Service, Error = Infallible> + Clone + Send + 'static, @@ -248,15 +290,16 @@ where /// Serve future with graceful shutdown enabled. #[cfg(all(feature = "tokio", any(feature = "http1", feature = "http2")))] #[must_use = "futures must be awaited or polled"] -pub struct WithGracefulShutdown { +pub struct WithGracefulShutdown { listener: L, + connection_builder: C, make_service: M, signal: F, _marker: PhantomData<(S, B)>, } #[cfg(all(feature = "tokio", any(feature = "http1", feature = "http2")))] -impl WithGracefulShutdown +impl WithGracefulShutdown where L: Listener, { @@ -267,10 +310,11 @@ where } #[cfg(all(feature = "tokio", any(feature = "http1", feature = "http2")))] -impl WithGracefulShutdown +impl WithGracefulShutdown where L: Listener, L::Addr: Debug, + C: ConnectionBuilder + Send + 'static, M: for<'a> Service, Error = Infallible, Response = S> + Send + 'static, for<'a> >>::Future: Send, S: Service, Error = Infallible> + Clone + Send + 'static, @@ -285,6 +329,7 @@ where mut listener, mut make_service, signal, + mut connection_builder, _marker, } = self; @@ -298,15 +343,25 @@ where let (close_tx, close_rx) = watch::channel(()); loop { - let (io, remote_addr) = tokio::select! { - conn = listener.accept() => conn, - _ = signal_tx.closed() => { + use futures_util::future::{select, Either}; + + match select(pin!(listener.accept()), pin!(signal_tx.closed())).await { + Either::Left(((io, remote_addr), _)) => { + handle_connection( + &mut make_service, + &close_rx, + io, + remote_addr, + connection_builder.clone(), + ) + .await; + } + Either::Right(((), _)) => { + connection_builder.graceful_shutdown(); trace!("signal received, not accepting new connections"); break; } - }; - - handle_connection(&mut make_service, &signal_tx, &close_rx, io, remote_addr).await; + } } drop(close_rx); @@ -321,9 +376,10 @@ where } #[cfg(all(feature = "tokio", any(feature = "http1", feature = "http2")))] -impl Debug for WithGracefulShutdown +impl Debug for WithGracefulShutdown where - L: Debug + 'static, + L: Debug, + C: Debug, M: Debug, S: Debug, F: Debug, @@ -331,6 +387,7 @@ where fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let Self { listener, + connection_builder, make_service, signal, _marker: _, @@ -338,6 +395,7 @@ where f.debug_struct("WithGracefulShutdown") .field("listener", listener) + .field("connection_builder", connection_builder) .field("make_service", make_service) .field("signal", signal) .finish() @@ -345,10 +403,11 @@ where } #[cfg(all(feature = "tokio", any(feature = "http1", feature = "http2")))] -impl IntoFuture for WithGracefulShutdown +impl IntoFuture for WithGracefulShutdown where L: Listener, L::Addr: Debug, + C: ConnectionBuilder + Send + 'static, M: for<'a> Service, Error = Infallible, Response = S> + Send + 'static, for<'a> >>::Future: Send, S: Service, Error = Infallible> + Clone + Send + 'static, @@ -369,15 +428,16 @@ where } } -async fn handle_connection( +async fn handle_connection( make_service: &mut M, - signal_tx: &watch::Sender<()>, close_rx: &watch::Receiver<()>, io: ::Io, remote_addr: ::Addr, + mut connection_builder: C, ) where L: Listener, L::Addr: Debug, + C: ConnectionBuilder + Send + 'static, M: for<'a> Service, Error = Infallible, Response = S> + Send + 'static, for<'a> >>::Future: Send, S: Service, Error = Infallible> + Clone + Send + 'static, @@ -386,8 +446,6 @@ async fn handle_connection( B::Data: Send, B::Error: Into>, { - let io = TokioIo::new(io); - trace!("connection {remote_addr:?} accepted"); make_service @@ -401,41 +459,19 @@ async fn handle_connection( remote_addr, }) .await - .unwrap_or_else(|err| match err {}) - .map_request(|req: Request| req.map(Body::new)); + .unwrap_or_else(|err| match err {}); - let hyper_service = TowerToHyperService::new(tower_service); - let signal_tx = signal_tx.clone(); let close_rx = close_rx.clone(); tokio::spawn(async move { - #[allow(unused_mut)] - let mut builder = Builder::new(TokioExecutor::new()); - - // Enable Hyper's default HTTP/1 request header timeout. - #[cfg(feature = "http1")] - builder.http1().timer(TokioTimer::new()); + let connection = connection_builder.build_connection(io, tower_service); - // CONNECT protocol needed for HTTP/2 websockets - #[cfg(feature = "http2")] - builder.http2().enable_connect_protocol(); + let mut connection = pin!(connection); - let mut conn = pin!(builder.serve_connection_with_upgrades(io, hyper_service)); - let mut signal_closed = pin!(signal_tx.closed().fuse()); + let connection_future = poll_fn(|cx| connection.as_mut().poll_connection(cx)); - loop { - tokio::select! { - result = conn.as_mut() => { - if let Err(_err) = result { - trace!("failed to serve connection: {_err:#}"); - } - break; - } - _ = &mut signal_closed => { - trace!("signal received in task, starting graceful shutdown"); - conn.as_mut().graceful_shutdown(); - } - } + if let Err(err) = connection_future.await { + trace!(error = debug(err), "failed to serve connection"); } drop(close_rx); @@ -452,7 +488,7 @@ pub struct IncomingStream<'a, L> where L: Listener, { - io: &'a TokioIo, + io: &'a L::Io, remote_addr: L::Addr, } @@ -462,7 +498,7 @@ where { /// Get a reference to the inner IO type. pub fn io(&self) -> &L::Io { - self.io.inner() + self.io } /// Returns the remote address that this stream is bound to. @@ -525,7 +561,7 @@ mod tests { body::to_bytes, handler::{Handler, HandlerWithoutStateExt}, routing::get, - serve::ListenerExt, + serve::{serve_with_connection_builder, Connection, ConnectionBuilder, ListenerExt}, Router, ServiceExt, }; @@ -842,4 +878,33 @@ mod tests { app.into_make_service(), ); } + + #[crate::test] + async fn serving_without_hyper() { + #[derive(Clone)] + struct OkGenerator; + + impl ConnectionBuilder for OkGenerator { + fn build_connection(&mut self, mut io: Io, _service: S) -> impl Connection { + Box::pin(async move { + io.write_all(b"OK").await?; + Ok(()) + }) + } + + fn graceful_shutdown(&mut self) {} + } + + let (mut client, server) = io::duplex(1024); + let listener = ReadyListener(Some(server)); + + let app = Router::new().route("/", get(|| async { "Hello, World!" })); + + tokio::spawn(serve_with_connection_builder(listener, OkGenerator, app).into_future()); + + let mut buf = [0u8; 2]; + client.read_exact(&mut buf).await.unwrap(); + + assert_eq!(&buf, b"OK"); + } } diff --git a/examples/serve-with-hyper-rustls/Cargo.toml b/examples/serve-with-hyper-rustls/Cargo.toml new file mode 100644 index 0000000000..8e92732a66 --- /dev/null +++ b/examples/serve-with-hyper-rustls/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "example-serve-with-hyper-rustls" +version = "0.1.0" +edition = "2021" +publish = false + +[dependencies] +anyhow = "1.0" +axum = { path = "../../axum", features = ["http1", "http2"] } +http-body = "1.0" +hyper = "1.0" +rustls = "0.23" +rustls-pemfile = "2" +tokio = { version = "1.0", features = ["full"] } +tokio-rustls = { version = "0.26", default-features = false } +tokio-util = "0.7" +tower = { version = "0.5.2", features = ["util"] } +tracing = "0.1.41" diff --git a/examples/serve-with-hyper-rustls/self_signed_certs/cert.pem b/examples/serve-with-hyper-rustls/self_signed_certs/cert.pem new file mode 100644 index 0000000000..656aa88055 --- /dev/null +++ b/examples/serve-with-hyper-rustls/self_signed_certs/cert.pem @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDkzCCAnugAwIBAgIUXVYkRCrM/ge03DVymDtXCuybp7gwDQYJKoZIhvcNAQEL +BQAwWTELMAkGA1UEBhMCVVMxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDESMBAGA1UEAwwJbG9jYWxob3N0MB4X +DTIxMDczMTE0MjIxMloXDTIyMDczMTE0MjIxMlowWTELMAkGA1UEBhMCVVMxEzAR +BgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5 +IEx0ZDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEA02V5ZjmqLB/VQwTarrz/35qsa83L+DbAoa0001+jVmmC+G9Nufi0 +daroFWj/Uicv2fZWETU8JoZKUrX4BK9og5cg5rln/CtBRWCUYIwRgY9R/CdBGPn4 +kp+XkSJaCw74ZIyLy/Zfux6h8ES1m9YRnBza+s7U+ImRBRf4MRPtXQ3/mqJxAZYq +dOnKnvssRyD2qutgVTAxwMUvJWIivRhRYDj7WOpS4CEEeQxP1iH1/T5P7FdtTGdT +bVBABCA8JhL96uFGPpOYHcM/7R5EIA3yZ5FNg931QzoDITjtXGtQ6y9/l/IYkWm6 +J67RWcN0IoTsZhz0WNU4gAeslVtJLofn8QIDAQABo1MwUTAdBgNVHQ4EFgQUzFnK +NfS4LAYuKeWwHbzooER0yZ0wHwYDVR0jBBgwFoAUzFnKNfS4LAYuKeWwHbzooER0 +yZ0wDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAk4O+e9jia59W +ZwetN4GU7OWcYhmOgSizRSs6u7mTfp62LDMt96WKU3THksOnZ44HnqWQxsSfdFVU +XJD12tjvVU8Z4FWzQajcHeemUYiDze8EAh6TnxnUcOrU8IcwiKGxCWRY/908jnWg ++MMscfMCMYTRdeTPqD8fGzAlUCtmyzH6KLE3s4Oo/r5+NR+Uvrwpdvb7xe0MwwO9 +Q/zR4N8ep/HwHVEObcaBofE1ssZLksX7ZgCP9wMgXRWpNAtC5EWxMbxYjBfWFH24 +fDJlBMiGJWg8HHcxK7wQhFh+fuyNzE+xEWPsI9VL1zDftd9x8/QsOagyEOnY8Vxr +AopvZ09uEQ== +-----END CERTIFICATE----- diff --git a/examples/serve-with-hyper-rustls/self_signed_certs/key.pem b/examples/serve-with-hyper-rustls/self_signed_certs/key.pem new file mode 100644 index 0000000000..3de14eb32f --- /dev/null +++ b/examples/serve-with-hyper-rustls/self_signed_certs/key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDTZXlmOaosH9VD +BNquvP/fmqxrzcv4NsChrTTTX6NWaYL4b025+LR1qugVaP9SJy/Z9lYRNTwmhkpS +tfgEr2iDlyDmuWf8K0FFYJRgjBGBj1H8J0EY+fiSn5eRIloLDvhkjIvL9l+7HqHw +RLWb1hGcHNr6ztT4iZEFF/gxE+1dDf+aonEBlip06cqe+yxHIPaq62BVMDHAxS8l +YiK9GFFgOPtY6lLgIQR5DE/WIfX9Pk/sV21MZ1NtUEAEIDwmEv3q4UY+k5gdwz/t +HkQgDfJnkU2D3fVDOgMhOO1ca1DrL3+X8hiRabonrtFZw3QihOxmHPRY1TiAB6yV +W0kuh+fxAgMBAAECggEADltu8k1qTFLhJgsXWxTFAAe+PBgfCT2WuaRM2So+qqjB +12Of0MieYPt5hbK63HaC3nfHgqWt7yPhulpXfOH45C8IcgMXl93MMg0MJr58leMI ++2ojFrIrerHSFm5R1TxwDEwrVm/mMowzDWFtQCc6zPJ8wNn5RuP48HKfTZ3/2fjw +zEjSwPO2wFMfo1EJNTjlI303lFbdFBs67NaX6puh30M7Tn+gznHKyO5a7F57wkIt +fkgnEy/sgMedQlwX7bRpUoD6f0fZzV8Qz4cHFywtYErczZJh3VGitJoO/VCIDdty +RPXOAqVDd7EpP1UUehZlKVWZ0OZMEfRgKbRCel5abQKBgQDwgwrIQ5+BiZv6a0VT +ETeXB+hRbvBinRykNo/RvLc3j1enRh9/zO/ShadZIXgOAiM1Jnr5Gp8KkNGca6K1 +myhtad7xYPODYzNXXp6T1OPgZxHZLIYzVUj6ypXeV64Te5ZiDaJ1D49czsq+PqsQ +XRcgBJSNpFtDFiXWpjXWfx8PxwKBgQDhAnLY5Sl2eeQo+ud0MvjwftB/mN2qCzJY +5AlQpRI4ThWxJgGPuHTR29zVa5iWNYuA5LWrC1y/wx+t5HKUwq+5kxvs+npYpDJD +ZX/w0Glc6s0Jc/mFySkbw9B2LePedL7lRF5OiAyC6D106Sc9V2jlL4IflmOzt4CD +ZTNbLtC6hwKBgHfIzBXxl/9sCcMuqdg1Ovp9dbcZCaATn7ApfHd5BccmHQGyav27 +k7XF2xMJGEHhzqcqAxUNrSgV+E9vTBomrHvRvrd5Ec7eGTPqbBA0d0nMC5eeFTh7 +wV0miH20LX6Gjt9G6yJiHYSbeV5G1+vOcTYBEft5X/qJjU7aePXbWh0BAoGBAJlV +5tgCCuhvFloK6fHYzqZtdT6O+PfpW20SMXrgkvMF22h2YvgDFrDwqKRUB47NfHzg +3yBpxNH1ccA5/w97QO8w3gX3h6qicpJVOAPusu6cIBACFZfjRv1hyszOZwvw+Soa +Fj5kHkqTY1YpkREPYS9V2dIW1Wjic1SXgZDw7VM/AoGAP/cZ3ZHTSCDTFlItqy5C +rIy2AiY0WJsx+K0qcvtosPOOwtnGjWHb1gdaVdfX/IRkSsX4PAOdnsyidNC5/l/m +y8oa+5WEeGFclWFhr4dnTA766o8HrM2UjIgWWYBF2VKdptGnHxFeJWFUmeQC/xeW +w37pCS7ykL+7gp7V0WShYsw= +-----END PRIVATE KEY----- diff --git a/examples/serve-with-hyper-rustls/src/main.rs b/examples/serve-with-hyper-rustls/src/main.rs new file mode 100644 index 0000000000..6d163d99c7 --- /dev/null +++ b/examples/serve-with-hyper-rustls/src/main.rs @@ -0,0 +1,142 @@ +//! Run with +//! +//! ```not_rust +//! cargo run -p example-serve-with-hyper-rustls +//! ``` +//! +//! Test that the server runs with +//! ```bash +//! curl -kv https://localhost:3000 +//! ``` + +use std::convert::Infallible; +use std::error::Error as StdError; +use std::future::poll_fn; +use std::net::{Ipv4Addr, SocketAddr}; +use std::pin::pin; +use std::sync::Arc; +use std::{fs, io}; + +use axum::response::Response; +use axum::serve::{Connection, ConnectionBuilder, Hyper}; +use axum::{extract::Request, routing::get, Router}; +use http_body::Body as HttpBody; +use rustls::pki_types::{CertificateDer, PrivateKeyDer}; +use rustls::ServerConfig; +use tokio::io::{AsyncRead, AsyncWrite}; +use tokio::net::TcpListener; +use tokio_rustls::TlsAcceptor; +use tower::Service; + +#[derive(Clone)] +pub struct HyperRustls { + tls_acceptor: TlsAcceptor, + inner: Hyper, +} + +impl HyperRustls { + pub fn try_new() -> anyhow::Result { + // Load public certificate. + let certs = load_certs(&format!( + "{}/self_signed_certs/cert.pem", + env!("CARGO_MANIFEST_DIR") + ))?; + // Load private key. + let key = load_private_key(&format!( + "{}/self_signed_certs/key.pem", + env!("CARGO_MANIFEST_DIR") + ))?; + + // Build TLS configuration. + let mut server_config = ServerConfig::builder() + .with_no_client_auth() + .with_single_cert(certs, key) + .inspect_err(|e| tracing::error!(error = display(e), "Cannot load certificate.")) + .unwrap(); + server_config.alpn_protocols = + vec![b"h2".to_vec(), b"http/1.1".to_vec(), b"http/1.0".to_vec()]; + + Ok(Self { + tls_acceptor: TlsAcceptor::from(Arc::new(server_config)), + inner: Hyper::default(), + }) + } +} + +impl ConnectionBuilder for HyperRustls +where + Io: AsyncRead + AsyncWrite + Unpin + Send + 'static, + S: Service, Error = Infallible> + Clone + Send + 'static, + >::Future: Send, + B: HttpBody + Send + 'static, + B::Data: Send, + B::Error: Into>, +{ + fn build_connection(&mut self, io: Io, service: S) -> impl Connection { + let tls_acceptor = self.tls_acceptor.clone(); + let mut hyper = self.inner.clone(); + + Box::pin(async move { + let tls_stream = match tls_acceptor.accept(io).await { + Ok(tls_stream) => tls_stream, + Err(err) => { + eprintln!("failed to perform tls handshake: {err:#}"); + return Err(Box::new(err) as _); + } + }; + + let mut connection = pin!(hyper.build_connection(tls_stream, service)); + + poll_fn(|cx| connection.as_mut().poll_connection(cx)).await + }) + } + + fn graceful_shutdown(&mut self) { + ConnectionBuilder::::graceful_shutdown(&mut self.inner); + } +} + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + let addr = SocketAddr::new(Ipv4Addr::LOCALHOST.into(), 3000); + + println!("Starting to serve on https://{addr}"); + + // Create a regular axum app. + let app = Router::new().route("/", get(|| async { "Hello!" })); + + // Create a `TcpListener` using tokio. + let listener = TcpListener::bind(addr).await.unwrap(); + + // Create a connection builder which first drives the TLS handshake and then uses `hyper` to + // serve the connection. + let connection_builder = HyperRustls::try_new()?; + + axum::serve::serve_with_connection_builder(listener, connection_builder, app) + .await + .unwrap(); + + Ok(()) +} + +// Load public certificate from file. +fn load_certs(filename: &str) -> io::Result>> { + // Open certificate file. + let certfile = fs::File::open(filename) + .map_err(|e| io::Error::other(format!("failed to open {filename}: {e}")))?; + let mut reader = io::BufReader::new(certfile); + + // Load and return certificate. + rustls_pemfile::certs(&mut reader).collect() +} + +// Load private key from file. +fn load_private_key(filename: &str) -> io::Result> { + // Open keyfile. + let keyfile = fs::File::open(filename) + .map_err(|e| io::Error::other(format!("failed to open {filename}: {e}")))?; + let mut reader = io::BufReader::new(keyfile); + + // Load and return a single private key. + rustls_pemfile::private_key(&mut reader).map(|key| key.unwrap()) +} diff --git a/examples/serve-with-rama/Cargo.toml b/examples/serve-with-rama/Cargo.toml new file mode 100644 index 0000000000..e9fc890d99 --- /dev/null +++ b/examples/serve-with-rama/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "example-serve-with-rama" +version = "0.1.0" +edition = "2021" +publish = false + +[dependencies] +axum = { path = "../../axum" } +pin-project-lite = "0.2.7" +rama = { version = "0.3.0-alpha.2", features = ["http-full", "tower"], default-features = false } +tokio = { version = "1.0", features = ["full"] } +tower = { version = "0.5.2", features = ["util"] } diff --git a/examples/serve-with-rama/src/main.rs b/examples/serve-with-rama/src/main.rs new file mode 100644 index 0000000000..a5f99d8183 --- /dev/null +++ b/examples/serve-with-rama/src/main.rs @@ -0,0 +1,140 @@ +//! Run with +//! +//! ```not_rust +//! cargo run -p example-serve-with-rama +//! ``` +//! +//! This example shows how to run axum using rama as the HTTP driving server instead of the default +//! hyper. +use std::convert::Infallible; +use std::future::{ready, Future}; + +use axum::body::{Body as AxumBody, HttpBody}; +use axum::http::StatusCode; +use axum::response::Response; +use axum::serve::{Connection, ConnectionBuilder}; +use axum::{extract::Request, routing::get, Router}; +use pin_project_lite::pin_project; +use rama::graceful::ShutdownBuilder; +use rama::http::core::body::Frame; +use rama::http::core::server::conn::auto; +use rama::http::Body as RamaBody; +use rama::rt::Executor; +use rama::utils::tower::ServiceAdapter; +use rama::Context; +use tokio::sync::watch; +use tower::{Service, ServiceExt}; + +#[tokio::main] +async fn main() { + let app = Router::new().route("/", get(|| ready(StatusCode::IM_A_TEAPOT))); + + let listener = tokio::net::TcpListener::bind("127.0.0.1:3000") + .await + .unwrap(); + let connection_builder = RamaConnectionBuilder::new(); + println!("listening on {}", listener.local_addr().unwrap()); + axum::serve::serve_with_connection_builder(listener, connection_builder, app) + .await + .unwrap(); +} + +#[derive(Clone)] +pub struct RamaConnectionBuilder { + server: rama::http::server::HttpServer, + shutdown: Option>, +} + +pin_project! { + pub struct RamaConnection { + #[pin] + inner: F + } +} + +pin_project! { + pub struct SyncBody { + #[pin] + inner: B, + } +} + +// SAFETY +// This is fine because we never provide references to the inner body and the only publicly +// accessible method using it requires `Pin<&mut Self>` which means exclusive access. +unsafe impl Sync for SyncBody {} + +impl SyncBody { + pub fn new(body: B) -> Self { + Self { inner: body } + } +} + +impl HttpBody for SyncBody { + type Data = B::Data; + + type Error = B::Error; + + fn poll_frame( + self: std::pin::Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> std::task::Poll, Self::Error>>> { + self.project().inner.poll_frame(cx) + } + + // We must NOT delegate the provided methods to the inner body. We must NOT use references to + // the inner body as it may not be `Sync` and who knows what thread holds references to it. +} + +impl RamaConnectionBuilder { + fn new() -> Self { + let (shutdown_tx, shutdown_rx) = watch::channel(()); + let shutdown = ShutdownBuilder::new() + .with_signal(async move { shutdown_tx.closed().await }) + .build(); + Self { + server: rama::http::server::HttpServer::auto(Executor::graceful(shutdown.guard())), + shutdown: Some(shutdown_rx), + } + } +} + +impl ConnectionBuilder for RamaConnectionBuilder +where + Io: rama::net::stream::Stream, + S: Clone + Send + Sync + 'static, + S: Service + + Clone + + Send + + Sync + + 'static, +{ + fn build_connection(&mut self, io: Io, service: S) -> impl Connection { + let rama_service = ServiceAdapter::new( + service + .map_request(|request: Request| request.map(AxumBody::new)) + .map_response(|response: Response| { + response.map(SyncBody::new).map(RamaBody::new) + }), + ); + RamaConnection { + inner: self.server.serve(Context::default(), io, rama_service), + } + } + + fn graceful_shutdown(&mut self) { + self.shutdown.take(); + } +} + +impl Connection for RamaConnection +where + F: Future>> + Send, +{ + fn poll_connection( + self: std::pin::Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> std::task::Poll>> { + self.project().inner.poll(cx) + } +}