From 1717a4b5b536db1e473d159a4d2f1feece9b183e Mon Sep 17 00:00:00 2001 From: Kevin Stone Date: Thu, 14 Dec 2023 19:29:13 -0800 Subject: [PATCH] Migrate to hyper 1.0 --- Cargo.lock | 360 +++++++++++++++++++++++++++++-------- Cargo.toml | 11 +- hyper_body/Cargo.lock | 336 ++++++++++++++++++++++++++++++++++ hyper_body/Cargo.toml | 13 ++ hyper_body/src/lib.rs | 214 ++++++++++++++++++++++ src/http/mod.rs | 3 +- src/http/request.rs | 12 +- src/http/stream.rs | 6 +- src/main.rs | 123 ++++++++++--- src/router/mod.rs | 22 ++- src/router/routes.rs | 4 +- src/service/method/body.rs | 8 +- src/test/request.rs | 3 +- src/test/response.rs | 6 +- 14 files changed, 995 insertions(+), 126 deletions(-) create mode 100644 hyper_body/Cargo.lock create mode 100644 hyper_body/Cargo.toml create mode 100644 hyper_body/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 4b4d6c0..932ecb2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,21 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "aho-corasick" version = "0.7.18" @@ -45,7 +60,7 @@ checksum = "87bf87e6e8b47264efa9bde63d6225c6276a52e05e91bf37eaa8afd0032d6b71" dependencies = [ "askama_shared", "proc-macro2", - "syn", + "syn 1.0.99", ] [[package]] @@ -70,7 +85,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn", + "syn 1.0.99", "toml", ] @@ -82,7 +97,7 @@ checksum = "76464446b8bc32758d7e88ee1a804d9914cd9b1cb264c029899680b0be29826f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.99", ] [[package]] @@ -91,11 +106,26 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + [[package]] name = "base64" -version = "0.13.0" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" [[package]] name = "bitflags" @@ -103,6 +133,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" + [[package]] name = "block-buffer" version = "0.10.2" @@ -142,7 +178,7 @@ version = "4.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d63b9e9c07271b9957ad22c173bae2a4d9a81127680962039296abcd2f8251d" dependencies = [ - "bitflags", + "bitflags 1.3.2", "clap_derive", "clap_lex", "is-terminal", @@ -170,7 +206,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 1.0.99", ] [[package]] @@ -213,9 +249,9 @@ dependencies = [ [[package]] name = "digest" -version = "0.10.3" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", "crypto-common", @@ -227,6 +263,12 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "errno" version = "0.2.8" @@ -320,7 +362,7 @@ checksum = "0db9cce532b0eae2ccf2766ab246f114b56b9cf6d445e00c2549fbc100ca045d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.99", ] [[package]] @@ -380,11 +422,17 @@ dependencies = [ "wasi", ] +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + [[package]] name = "h2" -version = "0.3.14" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca32592cf21ac7ccab1825cd87f6c9b3d9022c44d086172ed0966bec8af30be" +checksum = "e1d308f63daf4181410c242d34c11f928dcb3aa105852019e043c9d1f4e4368a" dependencies = [ "bytes", "fnv", @@ -392,7 +440,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap", + "indexmap 2.1.0", "slab", "tokio", "tokio-util", @@ -405,6 +453,12 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + [[package]] name = "hdrhistogram" version = "7.5.1" @@ -417,25 +471,24 @@ dependencies = [ [[package]] name = "headers" -version = "0.3.7" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cff78e5788be1e0ab65b04d306b2ed5092c815ec97ec70f4ebd5aee158aa55d" +checksum = "322106e6bd0cba2d5ead589ddb8150a13d7c4217cf80d7c4f682ca994ccc6aa9" dependencies = [ "base64", - "bitflags", "bytes", "headers-core", "http", "httpdate", "mime", - "sha-1", + "sha1", ] [[package]] name = "headers-core" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" +checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" dependencies = [ "http", ] @@ -466,9 +519,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.8" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" +checksum = "b32afd38673a8016f7c9ae69e5af41a58f81b1d31689040f2f1959594ce194ea" dependencies = [ "bytes", "fnv", @@ -477,26 +530,32 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.5" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" dependencies = [ "bytes", "http", - "pin-project-lite", ] [[package]] -name = "http-range-header" -version = "0.3.0" +name = "http-body-util" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bfe8eed0a9285ef776bb792479ea3834e8b94e13d615c2f66d03dd50a435a29" +checksum = "41cb79eb393015dadd30fc252023adb0b2400a0caee0fa2a077e6e21a551e840" +dependencies = [ + "bytes", + "futures-util", + "http", + "http-body", + "pin-project-lite", +] [[package]] name = "httparse" -version = "1.7.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "496ce29bb5a52785b44e0f7ca2847ae0bb839c9bd28f69acac9b99d461c0c04c" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" [[package]] name = "httpbox" @@ -511,7 +570,10 @@ dependencies = [ "futures", "futures-timer", "headers", + "http-body-util", "hyper", + "hyper-util", + "hyper_body", "itertools", "lazy_static", "mime", @@ -543,13 +605,12 @@ checksum = "02296996cb8796d7c6e3bc2d9211b7802812d36999a51bb754123ead7d37d026" [[package]] name = "hyper" -version = "0.14.20" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02c929dc5c39e335a03c405292728118860721b10190d98c2a0f0efd5baafbac" +checksum = "403f9214f3e703236b221f1a9cd88ec8b4adfa5296de01ab96216361f4692f56" dependencies = [ "bytes", "futures-channel", - "futures-core", "futures-util", "h2", "http", @@ -558,11 +619,40 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2", "tokio", + "want", +] + +[[package]] +name = "hyper-util" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ca339002caeb0d159cc6e023dff48e199f081e42fa039895c7c6f38b37f2e9d" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "pin-project-lite", + "socket2 0.5.5", + "tokio", + "tower", "tower-service", "tracing", - "want", +] + +[[package]] +name = "hyper_body" +version = "0.1.0" +dependencies = [ + "futures", + "http-body", + "http-body-util", + "hyper", + "pin-project-lite", + "sync_wrapper", ] [[package]] @@ -583,7 +673,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.12.3", +] + +[[package]] +name = "indexmap" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +dependencies = [ + "equivalent", + "hashbrown 0.14.3", ] [[package]] @@ -631,9 +731,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.138" +version = "0.2.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8" +checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" [[package]] name = "linux-raw-sys" @@ -703,16 +803,24 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] + [[package]] name = "mio" -version = "0.8.4" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf" +checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" dependencies = [ "libc", - "log", "wasi", - "windows-sys 0.36.1", + "windows-sys 0.48.0", ] [[package]] @@ -753,6 +861,15 @@ dependencies = [ "libc", ] +[[package]] +name = "object" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" version = "1.13.1" @@ -811,7 +928,7 @@ checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.99", ] [[package]] @@ -841,7 +958,7 @@ dependencies = [ "proc-macro-error-attr", "proc-macro2", "quote", - "syn", + "syn 1.0.99", "version_check", ] @@ -858,18 +975,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.43" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" +checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.21" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] @@ -910,7 +1027,7 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -939,13 +1056,19 @@ version = "0.6.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + [[package]] name = "rustix" version = "0.36.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3807b5d10909833d3e9acd1eb5fb988f79376ff10fce42937de71a449c4c588" dependencies = [ - "bitflags", + "bitflags 1.3.2", "errno", "io-lifetimes", "libc", @@ -982,7 +1105,7 @@ checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.99", ] [[package]] @@ -998,10 +1121,10 @@ dependencies = [ ] [[package]] -name = "sha-1" -version = "0.10.0" +name = "sha1" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", "cpufeatures", @@ -1043,14 +1166,24 @@ checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" [[package]] name = "socket2" -version = "0.4.4" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" +checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" dependencies = [ "libc", "winapi", ] +[[package]] +name = "socket2" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + [[package]] name = "strsim" version = "0.10.0" @@ -1068,6 +1201,23 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "2.0.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c8b28c477cc3bf0e7966561e3460130e1255f7a1cf71931075f1c5e7a7e269" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + [[package]] name = "termcolor" version = "1.1.3" @@ -1121,34 +1271,33 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.20.1" +version = "1.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a8325f63a7d4774dd041e363b2409ed1c5cbbd0f867795e661df066b2b0a581" +checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" dependencies = [ "autocfg", + "backtrace", "bytes", "libc", - "memchr", "mio", "num_cpus", - "once_cell", "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2", + "socket2 0.4.9", "tokio-macros", - "winapi", + "windows-sys 0.48.0", ] [[package]] name = "tokio-macros" -version = "1.8.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" +checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.41", ] [[package]] @@ -1183,7 +1332,7 @@ dependencies = [ "futures-core", "futures-util", "hdrhistogram", - "indexmap", + "indexmap 1.9.1", "pin-project", "pin-project-lite", "rand", @@ -1197,17 +1346,16 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.2.5" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aba3f3efabf7fb41fae8534fc20a817013dd1c12cb45441efb6c82e6556b4cd8" +checksum = "09e12e6351354851911bdf8c2b8f2ab15050c567d70a8b9a37ae7b8301a4080d" dependencies = [ - "bitflags", + "bitflags 2.4.1", "bytes", - "futures-core", "futures-util", "http", "http-body", - "http-range-header", + "http-body-util", "pin-project-lite", "tower-layer", "tower-service", @@ -1247,7 +1395,7 @@ checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.99", ] [[package]] @@ -1429,21 +1577,51 @@ version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" dependencies = [ - "windows_aarch64_gnullvm", + "windows_aarch64_gnullvm 0.42.0", "windows_aarch64_msvc 0.42.0", "windows_i686_gnu 0.42.0", "windows_i686_msvc 0.42.0", "windows_x86_64_gnu 0.42.0", - "windows_x86_64_gnullvm", + "windows_x86_64_gnullvm 0.42.0", "windows_x86_64_msvc 0.42.0", ] +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + [[package]] name = "windows_aarch64_msvc" version = "0.36.1" @@ -1456,6 +1634,12 @@ version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + [[package]] name = "windows_i686_gnu" version = "0.36.1" @@ -1468,6 +1652,12 @@ version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + [[package]] name = "windows_i686_msvc" version = "0.36.1" @@ -1480,6 +1670,12 @@ version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + [[package]] name = "windows_x86_64_gnu" version = "0.36.1" @@ -1492,12 +1688,24 @@ version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + [[package]] name = "windows_x86_64_msvc" version = "0.36.1" @@ -1509,3 +1717,9 @@ name = "windows_x86_64_msvc" version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" diff --git a/Cargo.toml b/Cargo.toml index f3bf522..26ae1db 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,8 +15,10 @@ cookie = "^0.16.0" anyhow = "^1.0.27" futures = "^0.3.1" futures-timer = "^3.0" -headers = "^0.3.2" -hyper = { version = "0.14", features = ["full"] } +headers = "^0.4" +hyper = { version = "1.0", features = ["full"] } +hyper-util = { version = "0.1.1", features = ["tokio", "server", "server-auto"] } +http-body-util = "0.1.0" itertools = "^0.10.0" lazy_static = "^1.4.0" mime = "^0.3.13" @@ -26,12 +28,13 @@ serde = "^1.0.98" serde_derive = "^1.0.98" serde_urlencoded = "^0.7" url = "^2.2.1" -tokio = { version = "1.5.0", features = ["full"] } +tokio = { version = "1.25.0", features = ["full"] } tower = { version = "^0.4.12", features = ["full"] } -tower-http = { version = "^0.2.5", features=["trace"] } +tower-http = { version = "^0.5", features=["trace"] } tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter"] } uri_path = { path = "uri_path" } +hyper_body = { path = "hyper_body" } [[bin]] name = "httpbox" diff --git a/hyper_body/Cargo.lock b/hyper_body/Cargo.lock new file mode 100644 index 0000000..9635373 --- /dev/null +++ b/hyper_body/Cargo.lock @@ -0,0 +1,336 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "bytes" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" + +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "futures" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" + +[[package]] +name = "futures-executor" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" + +[[package]] +name = "futures-macro" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" + +[[package]] +name = "futures-task" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" + +[[package]] +name = "futures-util" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + +[[package]] +name = "http" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b32afd38673a8016f7c9ae69e5af41a58f81b1d31689040f2f1959594ce194ea" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41cb79eb393015dadd30fc252023adb0b2400a0caee0fa2a077e6e21a551e840" +dependencies = [ + "bytes", + "futures-util", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "hyper" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "403f9214f3e703236b221f1a9cd88ec8b4adfa5296de01ab96216361f4692f56" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "hyper_body" +version = "0.1.0" +dependencies = [ + "futures", + "http-body", + "http-body-util", + "hyper", + "pin-project-lite", + "sync_wrapper", +] + +[[package]] +name = "itoa" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" + +[[package]] +name = "libc" +version = "0.2.151" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" + +[[package]] +name = "memchr" +version = "2.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" + +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] + +[[package]] +name = "object" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +dependencies = [ + "memchr", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "proc-macro2" +version = "1.0.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "syn" +version = "2.0.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c8b28c477cc3bf0e7966561e3460130e1255f7a1cf71931075f1c5e7a7e269" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "tokio" +version = "1.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d45b238a16291a4e1584e61820b8ae57d696cc5015c459c229ccc6990cc1c" +dependencies = [ + "backtrace", + "pin-project-lite", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" diff --git a/hyper_body/Cargo.toml b/hyper_body/Cargo.toml new file mode 100644 index 0000000..8580db0 --- /dev/null +++ b/hyper_body/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "hyper_body" +version = "0.1.0" +authors = ["Kevin Stone "] +edition = "2021" + +[dependencies] +futures = "^0.3.1" +http-body = "1.0.0" +http-body-util = "0.1.0" +hyper = "1.0" +pin-project-lite = "0.2.7" +sync_wrapper = "0.1.1" diff --git a/hyper_body/src/lib.rs b/hyper_body/src/lib.rs new file mode 100644 index 0000000..ec6069c --- /dev/null +++ b/hyper_body/src/lib.rs @@ -0,0 +1,214 @@ +use futures::prelude::*; +use http_body::{Body as HttpBody, Frame, SizeHint}; +use http_body_util::BodyExt; +use hyper::body::{Bytes, Incoming}; +use pin_project_lite::pin_project; +use std::pin::Pin; +use std::task::{Context, Poll}; +use std::{error::Error as StdError, fmt}; +use sync_wrapper::SyncWrapper; + +type BoxBody = http_body_util::combinators::UnsyncBoxBody; +type BoxError = Box; + +/// Errors that can happen when using axum. +#[derive(Debug)] +pub struct Error { + inner: BoxError, +} + +impl Error { + /// Create a new `Error` from a boxable error. + pub fn new(error: impl Into) -> Self { + Self { + inner: error.into(), + } + } + + /// Convert an `Error` back into the underlying boxed trait object. + pub fn into_inner(self) -> BoxError { + self.inner + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.inner.fmt(f) + } +} + +impl StdError for Error { + fn source(&self) -> Option<&(dyn StdError + 'static)> { + Some(&*self.inner) + } +} + +fn boxed(body: B) -> BoxBody +where + B: HttpBody + Send + 'static, + B::Error: Into, +{ + try_downcast(body) + .unwrap_or_else(|body| body.map_err(Error::new).boxed_unsync()) +} + +pub(crate) fn try_downcast(k: K) -> Result +where + T: 'static, + K: Send + 'static, +{ + let mut k = Some(k); + if let Some(k) = ::downcast_mut::>(&mut k) { + Ok(k.take().unwrap()) + } else { + Err(k.unwrap()) + } +} + +#[derive(Debug)] +pub struct Body(BoxBody); + +impl Body { + /// Create a new `Body` that wraps another [`HttpBody`]. + pub fn new(body: B) -> Self + where + B: HttpBody + Send + 'static, + B::Error: Into, + { + try_downcast(body).unwrap_or_else(|body| Self(boxed(body))) + } + + /// Create an empty body. + pub fn empty() -> Self { + Self::new(http_body_util::Empty::new()) + } + + /// Create a new `Body` from a [`Stream`]. + /// + /// [`Stream`]: futures::stream::Stream + pub fn from_stream(stream: S) -> Self + where + S: TryStream + Send + 'static, + S::Ok: Into, + S::Error: Into, + { + Self::new(StreamBody { + stream: SyncWrapper::new(stream), + }) + } +} + +impl Default for Body { + fn default() -> Self { + Self::empty() + } +} + +impl From for Body { + fn from(incoming: Incoming) -> Self { + Self::new(incoming) + } +} + +macro_rules! body_from_impl { + ($ty:ty) => { + impl From<$ty> for Body { + fn from(buf: $ty) -> Self { + Self::new(http_body_util::Full::from(buf)) + } + } + }; +} + +body_from_impl!(&'static [u8]); +body_from_impl!(std::borrow::Cow<'static, [u8]>); +body_from_impl!(Vec); + +body_from_impl!(&'static str); +body_from_impl!(std::borrow::Cow<'static, str>); +body_from_impl!(String); + +body_from_impl!(Bytes); + +impl HttpBody for Body { + type Data = Bytes; + type Error = Error; + + #[inline] + fn poll_frame( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll, Self::Error>>> { + Pin::new(&mut self.0).poll_frame(cx) + } + + #[inline] + fn size_hint(&self) -> SizeHint { + self.0.size_hint() + } + + #[inline] + fn is_end_stream(&self) -> bool { + self.0.is_end_stream() + } +} + +impl Stream for Body { + type Item = Result; + + #[inline] + fn poll_next( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { + loop { + match futures::ready!(self.as_mut().poll_frame(cx)?) { + Some(frame) => match frame.into_data() { + Ok(data) => return Poll::Ready(Some(Ok(data))), + Err(_frame) => {} + }, + None => return Poll::Ready(None), + } + } + } +} + +pin_project! { + struct StreamBody { + #[pin] + stream: SyncWrapper, + } +} + +impl HttpBody for StreamBody +where + S: TryStream, + S::Ok: Into, + S::Error: Into, +{ + type Data = Bytes; + type Error = Error; + + fn poll_frame( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll, Self::Error>>> { + let stream = self.project().stream.get_pin_mut(); + match futures::ready!(stream.try_poll_next(cx)) { + Some(Ok(chunk)) => Poll::Ready(Some(Ok(Frame::data(chunk.into())))), + Some(Err(err)) => Poll::Ready(Some(Err(Error::new(err)))), + None => Poll::Ready(None), + } + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_try_downcast() { + assert_eq!(try_downcast::(5_u32), Err(5_u32)); + assert_eq!(try_downcast::(5_i32), Ok(5_i32)); + } +} diff --git a/src/http/mod.rs b/src/http/mod.rs index 9915c97..6815904 100644 --- a/src/http/mod.rs +++ b/src/http/mod.rs @@ -1,5 +1,5 @@ +pub use hyper::body::Bytes; pub use hyper::http::{StatusCode, Uri}; -pub use hyper::{body::Bytes, Body}; mod error; mod request; @@ -10,5 +10,6 @@ pub use self::error::Error; pub use self::request::*; pub use self::response::*; pub(crate) use self::stream::*; +pub use hyper_body::Body; pub type Result = std::result::Result; diff --git a/src/http/request.rs b/src/http/request.rs index 4b583e0..12fc536 100644 --- a/src/http/request.rs +++ b/src/http/request.rs @@ -1,6 +1,6 @@ +use super::Body; use crate::headers::{Header, HeaderMapExt}; use hyper::http::Request as HTTPRequest; -use hyper::Body; use std::net::SocketAddr; use uri_path::PathMatch; @@ -36,10 +36,6 @@ impl Request { de::deserialize(self.params.clone()).ok() } - pub fn body(&mut self) -> Body { - std::mem::replace(self.req.body_mut(), Body::empty()) - } - pub fn typed_header(&self) -> Option { self.req.headers().typed_get::() } @@ -63,3 +59,9 @@ impl core::ops::Deref for Request { &self.req } } + +impl core::ops::DerefMut for Request { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.req + } +} diff --git a/src/http/stream.rs b/src/http/stream.rs index 9145503..8dce587 100644 --- a/src/http/stream.rs +++ b/src/http/stream.rs @@ -1,6 +1,6 @@ +use crate::http::Body; use futures::prelude::*; use hyper::body::Bytes; -use hyper::Body; use std::convert::Infallible; pub(crate) fn ok_stream>( @@ -13,7 +13,7 @@ pub(crate) fn body_from_stream( stream: S, ) -> Body where - Bytes: From<::Item>, + S::Item: Into, { - Body::wrap_stream(ok_stream(stream).into_stream()) + Body::from_stream(ok_stream(stream)) } diff --git a/src/main.rs b/src/main.rs index dde5a91..aecc1f9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,13 +1,14 @@ use clap::{Command, CommandFactory, Parser}; use clap_complete::{generate, Generator, Shell}; -use futures::prelude::*; -use hyper::server::conn::AddrStream; -use hyper::Server; -use hyper::{Body, Request as HTTPRequest}; +use hyper::server::conn::http1; +use hyper::Request as HTTPRequest; +use hyper_util::rt::TokioIo; use std::io; use std::net::ToSocketAddrs; use std::num::NonZeroUsize; -use tokio::runtime; +use tokio::net::TcpListener; +use tokio::{runtime, signal, sync::watch}; +use tower::Service; use tower::ServiceBuilder; use tower::ServiceExt; use tower_http::trace::TraceLayer; @@ -61,7 +62,27 @@ fn print_completions(gen: G, app: &mut Command) { async fn shutdown_signal() { // Wait for the CTRL+C signal - tokio::signal::ctrl_c().await.unwrap() + let ctrl_c = async { + signal::ctrl_c() + .await + .expect("failed to install Ctrl+C handler"); + }; + + #[cfg(unix)] + let terminate = async { + signal::unix::signal(signal::unix::SignalKind::terminate()) + .expect("failed to install signal handler") + .recv() + .await; + }; + + #[cfg(not(unix))] + let terminate = std::future::pending::<()>(); + + tokio::select! { + _ = ctrl_c => {}, + _ = terminate => {}, + } } fn main() -> Result<(), Box> { @@ -105,23 +126,77 @@ fn main() -> Result<(), Box> { .layer(TraceLayer::new_for_http()) .service(service::router()); - let factory = tower::service_fn(|conn: &AddrStream| { - let addr = conn.remote_addr(); - future::ok::<_, std::convert::Infallible>( - service.clone().map_request( - move |mut req: HTTPRequest| { - req.extensions_mut().insert(addr); - req + let listener = TcpListener::bind(addr).await.unwrap(); + let (close_tx, close_rx) = watch::channel(()); + + loop { + let (stream, addr) = tokio::select! { + result = listener.accept() => { + result.unwrap() + }, + _ = shutdown_signal() => { + tracing::debug!("signal received, not accepting new connections"); + break; + } + }; + + let stream = TokioIo::new(stream); + + // Inject the client addr into the request + let tower_service = service.clone().map_request( + move |mut req: HTTPRequest<_>| { + req.extensions_mut().insert(addr); + req + }, + ); + + let close_rx = close_rx.clone(); + + runtime.spawn(async move { + let hyper_service = hyper::service::service_fn( + move |request: hyper::Request<_>| { + tower_service.clone().call(request) }, - ), - ) - }); - - let server = Server::bind(&addr) - .serve(factory) - .with_graceful_shutdown(shutdown_signal()); - - server.await?; - Ok(()) - }) + ); + + let conn = http1::Builder::new() + .serve_connection(stream, hyper_service).with_upgrades(); + + let mut conn = std::pin::pin!(conn); + + loop { + tokio::select! { + // Poll the connection. This completes when the client has closed the + // connection, graceful shutdown has completed, or we encounter a TCP error. + result = conn.as_mut() => { + if let Err(err) = result { + tracing::error!("Error serving connection: {err:#}"); + } + break; + } + // Start graceful shutdown when we receive a shutdown signal. + // + // We use a loop to continue polling the connection to allow requests to finish + _ = shutdown_signal() => { + tracing::debug!("signal received, starting graceful shutdown"); + conn.as_mut().graceful_shutdown(); + } + } + } + + // Drop the watch receiver to signal to `main` that this task is done. + drop(close_rx); + }); + } + + drop(close_rx); + + // Close the listener to stop accepting new connections. + drop(listener); + + // Wait for all tasks to complete. + tracing::debug!("waiting for {} tasks to finish", close_tx.receiver_count()); + close_tx.closed().await; + }); + Ok(()) } diff --git a/src/router/mod.rs b/src/router/mod.rs index 48e4ac9..eb41d90 100644 --- a/src/router/mod.rs +++ b/src/router/mod.rs @@ -1,10 +1,13 @@ use crate::handler::Handler; -use crate::http::{internal_server_error, not_found, Error, Request, Response}; +use crate::http::{ + internal_server_error, not_found, Body, Error, Request, Response, +}; use futures::prelude::*; -use hyper::{service::Service, Body, Request as HTTPRequest}; +use hyper::Request as HTTPRequest; use std::pin::Pin; use std::sync::Arc; use std::task::{Context, Poll}; +use tower::Service; use uri_path::PathMatch; mod routes; @@ -67,9 +70,9 @@ pub struct RouterInternal { } impl RouterInternal { - pub fn route( + pub fn route( &self, - req: &HTTPRequest, + req: &HTTPRequest, ) -> Option<(&Endpoint, PathMatch)> { self.endpoints.iter().find_map(|endpoint| { endpoint.route.matches(req).map(|params| (endpoint, params)) @@ -90,7 +93,9 @@ impl Router { } } -impl Service> for Router { +impl + std::marker::Send + 'static> Service> + for Router +{ type Response = Response; type Error = hyper::http::Error; #[allow(clippy::type_complexity)] @@ -105,14 +110,14 @@ impl Service> for Router { Poll::Ready(Ok(())) } - fn call(&mut self, req: HTTPRequest) -> Self::Future { + fn call(&mut self, req: HTTPRequest) -> Self::Future { let router = self.0.clone(); async move { let (endpoint, matched_path) = router.route(&req).ok_or_else(not_found)?; - let client_req = Request::new(req, matched_path); + let client_req = Request::new(req.map(|b| b.into()), matched_path); handle_panics(endpoint.handler.handle(client_req)).await } .or_else(|e: Error| e.into_result()) @@ -139,7 +144,8 @@ mod test { let router = Router::builder().install(handler, route(path!())).build(); let mut service = router; - let res = service.call(HTTPRequest::default()).await.unwrap(); + let body = Body::empty(); + let res = service.call(HTTPRequest::new(body)).await.unwrap(); assert_eq!(res.status(), StatusCode::INTERNAL_SERVER_ERROR); } } diff --git a/src/router/routes.rs b/src/router/routes.rs index 0e5d7dd..8b3640c 100644 --- a/src/router/routes.rs +++ b/src/router/routes.rs @@ -1,4 +1,4 @@ -use hyper::{Body, Method, Request as HTTPRequest}; +use hyper::{Method, Request as HTTPRequest}; use std::collections::BTreeMap; use uri_path::{Path, PathMatch}; @@ -73,7 +73,7 @@ impl Route { self.example_path.as_ref().map(String::as_ref) } - pub fn matches(&self, req: &HTTPRequest) -> Option { + pub fn matches(&self, req: &HTTPRequest) -> Option { if self.method() != req.method() { return None; } diff --git a/src/service/method/body.rs b/src/service/method/body.rs index f93bc7f..f2b20ac 100644 --- a/src/service/method/body.rs +++ b/src/service/method/body.rs @@ -1,5 +1,6 @@ use crate::headers::ContentType; use crate::http::{bad_request, ok, Bytes, Request, Result}; +use http_body_util::BodyExt; use itertools::Itertools; use std::str; @@ -42,9 +43,12 @@ fn parse_body(req: &Request, chunk: &Bytes) -> anyhow::Result { } pub async fn body(mut req: Request) -> Result { - let body = hyper::body::to_bytes(req.body()) + let body = req + .body_mut() + .collect() .await - .map_err(|_| bad_request())?; + .map_err(|_| bad_request())? + .to_bytes(); let content = parse_body(&req, &body).map_err(|_| bad_request())?; ok(content) } diff --git a/src/test/request.rs b/src/test/request.rs index e1d998e..e27dae6 100644 --- a/src/test/request.rs +++ b/src/test/request.rs @@ -3,11 +3,10 @@ use crate::handler::Handler; use crate::headers::ContentLength; use crate::headers::{Header, HeaderMapExt}; -use crate::http::Request; +use crate::http::{Body, Request}; use futures::prelude::*; use hyper::header::{HeaderName, HeaderValue}; use hyper::http::{Request as HTTPRequest, Response as HTTPResponse}; -use hyper::Body; use hyper::Method; use std::convert::TryFrom; use std::net::SocketAddr; diff --git a/src/test/response.rs b/src/test/response.rs index 64f9e62..53b05e8 100644 --- a/src/test/response.rs +++ b/src/test/response.rs @@ -1,4 +1,6 @@ +use crate::http::Body; use async_trait::async_trait; +use http_body_util::BodyExt; #[async_trait] pub trait TestResponseExt: Sized { @@ -9,9 +11,9 @@ pub trait TestResponseExt: Sized { } #[async_trait] -impl TestResponseExt for hyper::Response { +impl TestResponseExt for hyper::Response { async fn read_body(self) -> anyhow::Result> { - let bytes = hyper::body::to_bytes(self.into_body()).await?; + let bytes = BodyExt::collect(self.into_body()).await?.to_bytes(); Ok(bytes.to_vec()) } }