diff --git a/.gitignore b/.gitignore index 81fce4ad..16b13b83 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ .vscode .idea -/target +/target \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 11ff5c03..7dea3828 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -179,9 +179,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.4" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" [[package]] name = "bit-set" @@ -260,9 +260,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.6" +version = "4.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d04704f56c2cde07f43e8e2c154b43f216dc5c92fc98ada720177362f953b956" +checksum = "ac495e00dcec98c83465d5ad66c5c4fabd652fd6686e7c6269b117e729a6f17b" dependencies = [ "clap_builder", "clap_derive", @@ -270,9 +270,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.6" +version = "4.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e231faeaca65ebd1ea3c737966bf858971cd38c3849107aa3ea7de90a804e45" +checksum = "c77ed9a32a62e6ca27175d00d29d05ca32e396ea1eb5fb01d8256b669cec7663" dependencies = [ "anstream", "anstyle", @@ -283,9 +283,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.4.2" +version = "4.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873" +checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" dependencies = [ "heck 0.4.1", "proc-macro2", @@ -295,9 +295,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.5.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" +checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" [[package]] name = "colorchoice" @@ -517,7 +517,10 @@ dependencies = [ "lazy_static", "metainfo", "pilota", + "rustls", + "rustls-pemfile", "tokio", + "tokio-rustls", "tokio-stream", "tracing", "tracing-subscriber", @@ -565,6 +568,21 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "form_urlencoded" version = "1.2.0" @@ -1091,9 +1109,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0" dependencies = [ "libc", "wasi", @@ -1130,6 +1148,24 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97af489e1e21b68de4c390ecca6703318bc1aa16e9733bcb62c089b73c6fbb1b" +[[package]] +name = "native-tls" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + [[package]] name = "nix" version = "0.27.1" @@ -1233,6 +1269,50 @@ version = "11.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" +[[package]] +name = "openssl" +version = "0.10.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c" +dependencies = [ + "bitflags 2.4.1", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db4d56a4c0478783083cfafcc42493dd4a981d41669da64b4572a2a089b51b1d" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "option-ext" version = "0.2.0" @@ -1465,6 +1545,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkg-config" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -1724,7 +1810,7 @@ version = "0.11.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" dependencies = [ - "base64 0.21.4", + "base64 0.21.5", "bytes", "encoding_rs", "futures-core", @@ -1760,17 +1846,16 @@ dependencies = [ [[package]] name = "ring" -version = "0.16.20" +version = "0.17.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +checksum = "fb0205304757e5d899b9c2e448b867ffd03ae7f988002e47cd24954391394d0b" dependencies = [ "cc", + "getrandom", "libc", - "once_cell", "spin", "untrusted", - "web-sys", - "winapi", + "windows-sys", ] [[package]] @@ -1809,9 +1894,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.7" +version = "0.21.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd8d6c9f025a446bc4d18ad9632e69aec8f287aa84499ee335599fabd20c3fd8" +checksum = "446e14c5cda4f3f30fe71863c34ec70f5ac79d6087097ad0bb433e1be5edf04c" dependencies = [ "log", "ring", @@ -1825,14 +1910,14 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" dependencies = [ - "base64 0.21.4", + "base64 0.21.5", ] [[package]] name = "rustls-webpki" -version = "0.101.6" +version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c7d5dece342910d9ba34d259310cae3e0154b873b35408b787b59bce53d34fe" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ "ring", "untrusted", @@ -1894,6 +1979,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "schannel" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" +dependencies = [ + "windows-sys", +] + [[package]] name = "scoped-tls" version = "1.0.1" @@ -1908,14 +2002,37 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "sct" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ "ring", "untrusted", ] +[[package]] +name = "security-framework" +version = "2.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "semver" version = "1.0.20" @@ -1924,18 +2041,18 @@ checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" [[package]] name = "serde" -version = "1.0.189" +version = "1.0.190" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537" +checksum = "91d3c334ca1ee894a2c6f6ad698fe8c435b76d504b13d436f0685d648d6d96f7" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.189" +version = "1.0.190" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5" +checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3" dependencies = [ "proc-macro2", "quote", @@ -1955,9 +2072,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" +checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80" dependencies = [ "serde", ] @@ -1976,9 +2093,9 @@ dependencies = [ [[package]] name = "serde_yaml" -version = "0.9.25" +version = "0.9.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a49e178e4452f45cb61d0cd8cebc1b0fafd3e41929e996cef79aa3aca91f574" +checksum = "e94bf752b3784a50c603c3ec452c6be3bfe01312ce0a60c87a6ed25d68da2cb6" dependencies = [ "indexmap 2.0.2", "itoa", @@ -2048,9 +2165,9 @@ dependencies = [ [[package]] name = "spin" -version = "0.5.2" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" [[package]] name = "strsim" @@ -2218,6 +2335,16 @@ dependencies = [ "syn 2.0.38", ] +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + [[package]] name = "tokio-rustls" version = "0.24.1" @@ -2241,9 +2368,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d68074620f57a0b21594d9735eb2e98ab38b17f80d3fcb189fca266771ca60d" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" dependencies = [ "bytes", "futures-core", @@ -2256,21 +2383,21 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.2" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d" +checksum = "2ef75d881185fd2df4a040793927c153d863651108a93c7e17a9e591baa95cc6" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.20.2", + "toml_edit 0.20.4", ] [[package]] name = "toml_datetime" -version = "0.6.3" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" dependencies = [ "serde", ] @@ -2288,9 +2415,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.20.2" +version = "0.20.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" +checksum = "380f9e8120405471f7c9ad1860a713ef5ece6a670c7eae39225e477340f32fc4" dependencies = [ "indexmap 2.0.2", "serde", @@ -2366,12 +2493,12 @@ dependencies = [ [[package]] name = "tracing-log" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +checksum = "f751112709b4e791d8ce53e32c4ed2d353565a795ce84da2285393f41557bdf2" dependencies = [ - "lazy_static", "log", + "once_cell", "tracing-core", ] @@ -2440,9 +2567,9 @@ checksum = "f28467d3e1d3c6586d8f25fa243f544f5800fec42d97032474e17222c2b75cfa" [[package]] name = "untrusted" -version = "0.7.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "update-informer" @@ -2464,7 +2591,7 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f5ccd538d4a604753ebc2f17cd9946e89b77bf87f6a8e2309667c6f2e87855e3" dependencies = [ - "base64 0.21.4", + "base64 0.21.5", "flate2", "log", "once_cell", @@ -2505,6 +2632,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "volo" version = "0.8.0" @@ -2522,9 +2655,12 @@ dependencies = [ "once_cell", "pin-project", "rand", + "rustls", "socket2 0.5.5", "thiserror", "tokio", + "tokio-native-tls", + "tokio-rustls", "tokio-stream", "tower", "tracing", @@ -2618,6 +2754,8 @@ dependencies = [ "pilota", "pin-project", "tokio", + "tokio-native-tls", + "tokio-rustls", "tokio-stream", "tokio-util", "tower", diff --git a/Cargo.toml b/Cargo.toml index e29ebfe9..061b25fc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,7 @@ pilota-thrift-parser = "0.9" #pilota-thrift-parser = { git = "https://github.com/cloudwego/pilota", branch = "main" } motore = "0.4" -#motore = { git = "https://github.com/cloudwego/motore", branch = "main" } +# motore = { git = "https://github.com/cloudwego/motore", branch = "main" } metainfo = "0.7" @@ -100,6 +100,12 @@ update-informer = "1" url_path = "0.1" walkdir = "2" +# Optional dependencies +librustls = { package = "rustls", version = "0.21" } +rustls-pemfile = "1" +tokio-rustls = "0.24" +tokio-native-tls = "0.3" + [profile.release] opt-level = 3 debug = false diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 33097d14..6195c2fd 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -22,6 +22,16 @@ path = "src/hello/thrift_server.rs" name = "hello-thrift-client" path = "src/hello/thrift_client.rs" +# hello tls +[[bin]] +name = "hello-tls-grpc-server" +path = "src/hello_grpc_tls/grpc_tls_server.rs" +required-features = ["tls"] +[[bin]] +name = "hello-tls-grpc-client" +path = "src/hello_grpc_tls/grpc_tls_client.rs" +required-features = ["tls"] + # compression [[bin]] name = "compresion-grpc-server" @@ -79,3 +89,11 @@ volo-grpc = { path = "../volo-grpc" } volo-thrift = { path = "../volo-thrift" } volo-gen = { path = "./volo-gen" } + +# TLS dependencies +librustls = { workspace = true, optional = true} +rustls-pemfile = { workspace = true, optional = true } +tokio-rustls = { workspace = true, optional = true } + +[features] +tls = ["librustls", "rustls-pemfile", "tokio-rustls", "volo/rustls", "volo-grpc/rustls"] \ No newline at end of file diff --git a/examples/data/tls/ca.pem b/examples/data/tls/ca.pem new file mode 100644 index 00000000..d8195609 --- /dev/null +++ b/examples/data/tls/ca.pem @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIE3DCCA0SgAwIBAgIRAObeYbJFiVQSGR8yk44dsOYwDQYJKoZIhvcNAQELBQAw +gYUxHjAcBgNVBAoTFW1rY2VydCBkZXZlbG9wbWVudCBDQTEtMCsGA1UECwwkbHVj +aW9ATHVjaW9zLVdvcmstTUJQIChMdWNpbyBGcmFuY28pMTQwMgYDVQQDDCtta2Nl +cnQgbHVjaW9ATHVjaW9zLVdvcmstTUJQIChMdWNpbyBGcmFuY28pMB4XDTE5MDky +OTIzMzUzM1oXDTI5MDkyOTIzMzUzM1owgYUxHjAcBgNVBAoTFW1rY2VydCBkZXZl +bG9wbWVudCBDQTEtMCsGA1UECwwkbHVjaW9ATHVjaW9zLVdvcmstTUJQIChMdWNp +byBGcmFuY28pMTQwMgYDVQQDDCtta2NlcnQgbHVjaW9ATHVjaW9zLVdvcmstTUJQ +IChMdWNpbyBGcmFuY28pMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA +y/vE61ItbN/1qMYt13LMf+le1svwfkCCOPsygk7nWeRXmomgUpymqn1LnWiuB0+e +4IdVH2f5E9DknWEpPhKIDMRTCbz4jTwQfHrxCb8EGj3I8oO73pJO5S/xCedM9OrZ +qWcYWwN0GQ8cO/ogazaoZf1uTrRNHyzRyQsKyb412kDBTNEeldJZ2ljKgXXvh4HO +2ZIk9K/ZAaAf6VN8K/89rlJ9/KPgRVNsyAapE+Pb8XXKtpzeFiEcUfuXVYWtkoW+ +xyn/Zu8A1L2CXMQ1sARh7P/42BTMKr5pfraYgcBGxKXLrxoySpxCO9KqeVveKy1q +fPm5FCwFsXDr0koFLrCiR58mcIO/04Q9DKKTV4Z2a+LoqDJRY37KfBSc8sDMPhw5 +k7g3WPoa6QwXRjZTCA5fHWVgLOtcwLsnju5tBE4LDxwF6s+1wPF8NI5yUfufcEjJ +Z6JBwgoWYosVj27Lx7KBNLU/57PX9ryee691zmtswt0tP0WVBAgalhYWg99RXoa3 +AgMBAAGjRTBDMA4GA1UdDwEB/wQEAwICBDASBgNVHRMBAf8ECDAGAQH/AgEAMB0G +A1UdDgQWBBQdvlE4Bdcsjc9oaxjDCRu5FiuZkzANBgkqhkiG9w0BAQsFAAOCAYEA +BP/6o1kPINksMJZSSXgNCPZskDLyGw7auUZBnQ0ocDT3W6gXQvT/27LM1Hxoj9Eh +qU1TYdEt7ppecLQSGvzQ02MExG7H75art75oLiB+A5agDira937YbK4MCjqW481d +bDhw6ixJnY1jIvwjEZxyH6g94YyL927aSPch51fys0kSnjkFzC2RmuzDADScc4XH +5P1+/3dnIm3M5yfpeUzoaOrTXNmhn8p0RDIGrZ5kA5eISIGGD3Mm8FDssUNKndtO +g4ojHUsxb14icnAYGeye1NOhGiqN6TEFcgr6MPd0XdFNZ5c0HUaBCfN6bc+JxDV5 +MKZVJdNeJsYYwilgJNHAyZgCi30JC20xeYVtTF7CEEsMrFDGJ70Kz7o/FnRiFsA1 +ZSwVVWhhkHG2VkT4vlo0O3fYeZpenYicvy+wZNTbGK83gzHWqxxNC1z3Etg5+HRJ +F9qeMWPyfA3IHYXygiMcviyLcyNGG/SJ0EhUpYBN/Gg7wI5yFkcsxUDPPzd23O0M +-----END CERTIFICATE----- diff --git a/examples/data/tls/server.key b/examples/data/tls/server.key new file mode 100644 index 00000000..80984ef9 --- /dev/null +++ b/examples/data/tls/server.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDyptbMyYWztgta +t1MXLMzIkaQdeeVbs1Y/qCpAdwZe/Y5ZpbzjGIjCxbB6vNRSnEbYKpytKHPzYfM7 +8d8K8bPvpnqXIiTXFT0JQlw1OHLC1fr4e598GJumAmpMYFrtqv0fbmUFTuQGbHxe +OH2vji0bvr3NKZubMfkEZP3X4sNXXoXIuW2LaS8OMGKoJaeCBvdbszEiSGj/v9Bj +pM0yLTH89NNMX1T+FtTKnuXag5g7pr6lzJj83+MzAGy4nOjseSuUimuiyG90/C5t +A5wC0Qh5RbDnkFYhC44Kxof/i6+jnfateIPNiIIwQV+2f6G/aK1hgjekT10m/eoR +YDTf+e5ZAgMBAAECggEACODt7yRYjhDVLYaTtb9f5t7dYG67Y7WWLFIc6arxQryI +XuNfm/ej2WyeXn9WTYeGWBaHERbv1zH4UnMxNBdP/C7dQXZwXqZaS2JwOUpNeK+X +tUvgtAu6dkKUXSMRcKzXAjVp4N3YHhwOGOx8PNY49FDwZPdmyDD16aFAYIvdle6/ +PSMrj38rB1sbQQdmRob2FjJBSDZ44nsr+/nilrcOFNfNnWv7tQIWYVXNcLfdK/WJ +ZCDFhA8lr/Yon6MEq6ApTj2ZYRRGXPd6UeASJkmTZEUIUbeDcje/MO8cHkREpuRH +wm3pCjR7OdO4vc+/d/QmEvu5ns6wbTauelYnL616YQKBgQD414gJtpCHauNEUlFB +v/R3DzPI5NGp9PAqovOD8nCbI49Mw61gP/ExTIPKiR5uUX/5EL04uspaNkuohXk+ +ys0G5At0NfV7W39lzhvALEaSfleybvYxppbBrc20/q8Gvi/i30NY+1LM3RdtMiEw +hKHjU0SnFhJq0InFg3AO/iCeTQKBgQD5obkbzpOidSsa55aNsUlO2qjiUY9leq9b +irAohIZ8YnuuixYvkOeSeSz1eIrA4tECeAFSgTZxYe1Iz+USru2Xg/0xNte11dJD +rBoH/yMn2gDvBK7xQ6uFMPTeYtKG0vfvpXZYSWZzGntyrHTwFk6UV+xdrt9MBdd1 +XdSn7bwOPQKBgC9VQAko8uDvUf+C8PXiv2uONrl13PPJJY3WpR9qFEVOREnDxszS +HNzVwxPZdTJiykbkCjoqPadfQJDzopZxGQLAifU29lTamKcSx3CMe3gOFDxaovXa +zD5XAxP0hfJwZsdu1G6uj5dsTrJ0oJ+L+wc0pZBqwGIU/L/XOo9/g1DZAoGAUebL +kuH98ik7EUK2VJq8EJERI9/ailLsQb6I+WIxtZGiPqwHhWencpkrNQZtj8dbB9JT +rLwUHrMgZOlAoRafgTyez4zMzS3wJJ/Mkp8U67hM4h7JPwMSvUpIrMYDiJSjIA9L +er/qSw1/Pypx22uWMHmAZWRAgvLPtAQrB0Wqk4kCgYEAr2H1PvfbwZwkSvlMt5o8 +WLnBbxcM3AKglLRbkShxxgiZYdEP71/uOtRMiL26du5XX8evItITN0DsvmXL/kcd +h29LK7LM5uLw7efz0Qxs03G6kEyIHVkacowHi5I5Ul1qI61SoV3yMB1TjIU+bXZt +0ZjC07totO0fqPOLQxonjQg= +-----END PRIVATE KEY----- diff --git a/examples/data/tls/server.pem b/examples/data/tls/server.pem new file mode 100644 index 00000000..4cc97bcf --- /dev/null +++ b/examples/data/tls/server.pem @@ -0,0 +1,27 @@ +-----BEGIN CERTIFICATE----- +MIIEmDCCAwCgAwIBAgIQVEJFCgU/CZk9JEwTucWPpzANBgkqhkiG9w0BAQsFADCB +hTEeMBwGA1UEChMVbWtjZXJ0IGRldmVsb3BtZW50IENBMS0wKwYDVQQLDCRsdWNp +b0BMdWNpb3MtV29yay1NQlAgKEx1Y2lvIEZyYW5jbykxNDAyBgNVBAMMK21rY2Vy +dCBsdWNpb0BMdWNpb3MtV29yay1NQlAgKEx1Y2lvIEZyYW5jbykwHhcNMTkwNjAx +MDAwMDAwWhcNMjkwOTI5MjMzNTM0WjBYMScwJQYDVQQKEx5ta2NlcnQgZGV2ZWxv +cG1lbnQgY2VydGlmaWNhdGUxLTArBgNVBAsMJGx1Y2lvQEx1Y2lvcy1Xb3JrLU1C +UCAoTHVjaW8gRnJhbmNvKTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +APKm1szJhbO2C1q3UxcszMiRpB155VuzVj+oKkB3Bl79jlmlvOMYiMLFsHq81FKc +RtgqnK0oc/Nh8zvx3wrxs++mepciJNcVPQlCXDU4csLV+vh7n3wYm6YCakxgWu2q +/R9uZQVO5AZsfF44fa+OLRu+vc0pm5sx+QRk/dfiw1dehci5bYtpLw4wYqglp4IG +91uzMSJIaP+/0GOkzTItMfz000xfVP4W1Mqe5dqDmDumvqXMmPzf4zMAbLic6Ox5 +K5SKa6LIb3T8Lm0DnALRCHlFsOeQViELjgrGh/+Lr6Od9q14g82IgjBBX7Z/ob9o +rWGCN6RPXSb96hFgNN/57lkCAwEAAaOBrzCBrDAOBgNVHQ8BAf8EBAMCBaAwEwYD +VR0lBAwwCgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADAfBgNVHSMEGDAWgBQdvlE4 +Bdcsjc9oaxjDCRu5FiuZkzBWBgNVHREETzBNggtleGFtcGxlLmNvbYINKi5leGFt +cGxlLmNvbYIMZXhhbXBsZS50ZXN0gglsb2NhbGhvc3SHBH8AAAGHEAAAAAAAAAAA +AAAAAAAAAAEwDQYJKoZIhvcNAQELBQADggGBAKb2TJ8l+e1eraNwZWizLw5fccAf +y59J1JAWdLxZyAI/bkiTlVO3DQoPZpw7XwLhefCvILkwKAL4TtIGGVC9yTb5Q5eg +rqGO3FC0yg1fn65Kf1VpVxxUVyoiM5PQ4pFJb4AicAv88rCOLD9FFuE0PKOKU/dm +Tw0WgPStoh9wsJ1RXUuTJYZs1nd1kMBlfv9NbLilnL+cR2sLktS54X5XagsBYVlf +oapRb0JtABOoQhX3U8QMq8UF8yzceRHNTN9yfLOUrW26s9nKtlWVniNhw1uPxZw9 +RHM7w9/4+a9LXtEDYg4IP/1mm0ywBoUqy1O6hA73uId+Yi/kFBks/GyYaGjKgYcO +23B75tkPGYEdGuGZYLzZNHbXg4V0UxFQG3KA1pUiSnD3bN2Rxs+CMpzORnOeK3xi +EooKgAPYsehItoQOMPpccI2xHdSAMWtwUgOKrefUQujkx2Op+KFlspF0+WJ6AZEe +2D4hyWaEZsvvILXapwqHDCuN3/jSUlTIqUoE1w== +-----END CERTIFICATE----- diff --git a/examples/src/hello_grpc_tls/grpc_tls_client.rs b/examples/src/hello_grpc_tls/grpc_tls_client.rs new file mode 100644 index 00000000..f97d9ecb --- /dev/null +++ b/examples/src/hello_grpc_tls/grpc_tls_client.rs @@ -0,0 +1,50 @@ +//! Run with `cargo run --example hello-tls-grpc-client --features tls` + +use std::{net::SocketAddr, path::Path, sync::Arc}; + +use librustls::{Certificate, ClientConfig, RootCertStore}; /* crate `rustls` is renamed to `librustls` in this example */ +use pilota::FastStr; +use rustls_pemfile::certs; +use volo::net::dial::ClientTlsConfig; + +fn load_certs(path: impl AsRef) -> std::io::Result> { + certs(&mut std::io::BufReader::new(std::fs::File::open(path)?)) + .map(|v| v.into_iter().map(Certificate).collect()) + .map_err(|_| std::io::Error::new(std::io::ErrorKind::InvalidInput, "invalid cert").into()) +} + +#[volo::main] +async fn main() { + // The key and certificate are copied from + // https://github.com/hyperium/tonic/tree/master/examples/data/tls + let data_dir = std::path::PathBuf::from_iter([std::env!("CARGO_MANIFEST_DIR"), "data"]); + let root_cert = load_certs(data_dir.join("tls/ca.pem")).unwrap(); + let mut root_certs = RootCertStore::empty(); + root_certs.add(&root_cert[0]).unwrap(); + + let client_config = ClientConfig::builder() + .with_safe_default_cipher_suites() + .with_safe_default_kx_groups() + .with_safe_default_protocol_versions() + .unwrap() + .with_root_certificates(root_certs) + .with_no_client_auth(); + let client_config = Arc::new(client_config); + let connector = tokio_rustls::TlsConnector::from(client_config); + let tls_config = ClientTlsConfig::new("example.com", connector); + + let addr: SocketAddr = "127.0.0.1:8080".parse().unwrap(); + let client = volo_gen::proto_gen::hello::GreeterClientBuilder::new("hello") + .tls_config(tls_config) + .address(addr) + .build(); + + let req = volo_gen::proto_gen::hello::HelloRequest { + name: FastStr::from_static_str("Volo"), + }; + let resp = client.say_hello(req).await; + match resp { + Ok(info) => println!("{info:?}"), + Err(e) => eprintln!("{e:?}"), + } +} diff --git a/examples/src/hello_grpc_tls/grpc_tls_server.rs b/examples/src/hello_grpc_tls/grpc_tls_server.rs new file mode 100644 index 00000000..ec55e600 --- /dev/null +++ b/examples/src/hello_grpc_tls/grpc_tls_server.rs @@ -0,0 +1,71 @@ +//! Run with `cargo run --example hello-tls-grpc-server --features tls` + +use std::{net::SocketAddr, path::Path, sync::Arc}; + +use librustls::{Certificate, PrivateKey, ServerConfig}; /* crate `rustls` is renamed to + * `librustls` in this example */ +use rustls_pemfile::{certs, pkcs8_private_keys}; +use volo_grpc::{ + server::{Server, ServiceBuilder}, + transport::ServerTlsConfig, +}; + +pub struct S; + +impl volo_gen::proto_gen::hello::Greeter for S { + async fn say_hello( + &self, + req: volo_grpc::Request, + ) -> Result, volo_grpc::Status> + { + let resp = volo_gen::proto_gen::hello::HelloReply { + message: format!("Hello, {}!", req.get_ref().name).into(), + }; + Ok(volo_grpc::Response::new(resp)) + } +} + +fn load_certs(path: impl AsRef) -> std::io::Result> { + certs(&mut std::io::BufReader::new(std::fs::File::open(path)?)) + .map(|v| v.into_iter().map(Certificate).collect()) + .map_err(|_| std::io::Error::new(std::io::ErrorKind::InvalidInput, "invalid cert").into()) +} + +fn load_keys(path: impl AsRef) -> std::io::Result> { + pkcs8_private_keys(&mut std::io::BufReader::new(std::fs::File::open(path)?)) + .map(|v| v.into_iter().map(PrivateKey).collect()) + .map_err(|_| std::io::Error::new(std::io::ErrorKind::InvalidInput, "invalid key").into()) +} + +#[volo::main] +async fn main() { + // TLS configuration + // + // The key and certificate are copied from + // https://github.com/hyperium/tonic/tree/master/examples/data/tls + let data_dir = std::path::PathBuf::from_iter([std::env!("CARGO_MANIFEST_DIR"), "data"]); + let certs = load_certs(data_dir.join("tls/server.pem")).unwrap(); + let private_key = load_keys(data_dir.join("tls/server.key")).unwrap()[0].clone(); + + let mut server_config = ServerConfig::builder() + .with_safe_defaults() + .with_no_client_auth() + .with_single_cert(certs, private_key) + .expect("bad certificate/key"); + server_config.alpn_protocols = vec![b"h2".to_vec()]; + + let server_config = Arc::new(server_config); + let acceptor = tokio_rustls::TlsAcceptor::from(server_config); + let tls_config = ServerTlsConfig::from(acceptor); + + // Server address + let addr: SocketAddr = "[::]:8080".parse().unwrap(); + let addr = volo::net::Address::from(addr); + + Server::new() + .tls_config(tls_config) + .add_service(ServiceBuilder::new(volo_gen::proto_gen::hello::GreeterServer::new(S)).build()) + .run(addr) + .await + .unwrap(); +} diff --git a/volo-grpc/Cargo.toml b/volo-grpc/Cargo.toml index 9c4f2a34..e2b0a970 100644 --- a/volo-grpc/Cargo.toml +++ b/volo-grpc/Cargo.toml @@ -14,6 +14,9 @@ keywords = ["async", "rpc", "grpc", "protobuf"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[package.metadata.docs.rs] +rustdoc-args = ["--cfg", "docsrs"] # for conditional intra-doc links + [badges] maintenance = { status = "actively-developed" } @@ -53,5 +56,14 @@ tower = { workspace = true, features = [ ] } tracing.workspace = true +tokio-rustls = { workspace = true, optional = true } +tokio-native-tls = { workspace = true, optional = true } + [dev-dependencies] tracing-subscriber.workspace = true + +[features] +default = [] + +rustls = ["tokio-rustls"] +native-tls = ["tokio-native-tls"] \ No newline at end of file diff --git a/volo-grpc/src/cfg.rs b/volo-grpc/src/cfg.rs new file mode 100644 index 00000000..ee63c1ff --- /dev/null +++ b/volo-grpc/src/cfg.rs @@ -0,0 +1,32 @@ +#[allow(unused_macros)] // Otherwise, it will complain if neither `rustls` nor `native-tls` is enabled. +macro_rules! cfg_rustls { + ($($item:item)*) => { + $( + #[cfg(feature = "rustls")] + #[cfg_attr(docsrs, doc(cfg(feature = "rustls")))] + $item + )* + } +} + +#[allow(unused_macros)] // Otherwise, it will complain if neither `rustls` nor `native-tls` is enabled. +macro_rules! cfg_native_tls { + ($($item:item)*) => { + $( + #[cfg(feature = "native-tls")] + #[cfg_attr(docsrs, doc(cfg(feature = "native-tls")))] + $item + )* + } +} + +#[allow(unused_macros)] // Otherwise, it will complain if neither `rustls` nor `native-tls` is enabled. +macro_rules! cfg_rustls_or_native_tls { + ($($item:item)*) => { + $( + #[cfg(any(feature = "rustls", feature = "native-tls"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "rustls", feature = "native-tls"))))] + $item + )* + } +} diff --git a/volo-grpc/src/client/mod.rs b/volo-grpc/src/client/mod.rs index 6ea2dc3b..3be9033c 100644 --- a/volo-grpc/src/client/mod.rs +++ b/volo-grpc/src/client/mod.rs @@ -47,6 +47,9 @@ pub struct ClientBuilder { mk_client: C, mk_lb: LB, _marker: PhantomData, + + #[cfg(any(feature = "rustls", feature = "native-tls"))] + tls_config: Option, } impl @@ -72,6 +75,9 @@ impl mk_client: service_client, mk_lb: LbConfig::new(WeightedRandomBalance::new(), DummyDiscover {}), _marker: PhantomData, + + #[cfg(any(feature = "rustls", feature = "native-tls"))] + tls_config: None, } } } @@ -92,6 +98,9 @@ impl ClientBuilder, T, mk_client: self.mk_client, mk_lb: self.mk_lb.load_balance(load_balance), _marker: PhantomData, + + #[cfg(any(feature = "rustls", feature = "native-tls"))] + tls_config: self.tls_config, } } @@ -110,6 +119,9 @@ impl ClientBuilder, T, mk_client: self.mk_client, mk_lb: self.mk_lb.discover(discover), _marker: PhantomData, + + #[cfg(any(feature = "rustls", feature = "native-tls"))] + tls_config: self.tls_config, } } } @@ -282,6 +294,9 @@ impl ClientBuilder { mk_client: self.mk_client, mk_lb: mk_load_balance, _marker: PhantomData, + + #[cfg(any(feature = "rustls", feature = "native-tls"))] + tls_config: self.tls_config, } } @@ -323,6 +338,9 @@ impl ClientBuilder { mk_client: self.mk_client, mk_lb: self.mk_lb, _marker: self._marker, + + #[cfg(any(feature = "rustls", feature = "native-tls"))] + tls_config: self.tls_config, } } @@ -354,6 +372,9 @@ impl ClientBuilder { mk_client: self.mk_client, mk_lb: self.mk_lb, _marker: self._marker, + + #[cfg(any(feature = "rustls", feature = "native-tls"))] + tls_config: self.tls_config, } } @@ -385,8 +406,18 @@ impl ClientBuilder { mk_client: self.mk_client, mk_lb: self.mk_lb, _marker: self._marker, + + #[cfg(any(feature = "rustls", feature = "native-tls"))] + tls_config: self.tls_config, } } + + /// Sets the [`ClientTlsConfig`] for the client. + #[cfg(any(feature = "rustls", feature = "native-tls"))] + pub fn tls_config(mut self, tls_config: volo::net::dial::ClientTlsConfig) -> Self { + self.tls_config = Some(tls_config); + self + } } impl ClientBuilder @@ -421,8 +452,19 @@ where { /// Builds a new [`Client`]. pub fn build(self) -> C::Target { + #[cfg(not(any(feature = "rustls", feature = "native-tls")))] let transport = MetaService::new(ClientTransport::new(&self.http2_config, &self.rpc_config)); + #[cfg(any(feature = "rustls", feature = "native-tls"))] + let transport = match self.tls_config { + Some(tls_config) => MetaService::new(ClientTransport::new_with_tls( + &self.http2_config, + &self.rpc_config, + tls_config, + )), + None => MetaService::new(ClientTransport::new(&self.http2_config, &self.rpc_config)), + }; + let transport = self.outer_layer.layer(BoxCloneService::new( self.mk_lb.make().layer(self.inner_layer.layer(transport)), )); diff --git a/volo-grpc/src/lib.rs b/volo-grpc/src/lib.rs index 1a353ecd..10ade2db 100644 --- a/volo-grpc/src/lib.rs +++ b/volo-grpc/src/lib.rs @@ -2,6 +2,10 @@ html_logo_url = "https://github.com/cloudwego/volo/raw/main/.github/assets/logo.png?sanitize=true" )] #![cfg_attr(not(doctest), doc = include_str!("../README.md"))] +#![cfg_attr(docsrs, feature(doc_cfg))] + +#[macro_use] +mod cfg; pub mod body; pub mod client; diff --git a/volo-grpc/src/server/mod.rs b/volo-grpc/src/server/mod.rs index eca757e5..66fbed40 100644 --- a/volo-grpc/src/server/mod.rs +++ b/volo-grpc/src/server/mod.rs @@ -14,13 +14,22 @@ use motore::{ BoxError, }; pub use service::ServiceBuilder; -use volo::{net::incoming::Incoming, spawn}; +use volo::{ + net::{conn::Conn, incoming::Incoming}, + spawn, +}; pub use self::router::Router; use crate::{ body::Body, context::ServerContext, server::meta::MetaService, Request, Response, Status, }; +cfg_rustls_or_native_tls! { + use volo::net::conn::ConnStream; + + use crate::transport::{ServerTlsConfig, TlsAcceptor}; +} + /// A trait to provide a static reference to the service's /// name. This is used for routing service's within the router. pub trait NamedService { @@ -36,6 +45,9 @@ pub struct Server { layer: L, http2_config: Http2Config, router: Router, + + #[cfg(any(feature = "rustls", feature = "native-tls"))] + tls_config: Option, } impl Default for Server { @@ -51,11 +63,24 @@ impl Server { layer: Identity::new(), http2_config: Http2Config::default(), router: Router::new(), + + #[cfg(any(feature = "rustls", feature = "native-tls"))] + tls_config: None, } } } impl Server { + cfg_rustls_or_native_tls! { + /// Sets the TLS configuration for the server. + /// + /// If not set, the server will not use TLS. + pub fn tls_config(mut self, value: impl Into) -> Self { + self.tls_config = Some(value.into()); + self + } + } + /// Sets the [`SETTINGS_INITIAL_WINDOW_SIZE`] option for HTTP2 /// stream-level flow control. /// @@ -174,6 +199,8 @@ impl Server { layer: Stack::new(layer, self.layer), http2_config: self.http2_config, router: self.router, + #[cfg(any(feature = "rustls", feature = "native-tls"))] + tls_config: self.tls_config, } } @@ -193,6 +220,8 @@ impl Server { layer: Stack::new(self.layer, layer), http2_config: self.http2_config, router: self.router, + #[cfg(any(feature = "rustls", feature = "native-tls"))] + tls_config: self.tls_config, } } @@ -210,6 +239,8 @@ impl Server { layer: self.layer, http2_config: self.http2_config, router: self.router.add_service(s), + #[cfg(any(feature = "rustls", feature = "native-tls"))] + tls_config: self.tls_config, } } @@ -253,10 +284,38 @@ impl Server { return Ok(()); }, conn = incoming.accept() => { - let conn = match conn? { + let conn: Conn = match conn? { Some(c) => c, None => return Ok(()), }; + #[cfg(any(feature = "rustls", feature = "native-tls"))] + let conn: Conn = { + let info = conn.info; + // Only perform TLS handshake if either rustls or native-tls is configured + match (conn.stream, self.tls_config.as_ref().map(|o| &o.acceptor)) { + #[cfg(feature = "rustls")] + (volo::net::conn::ConnStream::Tcp(tcp), Some(TlsAcceptor::Rustls(tls_acceptor))) => { + let stream = tls_acceptor.accept(tcp).await?; + Conn { + stream: ConnStream::Rustls(tokio_rustls::TlsStream::Server(stream)), + info + } + }, + #[cfg(feature = "native-tls")] + (volo::net::conn::ConnStream::Tcp(tcp), Some(TlsAcceptor::NativeTls(tls_acceptor))) => { + let stream = tls_acceptor.accept(tcp).await?; + Conn { + stream: ConnStream::NativeTls(stream), + info, + } + }, + (stream, _) => Conn { + stream, + info + }, + } + }; + tracing::trace!("[VOLO] recv a connection from: {:?}", conn.info.peer_addr); let peer_addr = conn.info.peer_addr.clone(); diff --git a/volo-grpc/src/transport/client.rs b/volo-grpc/src/transport/client.rs index 9fc51ee9..d9fc3e0a 100644 --- a/volo-grpc/src/transport/client.rs +++ b/volo-grpc/src/transport/client.rs @@ -64,6 +64,37 @@ impl ClientTransport { _marker: PhantomData, } } + + #[cfg(any(feature = "rustls", feature = "native-tls"))] + pub fn new_with_tls( + http2_config: &Http2Config, + rpc_config: &Config, + tls_config: volo::net::dial::ClientTlsConfig, + ) -> Self { + let config = volo::net::dial::Config::new( + rpc_config.connect_timeout, + rpc_config.read_timeout, + rpc_config.write_timeout, + ); + let http = HyperClient::builder() + .http2_only(!http2_config.accept_http1) + .http2_initial_stream_window_size(http2_config.init_stream_window_size) + .http2_initial_connection_window_size(http2_config.init_connection_window_size) + .http2_max_frame_size(http2_config.max_frame_size) + .http2_adaptive_window(http2_config.adaptive_window) + .http2_keep_alive_interval(http2_config.http2_keepalive_interval) + .http2_keep_alive_timeout(http2_config.http2_keepalive_timeout) + .http2_keep_alive_while_idle(http2_config.http2_keepalive_while_idle) + .http2_max_concurrent_reset_streams(http2_config.max_concurrent_reset_streams) + .http2_max_send_buf_size(http2_config.max_send_buf_size) + .retry_canceled_requests(http2_config.retry_canceled_requests) + .build(Connector::new_with_tls(Some(config), tls_config)); + + ClientTransport { + http_client: http, + _marker: PhantomData, + } + } } impl Service> for ClientTransport diff --git a/volo-grpc/src/transport/connect.rs b/volo-grpc/src/transport/connect.rs index 649ec505..9427649d 100644 --- a/volo-grpc/src/transport/connect.rs +++ b/volo-grpc/src/transport/connect.rs @@ -1,5 +1,4 @@ use std::{ - borrow::Cow, io, net::SocketAddr, pin::Pin, @@ -7,7 +6,6 @@ use std::{ }; use futures::future::BoxFuture; -use hex::FromHex; use hyper::client::connect::{Connected, Connection}; use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; use volo::net::{ @@ -16,8 +14,16 @@ use volo::net::{ Address, }; +cfg_rustls_or_native_tls! { + use volo::net::dial::{TlsMakeTransport, ClientTlsConfig}; +} + #[derive(Clone, Debug)] -pub struct Connector(DefaultMakeTransport); +pub enum Connector { + Default(DefaultMakeTransport), + #[cfg(any(feature = "rustls", feature = "native-tls"))] + Tls(TlsMakeTransport), +} impl Connector { pub fn new(cfg: Option) -> Self { @@ -27,7 +33,18 @@ impl Connector { mt.set_read_timeout(cfg.read_timeout); mt.set_write_timeout(cfg.write_timeout); } - Self(mt) + Self::Default(mt) + } + + #[cfg(any(feature = "rustls", feature = "native-tls"))] + pub fn new_with_tls(cfg: Option, tls_config: ClientTlsConfig) -> Self { + let mut mt = TlsMakeTransport::new(cfg.unwrap_or_default(), tls_config); + if let Some(cfg) = cfg { + mt.set_connect_timeout(cfg.connect_timeout); + mt.set_read_timeout(cfg.read_timeout); + mt.set_write_timeout(cfg.write_timeout); + } + Self::Tls(mt) } } @@ -49,40 +66,59 @@ impl tower::Service for Connector { } fn call(&mut self, uri: hyper::Uri) -> Self::Future { - let mk_conn = self.0; - Box::pin(async move { - let authority = uri.authority().expect("authority required").as_str(); - let target: Address = match uri.scheme_str() { - Some("http") => Address::Ip(authority.parse::().map_err(|_| { - io::Error::new( - io::ErrorKind::InvalidInput, - "authority must be valid SocketAddr", - ) - })?), - #[cfg(target_family = "unix")] - Some("http+unix") => { - let bytes = Vec::from_hex(authority).map_err(|_| { - io::Error::new( - io::ErrorKind::InvalidInput, - "authority must be hex-encoded path", - ) - })?; - Address::Unix(Cow::Owned( - String::from_utf8(bytes) - .map_err(|_| { + macro_rules! box_pin_call { + ($mk_conn:ident) => { + Box::pin(async move { + let authority = uri.authority().expect("authority required").as_str(); + let target: Address = match uri.scheme_str() { + Some("http") => { + Address::Ip(authority.parse::().map_err(|_| { + io::Error::new( + io::ErrorKind::InvalidInput, + "authority must be valid SocketAddr", + ) + })?) + } + #[cfg(target_family = "unix")] + Some("http+unix") => { + use hex::FromHex; + + let bytes = Vec::from_hex(authority).map_err(|_| { io::Error::new( io::ErrorKind::InvalidInput, - "authority must be valid UTF-8", + "authority must be hex-encoded path", ) - })? - .into(), - )) - } - _ => unimplemented!(), + })?; + Address::Unix(std::borrow::Cow::Owned( + String::from_utf8(bytes) + .map_err(|_| { + io::Error::new( + io::ErrorKind::InvalidInput, + "authority must be valid UTF-8", + ) + })? + .into(), + )) + } + _ => unimplemented!(), + }; + + Ok(ConnectionWrapper($mk_conn.make_connection(target).await?)) + }) }; + } - Ok(ConnectionWrapper(mk_conn.make_connection(target).await?)) - }) + match self { + Self::Default(mk_conn) => { + let mk_conn = mk_conn.clone(); + box_pin_call!(mk_conn) + } + #[cfg(any(feature = "rustls", feature = "native-tls"))] + Self::Tls(mk_conn) => { + let mk_conn = mk_conn.clone(); + box_pin_call!(mk_conn) + } + } } } diff --git a/volo-grpc/src/transport/mod.rs b/volo-grpc/src/transport/mod.rs index 03c4296d..d0bd126d 100644 --- a/volo-grpc/src/transport/mod.rs +++ b/volo-grpc/src/transport/mod.rs @@ -3,4 +3,9 @@ mod client; mod connect; +cfg_rustls_or_native_tls! { + mod tls; + pub use tls::{ServerTlsConfig, TlsAcceptor}; +} + pub use client::ClientTransport; diff --git a/volo-grpc/src/transport/tls.rs b/volo-grpc/src/transport/tls.rs new file mode 100644 index 00000000..6eb302fc --- /dev/null +++ b/volo-grpc/src/transport/tls.rs @@ -0,0 +1,50 @@ +cfg_rustls_or_native_tls! { + /// TLS configuration for a server. + #[derive(Clone)] + pub struct ServerTlsConfig { + pub acceptor: TlsAcceptor, + } + + /// A wrapper around [`tokio_rustls::TlsAcceptor`] and [`tokio_native_tls::TlsAcceptor`]. + #[derive(Clone)] + pub enum TlsAcceptor { + /// `tokio_rustls::TlsAcceptor` internally uses `Arc` + #[cfg_attr(docsrs, doc(cfg(feature = "rustls")))] + #[cfg(feature = "rustls")] + Rustls(tokio_rustls::TlsAcceptor), + + /// This takes an `Arc` because it does not internally use `Arc` + #[cfg_attr(docsrs, doc(cfg(feature = "native-tls")))] + #[cfg(feature = "native-tls")] + NativeTls(std::sync::Arc), + } +} + +cfg_rustls! { + impl From for ServerTlsConfig { + fn from(value: tokio_rustls::TlsAcceptor) -> Self { + Self { + acceptor: TlsAcceptor::Rustls(value), + } + } + } +} + +cfg_native_tls! { + impl From> for ServerTlsConfig { + fn from(value: std::sync::Arc) -> Self { + Self { + acceptor: TlsAcceptor::NativeTls(value), + } + } + } + + impl From for ServerTlsConfig { + fn from(value: tokio_native_tls::TlsAcceptor) -> Self { + Self { + acceptor: TlsAcceptor::NativeTls(std::sync::Arc::new(value)), + } + } + } +} + diff --git a/volo/Cargo.toml b/volo/Cargo.toml index 66e72872..75137fc4 100644 --- a/volo/Cargo.toml +++ b/volo/Cargo.toml @@ -16,6 +16,9 @@ keywords = ["async", "rpc", "thrift", "grpc", "protobuf"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[package.metadata.docs.rs] +rustdoc-args = ["--cfg", "docsrs"] # for conditional intra-doc links + [badges] maintenance = { status = "actively-developed" } @@ -46,3 +49,14 @@ tokio = { workspace = true, features = ["net", "time", "sync", "io-util"] } tokio-stream = { workspace = true, features = ["net"] } tower.workspace = true tracing.workspace = true + +# Optional dependencies +librustls = { workspace = true, optional = true } +tokio-rustls = { workspace = true, optional = true } +tokio-native-tls = { workspace = true, optional = true } + +[features] +default = [] + +rustls = ["tokio-rustls", "librustls"] +native-tls = ["tokio-native-tls"] \ No newline at end of file diff --git a/volo/src/cfg.rs b/volo/src/cfg.rs new file mode 100644 index 00000000..6c8941cf --- /dev/null +++ b/volo/src/cfg.rs @@ -0,0 +1,29 @@ +macro_rules! cfg_rustls { + ($($item:item)*) => { + $( + #[cfg(feature = "rustls")] + #[cfg_attr(docsrs, doc(cfg(feature = "rustls")))] + $item + )* + } +} + +macro_rules! cfg_native_tls { + ($($item:item)*) => { + $( + #[cfg(feature = "native-tls")] + #[cfg_attr(docsrs, doc(cfg(feature = "native-tls")))] + $item + )* + } +} + +macro_rules! cfg_rustls_or_native_tls { + ($($item:item)*) => { + $( + #[cfg(any(feature = "rustls", feature = "native-tls"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "rustls", feature = "native-tls"))))] + $item + )* + } +} diff --git a/volo/src/lib.rs b/volo/src/lib.rs index fdf3cc32..bd08abd4 100644 --- a/volo/src/lib.rs +++ b/volo/src/lib.rs @@ -2,6 +2,10 @@ html_logo_url = "https://github.com/cloudwego/volo/raw/main/.github/assets/logo.png?sanitize=true" )] #![cfg_attr(not(doctest), doc = include_str!("../README.md"))] +#![cfg_attr(docsrs, feature(doc_cfg))] + +#[macro_use] +mod cfg; pub use motore::{layer, layer::Layer, service, Service}; pub use tokio::main; diff --git a/volo/src/net/conn.rs b/volo/src/net/conn.rs index ed9efb78..8c39dc9e 100644 --- a/volo/src/net/conn.rs +++ b/volo/src/net/conn.rs @@ -28,6 +28,18 @@ pub enum ConnStream { Tcp(#[pin] TcpStream), #[cfg(target_family = "unix")] Unix(#[pin] UnixStream), + #[cfg(feature = "rustls")] + Rustls(#[pin] tokio_rustls::TlsStream), + #[cfg(feature = "native-tls")] + NativeTls(#[pin] tokio_native_tls::TlsStream), +} + +cfg_rustls! { + type RustlsWriteHalf = tokio::io::WriteHalf>; +} + +cfg_native_tls! { + type NativeTlsWriteHalf = tokio::io::WriteHalf>; } #[pin_project(project = OwnedWriteHalfProj)] @@ -35,6 +47,10 @@ pub enum OwnedWriteHalf { Tcp(#[pin] tcp::OwnedWriteHalf), #[cfg(target_family = "unix")] Unix(#[pin] unix::OwnedWriteHalf), + #[cfg(feature = "rustls")] + Rustls(#[pin] RustlsWriteHalf), + #[cfg(feature = "native-tls")] + NativeTls(#[pin] NativeTlsWriteHalf), } impl AsyncWrite for OwnedWriteHalf { @@ -48,6 +64,10 @@ impl AsyncWrite for OwnedWriteHalf { OwnedWriteHalfProj::Tcp(half) => half.poll_write(cx, buf), #[cfg(target_family = "unix")] OwnedWriteHalfProj::Unix(half) => half.poll_write(cx, buf), + #[cfg(feature = "rustls")] + OwnedWriteHalfProj::Rustls(half) => half.poll_write(cx, buf), + #[cfg(feature = "native-tls")] + OwnedWriteHalfProj::NativeTls(half) => half.poll_write(cx, buf), } } @@ -57,6 +77,10 @@ impl AsyncWrite for OwnedWriteHalf { OwnedWriteHalfProj::Tcp(half) => half.poll_flush(cx), #[cfg(target_family = "unix")] OwnedWriteHalfProj::Unix(half) => half.poll_flush(cx), + #[cfg(feature = "rustls")] + OwnedWriteHalfProj::Rustls(half) => half.poll_flush(cx), + #[cfg(feature = "native-tls")] + OwnedWriteHalfProj::NativeTls(half) => half.poll_flush(cx), } } @@ -66,6 +90,10 @@ impl AsyncWrite for OwnedWriteHalf { OwnedWriteHalfProj::Tcp(half) => half.poll_shutdown(cx), #[cfg(target_family = "unix")] OwnedWriteHalfProj::Unix(half) => half.poll_shutdown(cx), + #[cfg(feature = "rustls")] + OwnedWriteHalfProj::Rustls(half) => half.poll_shutdown(cx), + #[cfg(feature = "native-tls")] + OwnedWriteHalfProj::NativeTls(half) => half.poll_shutdown(cx), } } @@ -79,6 +107,10 @@ impl AsyncWrite for OwnedWriteHalf { OwnedWriteHalfProj::Tcp(half) => half.poll_write_vectored(cx, bufs), #[cfg(target_family = "unix")] OwnedWriteHalfProj::Unix(half) => half.poll_write_vectored(cx, bufs), + #[cfg(feature = "rustls")] + OwnedWriteHalfProj::Rustls(half) => half.poll_write_vectored(cx, bufs), + #[cfg(feature = "native-tls")] + OwnedWriteHalfProj::NativeTls(half) => half.poll_write_vectored(cx, bufs), } } @@ -88,15 +120,31 @@ impl AsyncWrite for OwnedWriteHalf { Self::Tcp(half) => half.is_write_vectored(), #[cfg(target_family = "unix")] Self::Unix(half) => half.is_write_vectored(), + #[cfg(feature = "rustls")] + Self::Rustls(half) => half.is_write_vectored(), + #[cfg(feature = "native-tls")] + Self::NativeTls(half) => half.is_write_vectored(), } } } +cfg_rustls! { + type RustlsReadHalf = tokio::io::ReadHalf>; +} + +cfg_native_tls! { + type NativeTlsReadHalf = tokio::io::ReadHalf>; +} + #[pin_project(project = OwnedReadHalfProj)] pub enum OwnedReadHalf { Tcp(#[pin] tcp::OwnedReadHalf), #[cfg(target_family = "unix")] Unix(#[pin] unix::OwnedReadHalf), + #[cfg(feature = "rustls")] + Rustls(#[pin] RustlsReadHalf), + #[cfg(feature = "native-tls")] + NativeTls(#[pin] NativeTlsReadHalf), } impl AsyncRead for OwnedReadHalf { @@ -110,6 +158,10 @@ impl AsyncRead for OwnedReadHalf { OwnedReadHalfProj::Tcp(half) => half.poll_read(cx, buf), #[cfg(target_family = "unix")] OwnedReadHalfProj::Unix(half) => half.poll_read(cx, buf), + #[cfg(feature = "rustls")] + OwnedReadHalfProj::Rustls(half) => half.poll_read(cx, buf), + #[cfg(feature = "native-tls")] + OwnedReadHalfProj::NativeTls(half) => half.poll_read(cx, buf), } } } @@ -127,6 +179,16 @@ impl ConnStream { let (rh, wh) = stream.into_split(); (OwnedReadHalf::Unix(rh), OwnedWriteHalf::Unix(wh)) } + #[cfg(feature = "rustls")] + Self::Rustls(stream) => { + let (rh, wh) = tokio::io::split(stream); + (OwnedReadHalf::Rustls(rh), OwnedWriteHalf::Rustls(wh)) + } + #[cfg(feature = "native-tls")] + Self::NativeTls(stream) => { + let (rh, wh) = tokio::io::split(stream); + (OwnedReadHalf::NativeTls(rh), OwnedWriteHalf::NativeTls(wh)) + } } } } @@ -147,6 +209,24 @@ impl From for ConnStream { } } +cfg_rustls! { + impl From> for ConnStream { + #[inline] + fn from(s: tokio_rustls::TlsStream) -> Self { + Self::Rustls(s) + } + } +} + +cfg_native_tls! { + impl From> for ConnStream { + #[inline] + fn from(s: tokio_native_tls::TlsStream) -> Self { + Self::NativeTls(s) + } + } +} + impl AsyncRead for ConnStream { #[inline] fn poll_read( @@ -158,6 +238,10 @@ impl AsyncRead for ConnStream { IoStreamProj::Tcp(s) => s.poll_read(cx, buf), #[cfg(target_family = "unix")] IoStreamProj::Unix(s) => s.poll_read(cx, buf), + #[cfg(feature = "rustls")] + IoStreamProj::Rustls(s) => s.poll_read(cx, buf), + #[cfg(feature = "native-tls")] + IoStreamProj::NativeTls(s) => s.poll_read(cx, buf), } } } @@ -173,6 +257,10 @@ impl AsyncWrite for ConnStream { IoStreamProj::Tcp(s) => s.poll_write(cx, buf), #[cfg(target_family = "unix")] IoStreamProj::Unix(s) => s.poll_write(cx, buf), + #[cfg(feature = "rustls")] + IoStreamProj::Rustls(s) => s.poll_write(cx, buf), + #[cfg(feature = "native-tls")] + IoStreamProj::NativeTls(s) => s.poll_write(cx, buf), } } @@ -182,6 +270,10 @@ impl AsyncWrite for ConnStream { IoStreamProj::Tcp(s) => s.poll_flush(cx), #[cfg(target_family = "unix")] IoStreamProj::Unix(s) => s.poll_flush(cx), + #[cfg(feature = "rustls")] + IoStreamProj::Rustls(s) => s.poll_flush(cx), + #[cfg(feature = "native-tls")] + IoStreamProj::NativeTls(s) => s.poll_flush(cx), } } @@ -191,6 +283,10 @@ impl AsyncWrite for ConnStream { IoStreamProj::Tcp(s) => s.poll_shutdown(cx), #[cfg(target_family = "unix")] IoStreamProj::Unix(s) => s.poll_shutdown(cx), + #[cfg(feature = "rustls")] + IoStreamProj::Rustls(s) => s.poll_shutdown(cx), + #[cfg(feature = "native-tls")] + IoStreamProj::NativeTls(s) => s.poll_shutdown(cx), } } @@ -204,6 +300,10 @@ impl AsyncWrite for ConnStream { IoStreamProj::Tcp(s) => s.poll_write_vectored(cx, bufs), #[cfg(target_family = "unix")] IoStreamProj::Unix(s) => s.poll_write_vectored(cx, bufs), + #[cfg(feature = "rustls")] + IoStreamProj::Rustls(s) => s.poll_write_vectored(cx, bufs), + #[cfg(feature = "native-tls")] + IoStreamProj::NativeTls(s) => s.poll_write_vectored(cx, bufs), } } @@ -213,6 +313,10 @@ impl AsyncWrite for ConnStream { Self::Tcp(s) => s.is_write_vectored(), #[cfg(target_family = "unix")] Self::Unix(s) => s.is_write_vectored(), + #[cfg(feature = "rustls")] + Self::Rustls(s) => s.is_write_vectored(), + #[cfg(feature = "native-tls")] + Self::NativeTls(s) => s.is_write_vectored(), } } } @@ -224,6 +328,16 @@ impl ConnStream { Self::Tcp(s) => s.peer_addr().map(Address::from).ok(), #[cfg(target_family = "unix")] Self::Unix(s) => s.peer_addr().ok().and_then(|s| Address::try_from(s).ok()), + #[cfg(feature = "rustls")] + Self::Rustls(s) => s.get_ref().0.peer_addr().map(Address::from).ok(), + #[cfg(feature = "native-tls")] + Self::NativeTls(s) => s + .get_ref() + .get_ref() + .get_ref() + .peer_addr() + .map(Address::from) + .ok(), } } } diff --git a/volo/src/net/dial.rs b/volo/src/net/dial.rs index e787a7b4..efef8a9e 100644 --- a/volo/src/net/dial.rs +++ b/volo/src/net/dial.rs @@ -1,11 +1,11 @@ -use std::{future::Future, io}; +use std::{future::Future, io, net::SocketAddr}; use socket2::{Domain, Protocol, Socket, Type}; #[cfg(target_family = "unix")] use tokio::net::UnixStream; use tokio::{ io::{AsyncRead, AsyncWrite}, - net::TcpSocket, + net::{TcpSocket, TcpStream}, time::{timeout, Duration}, }; @@ -99,36 +99,38 @@ impl MakeTransport for DefaultMakeTransport { } } +async fn make_tcp_connection(cfg: &Config, addr: SocketAddr) -> Result { + let domain = Domain::for_address(addr); + let socket = Socket::new(domain, Type::STREAM, Some(Protocol::TCP))?; + socket.set_nonblocking(true)?; + socket.set_read_timeout(cfg.read_timeout)?; + socket.set_write_timeout(cfg.write_timeout)?; + + #[cfg(unix)] + let socket = unsafe { + use std::os::unix::io::{FromRawFd, IntoRawFd}; + TcpSocket::from_raw_fd(socket.into_raw_fd()) + }; + #[cfg(windows)] + let socket = unsafe { + use std::os::windows::io::{FromRawSocket, IntoRawSocket}; + TcpSocket::from_raw_socket(socket.into_raw_socket()) + }; + + let connect = socket.connect(addr); + + if let Some(conn_timeout) = cfg.connect_timeout { + timeout(conn_timeout, connect).await? + } else { + connect.await + } +} + impl DefaultMakeTransport { pub async fn make_connection(&self, addr: Address) -> Result { match addr { Address::Ip(addr) => { - let stream = { - let domain = Domain::for_address(addr); - let socket = Socket::new(domain, Type::STREAM, Some(Protocol::TCP))?; - socket.set_nonblocking(true)?; - socket.set_read_timeout(self.cfg.read_timeout)?; - socket.set_write_timeout(self.cfg.write_timeout)?; - - #[cfg(unix)] - let socket = unsafe { - use std::os::unix::io::{FromRawFd, IntoRawFd}; - TcpSocket::from_raw_fd(socket.into_raw_fd()) - }; - #[cfg(windows)] - let socket = unsafe { - use std::os::windows::io::{FromRawSocket, IntoRawSocket}; - TcpSocket::from_raw_socket(socket.into_raw_socket()) - }; - - let connect = socket.connect(addr); - - if let Some(conn_timeout) = self.cfg.connect_timeout { - timeout(conn_timeout, connect).await?? - } else { - connect.await? - } - }; + let stream = make_tcp_connection(&self.cfg, addr).await?; stream.set_nodelay(true)?; Ok(Conn::from(stream)) } @@ -137,3 +139,139 @@ impl DefaultMakeTransport { } } } + +cfg_rustls_or_native_tls! { + /// A wrapper around [`tokio_rustls::TlsConnector`] and [`tokio_native_tls::TlsConnector`]. + #[derive(Clone)] + pub enum TlsConnector { + #[cfg_attr(docsrs, doc(cfg(feature = "rustls")))] + #[cfg(feature = "rustls")] + Rustls(tokio_rustls::TlsConnector), + + /// This takes an `Arc` because `tokio_native_tls::TlsConnector` does not internally use `Arc` + #[cfg_attr(docsrs, doc(cfg(feature = "native-tls")))] + #[cfg(feature = "native-tls")] + NativeTls(std::sync::Arc), + } + + impl std::fmt::Debug for TlsConnector { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + #[cfg(feature = "rustls")] + Self::Rustls(_) => f.debug_tuple("Rustls").finish(), + + #[cfg(feature = "native-tls")] + Self::NativeTls(_) => f.debug_tuple("NativeTls").finish(), + } + } + } + + /// TLS config for client + #[derive(Debug, Clone)] + pub struct ClientTlsConfig { + pub server_name: String, + pub connector: TlsConnector, + } + + impl ClientTlsConfig { + pub fn new(server_name: impl Into, connector: impl Into) -> Self { + Self { + server_name: server_name.into(), + connector: connector.into(), + } + } + } + + #[derive(Debug, Clone)] + pub struct TlsMakeTransport { + cfg: Config, + tls_config: ClientTlsConfig, + } + + impl TlsMakeTransport { + pub fn new(cfg: Config, tls_config: ClientTlsConfig) -> Self { + Self { + cfg, + tls_config, + } + } + + pub async fn make_connection(&self, addr: Address) -> Result { + match addr { + Address::Ip(addr) => { + let tcp = make_tcp_connection(&self.cfg, addr).await?; + + match &self.tls_config.connector { + #[cfg(feature = "rustls")] + TlsConnector::Rustls(connector) => { + let server_name = librustls::ServerName::try_from(&self.tls_config.server_name[..]) + .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?; + connector + .connect(server_name, tcp) + .await + .map(tokio_rustls::TlsStream::Client) + .map(Conn::from) + } + #[cfg(feature = "native-tls")] + TlsConnector::NativeTls(connector) => { + let tcp = make_tcp_connection(&self.cfg, addr).await?; + connector + .connect(&self.tls_config.server_name[..], tcp) + .await + .map(Conn::from) + .map_err(|e| io::Error::new(io::ErrorKind::Other, e)) + } + } + } + #[cfg(target_family = "unix")] + Address::Unix(addr) => UnixStream::connect(addr).await.map(Conn::from), + } + } + } + + impl MakeTransport for TlsMakeTransport { + type ReadHalf = OwnedReadHalf; + + type WriteHalf = OwnedWriteHalf; + + async fn make_transport(&self, addr: Address) -> io::Result<(Self::ReadHalf, Self::WriteHalf)> { + let conn = self.make_connection(addr).await?; + let (read, write) = conn.stream.into_split(); + Ok((read, write)) + } + + fn set_connect_timeout(&mut self, timeout: Option) { + self.cfg = self.cfg.with_connect_timeout(timeout); + } + + fn set_read_timeout(&mut self, timeout: Option) { + self.cfg = self.cfg.with_read_timeout(timeout); + } + + fn set_write_timeout(&mut self, timeout: Option) { + self.cfg = self.cfg.with_write_timeout(timeout); + } + } +} + +cfg_rustls! { + impl From for TlsConnector { + fn from(value: tokio_rustls::TlsConnector) -> Self { + Self::Rustls(value) + } + } +} + +cfg_native_tls! { + impl From> for TlsConnector { + fn from(value: std::sync::Arc) -> Self { + Self::NativeTls(value) + } + } + + impl From for TlsConnector { + fn from(value: tokio_native_tls::TlsConnector) -> Self { + Self::NativeTls(std::sync::Arc::new(value)) + } + } +} diff --git a/volo/src/net/incoming.rs b/volo/src/net/incoming.rs index 91a25cd0..e1750167 100644 --- a/volo/src/net/incoming.rs +++ b/volo/src/net/incoming.rs @@ -112,9 +112,12 @@ impl Stream for DefaultIncoming { #[cfg(target_family = "unix")] mod unix_helper { + #[cfg(target_os = "linux")] use std::{ fs::File, io::{BufRead, BufReader}, + }; + use std::{ net::{SocketAddr, TcpListener}, os::{ fd::{AsRawFd, FromRawFd, IntoRawFd}, @@ -165,6 +168,7 @@ mod unix_helper { (values[0], values[1]) } + #[cfg(target_os = "linux")] pub fn split_at_bytes(s: &str, t: &str) -> Vec { let mut result = Vec::new(); let mut last = 0; @@ -182,6 +186,7 @@ mod unix_helper { result } + #[cfg(target_os = "linux")] pub fn get_fields(s: &str) -> Vec { split_at_bytes(s, " \r\t\n") } diff --git a/volo/src/net/mod.rs b/volo/src/net/mod.rs index aaebc0b4..8620e9e2 100644 --- a/volo/src/net/mod.rs +++ b/volo/src/net/mod.rs @@ -3,7 +3,9 @@ pub mod dial; pub mod incoming; mod probe; -use std::{borrow::Cow, fmt, net::Ipv6Addr, path::Path}; +#[cfg(target_family = "unix")] +use std::{borrow::Cow, path::Path}; +use std::{fmt, net::Ipv6Addr}; pub use incoming::{DefaultIncoming, MakeIncoming};