From 621bec5a46fe16702b7a4a0624f842a5caed4af5 Mon Sep 17 00:00:00 2001 From: "sarunas.gincas" Date: Thu, 8 Aug 2024 10:41:40 +0300 Subject: [PATCH 1/3] Replace rouille with warp Co-authored-by: Fedor Sakharov --- Cargo.lock | 1075 +++++++++--------- Cargo.toml | 12 +- src/bin/sccache-dist/build.rs | 2 +- src/bin/sccache-dist/main.rs | 49 +- src/bin/sccache-dist/token_check.rs | 41 +- src/compiler/compiler.rs | 1 - src/compiler/rust.rs | 1 - src/dist/client_auth.rs | 17 +- src/dist/http.rs | 1569 ++++++++++++++++++--------- src/dist/mod.rs | 37 +- src/lib.rs | 3 - src/server.rs | 1 - src/test/tests.rs | 1 - src/util.rs | 41 +- tests/dist.rs | 80 +- tests/harness/mod.rs | 286 ++--- tests/system.rs | 34 +- 17 files changed, 1978 insertions(+), 1272 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 49f38ab50..a0aed958e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" dependencies = [ "gimli", ] @@ -30,9 +30,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] @@ -54,47 +54,48 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.11" +version = "0.6.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", + "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" -version = "1.0.2" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15c4c2c83f81532e5845a733998b6971faca23490340a418e9b72a3ec9de12ea" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" [[package]] name = "anstyle-parse" -version = "0.2.1" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.2" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" dependencies = [ "anstyle", "windows-sys 0.52.0", @@ -117,15 +118,15 @@ checksum = "d67af77d68a931ecd5cbd8a3b5987d63a1d1d1278f7f6a60ae33db485cdebb69" [[package]] name = "arc-swap" -version = "1.6.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6" +checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" [[package]] name = "arrayref" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" +checksum = "9d151e35f61089500b617991b791fc8bfd237ae50cd5950803758a179b41e67a" [[package]] name = "arrayvec" @@ -133,17 +134,11 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" -[[package]] -name = "ascii" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d92bec98840b8f03a5ff5413de5293bfcd8bf96467cf5452609f939ec6f5de16" - [[package]] name = "assert_cmd" -version = "2.0.13" +version = "2.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00ad3f3a942eee60335ab4342358c161ee296829e0d16ff42fc1d6cb07815467" +checksum = "bc65048dd435533bb1baf2ed9956b9a278fbfdcf90301b39ee117f06c0199d37" dependencies = [ "anstyle", "bstr", @@ -156,13 +151,13 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.80" +version = "0.1.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" +checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.72", ] [[package]] @@ -173,9 +168,9 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" -version = "1.1.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "backon" @@ -191,16 +186,16 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.69" +version = "0.3.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" dependencies = [ "addr2line", "cc", "cfg-if 1.0.0", "libc", "miniz_oxide", - "object", + "object 0.36.2", "rustc-demangle", ] @@ -230,12 +225,11 @@ checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] name = "bb8" -version = "0.8.1" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98b4b0f25f18bcdc3ac72bdb486ed0acf7e185221fd4dc985bc15db5800b0ba2" +checksum = "b10cf871f3ff2ce56432fddc2615ac7acc3aa22ca321f8fea800846fbb32f188" dependencies = [ "async-trait", - "futures-channel", "futures-util", "parking_lot", "tokio", @@ -258,15 +252,15 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.1" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "blake3" -version = "1.5.0" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0231f06152bf547e9c2b5194f247cd97aacf6dcd8b15d8e5ec0663f64580da87" +checksum = "e9ec96fe9a81b5e365f9db71fe00edc4fe4ca2cc7dcb7861f0603012a7caa210" dependencies = [ "arrayref", "arrayvec", @@ -295,30 +289,20 @@ dependencies = [ [[package]] name = "bstr" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c48f0051a4b4c5e0b6d365cd04af53aeaa209e3cc15ec2cdb69e73cc87fbd0dc" +checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" dependencies = [ "memchr", "regex-automata", "serde", ] -[[package]] -name = "buf_redux" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b953a6887648bb07a535631f2bc00fbdb2a2216f135552cb3f534ed136b9c07f" -dependencies = [ - "memchr", - "safemem", -] - [[package]] name = "bumpalo" -version = "3.14.0" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "byteorder" @@ -328,9 +312,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.6.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" +checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" [[package]] name = "cbc" @@ -343,9 +327,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.83" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +checksum = "26a5c3fd7bfa1ce3897a3a3501d362b2d87b7f2583ebcb4a949ec25911025cbc" dependencies = [ "jobserver", "libc", @@ -381,15 +365,9 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-targets 0.52.0", + "windows-targets 0.52.6", ] -[[package]] -name = "chunked_transfer" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4de3bc4ea267985becf712dc6d9eed8b04c953b3fcfb339ebc87acd9804901" - [[package]] name = "cipher" version = "0.4.4" @@ -402,9 +380,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.18" +version = "4.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c" +checksum = "0fbb260a053428790f3de475e304ff84cdbc4face759ea7a3e64c1edd938a7fc" dependencies = [ "clap_builder", "clap_derive", @@ -412,9 +390,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.18" +version = "4.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7" +checksum = "64b17d7ea74e9f833c7dbf2cbe4fb12ff26783eda4782a8975b72f895c9b4d99" dependencies = [ "anstream", "anstyle", @@ -425,33 +403,33 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.4.7" +version = "4.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" +checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.72", ] [[package]] name = "clap_lex" -version = "0.6.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" [[package]] name = "colorchoice" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" [[package]] name = "combine" -version = "4.6.6" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" dependencies = [ "bytes", "futures-core", @@ -469,9 +447,9 @@ checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "const-random" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aaf16c9c2c612020bcfd042e170f6e32de9b9d75adb5277cdbbd2e2c8c8299a" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" dependencies = [ "const-random-macro", ] @@ -546,21 +524,18 @@ dependencies = [ [[package]] name = "crc32fast" -version = "1.3.2" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ "cfg-if 1.0.0", ] [[package]] name = "crossbeam-utils" -version = "0.8.18" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3a430a770ebd84726f584a90ee7f020d28db52c6d02138900f22341f866d39c" -dependencies = [ - "cfg-if 1.0.0", -] +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crunchy" @@ -587,11 +562,17 @@ dependencies = [ "libc", ] +[[package]] +name = "data-encoding" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" + [[package]] name = "der" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" dependencies = [ "const-oid", "pem-rfc7468", @@ -609,13 +590,13 @@ dependencies = [ [[package]] name = "derive_more" -version = "0.99.17" +version = "0.99.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.72", ] [[package]] @@ -685,9 +666,9 @@ checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" [[package]] name = "either" -version = "1.9.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "encoding_rs" @@ -719,9 +700,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ "libc", "windows-sys 0.52.0", @@ -738,9 +719,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.0.1" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" [[package]] name = "filetime" @@ -750,21 +731,21 @@ checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" dependencies = [ "cfg-if 1.0.0", "libc", - "redox_syscall", + "redox_syscall 0.4.1", "windows-sys 0.52.0", ] [[package]] name = "flagset" -version = "0.4.4" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a7e408202050813e6f1d9addadcaafef3dca7530c7ddfb005d4081cce6779" +checksum = "b3ea1ec5f8307826a5b71094dd91fc04d4ae75d5709b20ad351c7fb4815c86ec" [[package]] name = "flate2" -version = "1.0.28" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" dependencies = [ "crc32fast", "miniz_oxide", @@ -789,7 +770,7 @@ dependencies = [ "futures-sink", "nanorand", "pin-project", - "spin 0.9.8", + "spin", ] [[package]] @@ -887,7 +868,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.72", ] [[package]] @@ -932,9 +913,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.11" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if 1.0.0", "js-sys", @@ -945,9 +926,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.28.1" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" [[package]] name = "gzp" @@ -975,7 +956,7 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http 0.2.11", + "http 0.2.12", "indexmap", "slab", "tokio", @@ -1004,21 +985,45 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "headers" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270" +dependencies = [ + "base64 0.21.7", + "bytes", + "headers-core", + "http 0.2.12", + "httpdate", + "mime", + "sha1", +] + +[[package]] +name = "headers-core" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" +dependencies = [ + "http 0.2.12", +] [[package]] name = "heck" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" -version = "0.3.3" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "hex" @@ -1057,9 +1062,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" dependencies = [ "bytes", "fnv", @@ -1084,15 +1089,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", - "http 0.2.11", + "http 0.2.12", "pin-project-lite", ] [[package]] name = "http-body" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", "http 1.1.0", @@ -1100,22 +1105,22 @@ dependencies = [ [[package]] name = "http-body-util" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ "bytes", - "futures-core", + "futures-util", "http 1.1.0", - "http-body 1.0.0", + "http-body 1.0.1", "pin-project-lite", ] [[package]] name = "httparse" -version = "1.8.0" +version = "1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" [[package]] name = "httpdate" @@ -1131,16 +1136,16 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.28" +version = "0.14.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" +checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9" dependencies = [ "bytes", "futures-channel", "futures-core", "futures-util", "h2 0.3.26", - "http 0.2.11", + "http 0.2.12", "http-body 0.4.6", "httparse", "httpdate", @@ -1155,20 +1160,21 @@ dependencies = [ [[package]] name = "hyper" -version = "1.1.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5aa53871fc917b1a9ed87b683a5d86db645e23acb32c2e0785a353e522fb75" +checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" dependencies = [ "bytes", "futures-channel", "futures-util", "h2 0.4.5", "http 1.1.0", - "http-body 1.0.0", + "http-body 1.0.1", "httparse", "httpdate", "itoa", "pin-project-lite", + "smallvec", "tokio", "want", ] @@ -1181,9 +1187,9 @@ checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" dependencies = [ "futures-util", "http 1.1.0", - "hyper 1.1.0", + "hyper 1.4.1", "hyper-util", - "rustls 0.23.10", + "rustls 0.23.12", "rustls-native-certs", "rustls-pki-types", "tokio", @@ -1199,7 +1205,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ "bytes", - "hyper 0.14.28", + "hyper 0.14.30", "native-tls", "tokio", "tokio-native-tls", @@ -1213,7 +1219,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper 1.1.0", + "hyper 1.4.1", "hyper-util", "native-tls", "tokio", @@ -1223,16 +1229,16 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.3" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa" +checksum = "3ab92f4f49ee4fb4f997c784b7a2e0fa70050211e0b6a287f898c3c9785ca956" dependencies = [ "bytes", "futures-channel", "futures-util", "http 1.1.0", - "http-body 1.0.0", - "hyper 1.1.0", + "http-body 1.0.1", + "hyper 1.4.1", "pin-project-lite", "socket2", "tokio", @@ -1243,9 +1249,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.59" +version = "0.1.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6a67363e2aa4443928ce15e57ebae94fd8949958fd1223c4cfc0cd473ad7539" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -1276,9 +1282,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.5" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" +checksum = "de3fc2e30ba82dd1b3911c8de1ffc143c74a914a14e99514d7637e3099df5ea0" dependencies = [ "equivalent", "hashbrown", @@ -1311,44 +1317,50 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + [[package]] name = "itertools" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" dependencies = [ "either", ] [[package]] name = "itoa" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "jobserver" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" dependencies = [ "libc", ] [[package]] name = "js-sys" -version = "0.3.66" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" dependencies = [ "wasm-bindgen", ] [[package]] name = "jsonwebtoken" -version = "9.2.0" +version = "9.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c7ea04a7c5c055c175f189b6dc6ba036fd62306b58c66c9f6389036c503a3f4" +checksum = "b9ae10193d25051e74945f1ea2d0b42e03cc3b890f7e4cc5faa44997d808193f" dependencies = [ "base64 0.21.7", "js-sys", @@ -1361,11 +1373,11 @@ dependencies = [ [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" dependencies = [ - "spin 0.5.2", + "spin", ] [[package]] @@ -1393,13 +1405,12 @@ dependencies = [ [[package]] name = "libredox" -version = "0.0.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.6.0", "libc", - "redox_syscall", ] [[package]] @@ -1410,15 +1421,15 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" -version = "0.4.12" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "lock_api" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", @@ -1448,9 +1459,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.1" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memmap2" @@ -1469,9 +1480,9 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "mime_guess" -version = "2.0.4" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" dependencies = [ "mime", "unicase", @@ -1479,40 +1490,41 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.7.1" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" dependencies = [ "adler", ] [[package]] name = "mio" -version = "0.8.11" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4" dependencies = [ + "hermit-abi", "libc", "wasi", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] -name = "multipart" -version = "0.18.0" +name = "multer" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00dec633863867f29cb39df64a397cdf4a6354708ddd7759f70c7fb51c5f9182" +checksum = "01acbdc23469fd8fe07ab135923371d5f5a422fbf9c522158677c8eb15bc51c2" dependencies = [ - "buf_redux", + "bytes", + "encoding_rs", + "futures-util", + "http 0.2.12", "httparse", "log", + "memchr", "mime", - "mime_guess", - "quick-error", - "rand", - "safemem", - "tempfile", - "twoway", + "spin", + "version_check", ] [[package]] @@ -1526,11 +1538,10 @@ dependencies = [ [[package]] name = "native-tls" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" dependencies = [ - "lazy_static", "libc", "log", "openssl", @@ -1561,7 +1572,7 @@ version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.6.0", "cfg-if 1.0.0", "cfg_aliases", "libc", @@ -1575,11 +1586,10 @@ checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" [[package]] name = "num-bigint" -version = "0.4.4" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ - "autocfg", "num-integer", "num-traits", ] @@ -1609,19 +1619,18 @@ checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" [[package]] name = "num-integer" -version = "0.1.45" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ - "autocfg", "num-traits", ] [[package]] name = "num-iter" -version = "0.1.43" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" dependencies = [ "autocfg", "num-integer", @@ -1630,9 +1639,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.17" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", "libm", @@ -1650,9 +1659,9 @@ dependencies = [ [[package]] name = "num_threads" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" dependencies = [ "libc", ] @@ -1674,6 +1683,15 @@ dependencies = [ "ruzstd", ] +[[package]] +name = "object" +version = "0.36.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f203fa8daa7bb185f760ae12bd8e097f63d17041dcdcaf675ac54cdf863170e" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" version = "1.19.0" @@ -1715,11 +1733,11 @@ dependencies = [ [[package]] name = "openssl" -version = "0.10.64" +version = "0.10.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" +checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.6.0", "cfg-if 1.0.0", "foreign-types", "libc", @@ -1736,7 +1754,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.72", ] [[package]] @@ -1747,18 +1765,18 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-src" -version = "300.2.1+3.2.0" +version = "300.3.1+3.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fe476c29791a5ca0d1273c697e96085bbabbbea2ef7afd5617e78a4b40332d3" +checksum = "7259953d42a81bf137fbbd73bd30a8e1914d6dce43c2b90ed575783a22608b91" dependencies = [ "cc", ] [[package]] name = "openssl-sys" -version = "0.9.101" +version = "0.9.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dda2b0f344e78efc2facf7d195d098df0dd72151b26ab98da807afc26c198dff" +checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" dependencies = [ "cc", "libc", @@ -1775,9 +1793,9 @@ checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] name = "ordered-multimap" -version = "0.7.0" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04d84ee66570a6460dc6143a5c4835f3a4179201ce91c25fc717d4eb3dc31db9" +checksum = "49203cdcae0030493bad186b28da2fa25645fa276a51b6fec8010d281e02ef79" dependencies = [ "dlv-list", "hashbrown", @@ -1785,9 +1803,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", @@ -1795,15 +1813,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.9" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if 1.0.0", "libc", - "redox_syscall", + "redox_syscall 0.5.3", "smallvec", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] @@ -1818,11 +1836,11 @@ dependencies = [ [[package]] name = "pem" -version = "3.0.3" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8fcc794035347fb64beda2d3b462595dd2753e3f268d89c5aae77e8cf2c310" +checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae" dependencies = [ - "base64 0.21.7", + "base64 0.22.1", "serde", ] @@ -1843,29 +1861,29 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pin-project" -version = "1.1.3" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.3" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.72", ] [[package]] name = "pin-project-lite" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" @@ -1913,9 +1931,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69d3587f8a9e599cc7ec2c00e331f71c4e69a5f9a4b8a6efd5b07466b9736f9a" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "powerfmt" @@ -1925,9 +1943,12 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "dee4364d9f3b902ef14fab8a1ddffb783a1cb6b4bba3bfc1fa3922732c7de97f" +dependencies = [ + "zerocopy", +] [[package]] name = "predicates" @@ -1945,15 +1966,15 @@ dependencies = [ [[package]] name = "predicates-core" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174" +checksum = "ae8177bee8e75d6846599c6b9ff679ed51e882816914eec639944d7c9aa11931" [[package]] name = "predicates-tree" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368ba315fb8c5052ab692e68a0eefec6ec57b23a36959c14496f0b0df2c0cecf" +checksum = "41b740d195ed3166cd147c8047ec98db0e22ec019eb8eeb76d343b795304fb13" dependencies = [ "predicates-core", "termtree", @@ -1961,9 +1982,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.75" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "907a61bd0f64c2f29cd1cf1dc34d05176426a3f504a78010f08416ddb7b13708" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] @@ -2005,7 +2026,7 @@ dependencies = [ "quinn-proto", "quinn-udp", "rustc-hash", - "rustls 0.23.10", + "rustls 0.23.12", "thiserror", "tokio", "tracing", @@ -2021,7 +2042,7 @@ dependencies = [ "rand", "ring", "rustc-hash", - "rustls 0.23.10", + "rustls 0.23.12", "slab", "thiserror", "tinyvec", @@ -2030,22 +2051,21 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.2" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9096629c45860fc7fb143e125eb826b5e721e10be3263160c7d60ca832cf8c46" +checksum = "8bffec3605b73c6f1754535084a85229fa8a30f86014e6c81aeec4abb68b0285" dependencies = [ "libc", "once_cell", "socket2", - "tracing", "windows-sys 0.52.0", ] [[package]] name = "quote" -version = "1.0.35" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -2100,7 +2120,7 @@ dependencies = [ "rand", "rustls 0.22.4", "rustls-native-certs", - "rustls-pemfile", + "rustls-pemfile 2.1.2", "rustls-pki-types", "ryu", "sha1_smol", @@ -2121,11 +2141,20 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "redox_syscall" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +dependencies = [ + "bitflags 2.6.0", +] + [[package]] name = "redox_users" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" +checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" dependencies = [ "getrandom", "libredox", @@ -2134,9 +2163,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.3" +version = "1.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" dependencies = [ "aho-corasick", "memchr", @@ -2146,9 +2175,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.5" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", @@ -2157,9 +2186,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "reqsign" @@ -2195,9 +2224,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.11.23" +version = "0.11.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" dependencies = [ "base64 0.21.7", "bytes", @@ -2205,9 +2234,9 @@ dependencies = [ "futures-core", "futures-util", "h2 0.3.26", - "http 0.2.11", + "http 0.2.12", "http-body 0.4.6", - "hyper 0.14.28", + "hyper 0.14.30", "hyper-tls 0.5.0", "ipnet", "js-sys", @@ -2217,9 +2246,11 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", + "rustls-pemfile 1.0.4", "serde", "serde_json", "serde_urlencoded", + "sync_wrapper 0.1.2", "system-configuration", "tokio", "tokio-native-tls", @@ -2245,9 +2276,9 @@ dependencies = [ "futures-util", "h2 0.4.5", "http 1.1.0", - "http-body 1.0.0", + "http-body 1.0.1", "http-body-util", - "hyper 1.1.0", + "hyper 1.4.1", "hyper-rustls", "hyper-tls 0.6.0", "hyper-util", @@ -2260,14 +2291,14 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls 0.23.10", + "rustls 0.23.12", "rustls-native-certs", - "rustls-pemfile", + "rustls-pemfile 2.1.2", "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", - "sync_wrapper", + "sync_wrapper 1.0.1", "system-configuration", "tokio", "tokio-native-tls", @@ -2294,38 +2325,17 @@ dependencies = [ [[package]] name = "ring" -version = "0.17.7" +version = "0.17.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", + "cfg-if 1.0.0", "getrandom", "libc", - "spin 0.9.8", + "spin", "untrusted", - "windows-sys 0.48.0", -] - -[[package]] -name = "rouille" -version = "3.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3716fbf57fc1084d7a706adf4e445298d123e4a44294c4e8213caf1b85fcc921" -dependencies = [ - "base64 0.13.1", - "chrono", - "filetime", - "multipart", - "percent-encoding", - "rand", - "serde", - "serde_derive", - "serde_json", - "sha1_smol", - "threadpool", - "time", - "tiny_http", - "url", + "windows-sys 0.52.0", ] [[package]] @@ -2362,9 +2372,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc-hash" @@ -2387,7 +2397,7 @@ version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.6.0", "errno", "libc", "linux-raw-sys", @@ -2410,9 +2420,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.10" +version = "0.23.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05cff451f60db80f490f3c182b77c35260baace73209e9cdbbe526bfe3a4d402" +checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044" dependencies = [ "once_cell", "ring", @@ -2424,17 +2434,26 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f1fb85efa936c42c6d5fc28d2629bb51e4b2f4b8a5211e297d599cc5a093792" +checksum = "a88d6d420651b496bdd98684116959239430022a115c1240e6c3993be0b15fba" dependencies = [ "openssl-probe", - "rustls-pemfile", + "rustls-pemfile 2.1.2", "rustls-pki-types", "schannel", "security-framework", ] +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", +] + [[package]] name = "rustls-pemfile" version = "2.1.2" @@ -2453,9 +2472,9 @@ checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" [[package]] name = "rustls-webpki" -version = "0.102.4" +version = "0.102.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff448f7e92e913c4b7d4c6d8e4540a1724b319b4152b8aef6d4cf8339712b33e" +checksum = "8e6b52d4fda176fd835fdc55a835d4a89b8499cad995885a21149d5ad62f852e" dependencies = [ "ring", "rustls-pki-types", @@ -2475,15 +2494,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" - -[[package]] -name = "safemem" -version = "0.3.3" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "salsa20" @@ -2505,9 +2518,9 @@ dependencies = [ [[package]] name = "scc" -version = "2.1.0" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec96560eea317a9cc4e0bb1f6a2c93c09a19b8c4fc5cb3fcc0ec1c094cd783e2" +checksum = "05ccfb12511cdb770157ace92d7dda771e498445b78f9886e8cdbc5140a4eced" dependencies = [ "sdd", ] @@ -2539,7 +2552,7 @@ dependencies = [ "gzp", "http 1.1.0", "http-body-util", - "hyper 1.1.0", + "hyper 1.4.1", "hyper-util", "is-terminal", "itertools", @@ -2552,10 +2565,11 @@ dependencies = [ "memchr", "memmap2", "mime", + "native-tls", "nix 0.28.0", "num_cpus", "number_prefix", - "object", + "object 0.32.2", "once_cell", "opendal", "openssl", @@ -2565,7 +2579,6 @@ dependencies = [ "reqsign", "reqwest 0.12.5", "retry", - "rouille", "semver", "serde", "serde_json", @@ -2578,6 +2591,7 @@ dependencies = [ "tempfile", "test-case", "thirtyfour_sync", + "thiserror", "tokio", "tokio-serde", "tokio-util", @@ -2587,6 +2601,7 @@ dependencies = [ "uuid", "version-compare", "walkdir", + "warp", "which", "windows-sys 0.52.0", "zip", @@ -2602,6 +2617,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + [[package]] name = "scopeguard" version = "1.2.0" @@ -2621,17 +2642,17 @@ dependencies = [ [[package]] name = "sdd" -version = "0.2.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b84345e4c9bd703274a082fb80caaa99b7612be48dfaa1dd9266577ec412309d" +checksum = "177258b64c0faaa9ffd3c65cd3262c2bc7e2588dbbd9c1641d0346145c1bbda8" [[package]] name = "security-framework" -version = "2.9.2" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.6.0", "core-foundation", "core-foundation-sys", "libc", @@ -2640,9 +2661,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.9.1" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" +checksum = "75da29fe9b9b08fe9d6b22b5b4bcbc75d8db3aa31e639aa56bb62e9d46bfceaf" dependencies = [ "core-foundation-sys", "libc", @@ -2656,52 +2677,53 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.201" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "780f1cebed1629e4753a1a38a3c72d30b97ec044f0aef68cb26650a3c5cf363c" +checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.201" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e405930b9796f1c00bee880d03fc7e0bb4b9a11afc776885ffe84320da2865" +checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.72", ] [[package]] name = "serde_json" -version = "1.0.114" +version = "1.0.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" +checksum = "784b6203951c57ff748476b126ccb5e8e2959a5c19e5c617ab1956be3dbc68da" dependencies = [ "indexmap", "itoa", + "memchr", "ryu", "serde", ] [[package]] name = "serde_repr" -version = "0.1.18" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb" +checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.72", ] [[package]] name = "serde_spanned" -version = "0.6.5" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" +checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" dependencies = [ "serde", ] @@ -2720,9 +2742,9 @@ dependencies = [ [[package]] name = "serial_test" -version = "3.1.0" +version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb86f9315df5df6a70eae0cc22395a44e544a0d8897586820770a35ede74449" +checksum = "4b4b487fe2acf240a021cf57c6b2b4903b1e78ca0ecd862a71b71d2a51fed77d" dependencies = [ "futures", "log", @@ -2734,13 +2756,13 @@ dependencies = [ [[package]] name = "serial_test_derive" -version = "3.1.0" +version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9bb72430492e9549b0c4596725c0f82729bff861c45aa8099c0a8e67fc3b721" +checksum = "82fe9db325bcef1fbcde82e078a5cc4efdf787e96b3b9cf45b50b529f2083d67" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.72", ] [[package]] @@ -2756,9 +2778,9 @@ dependencies = [ [[package]] name = "sha1_smol" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" +checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d" [[package]] name = "sha2" @@ -2773,9 +2795,9 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" dependencies = [ "libc", ] @@ -2813,26 +2835,20 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.2" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" -version = "0.5.5" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" dependencies = [ "libc", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] -[[package]] -name = "spin" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" - [[package]] name = "spin" version = "0.9.8" @@ -2878,15 +2894,15 @@ dependencies = [ [[package]] name = "strsim" -version = "0.10.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "subtle" -version = "2.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" @@ -2901,15 +2917,21 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.48" +version = "2.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" 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 = "sync_wrapper" version = "1.0.1" @@ -2918,9 +2940,9 @@ checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" [[package]] name = "syslog" -version = "6.1.0" +version = "6.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7434e95bcccce1215d30f4bf84fe8c00e8de1b9be4fb736d747ca53d36e7f96f" +checksum = "dfc7e95b5b795122fafe6519e27629b5ab4232c73ebb2428f568e82b1a457ad3" dependencies = [ "error-chain", "hostname", @@ -2952,9 +2974,9 @@ dependencies = [ [[package]] name = "tar" -version = "0.4.40" +version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16afcea1f22891c49a00c751c7b63b2233284064f11a200fc624137c51e2ddb" +checksum = "cb797dad5fb5b76fcf519e702f4a589483b5ef06567f160c392832c1f5e44909" dependencies = [ "filetime", "libc", @@ -2984,9 +3006,9 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ "winapi-util", ] @@ -3025,7 +3047,7 @@ dependencies = [ "cfg-if 1.0.0", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.72", ] [[package]] @@ -3036,7 +3058,7 @@ checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.72", "test-case-core", ] @@ -3052,7 +3074,7 @@ dependencies = [ "displaydoc", "futures", "log", - "reqwest 0.11.23", + "reqwest 0.11.27", "serde", "serde_json", "serde_repr", @@ -3070,7 +3092,7 @@ checksum = "ab1e47e6c2fed609d851c6f6171a559ecffb1d121f2d6e02dd390e90ea2c3d38" dependencies = [ "base64 0.13.1", "log", - "reqwest 0.11.23", + "reqwest 0.11.27", "serde", "serde_json", "stringmatch", @@ -3079,31 +3101,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.56" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.56" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", -] - -[[package]] -name = "threadpool" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" -dependencies = [ - "num_cpus", + "syn 2.0.72", ] [[package]] @@ -3148,25 +3161,11 @@ dependencies = [ "crunchy", ] -[[package]] -name = "tiny_http" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389915df6413a2e74fb181895f933386023c71110878cd0825588928e64cdc82" -dependencies = [ - "ascii", - "chunked_transfer", - "httpdate", - "log", - "openssl", - "zeroize", -] - [[package]] name = "tinyvec" -version = "1.6.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" dependencies = [ "tinyvec_macros", ] @@ -3179,32 +3178,31 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.37.0" +version = "1.39.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" +checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" dependencies = [ "backtrace", "bytes", "libc", "mio", - "num_cpus", "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "tokio-macros" -version = "2.2.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.72", ] [[package]] @@ -3245,7 +3243,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.23.10", + "rustls 0.23.12", "rustls-pki-types", "tokio", ] @@ -3262,25 +3260,36 @@ dependencies = [ "pin-project", ] +[[package]] +name = "tokio-tungstenite" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c83b561d025642014097b66e6c1bb422783339e0909e4429cde4749d1990bc38" +dependencies = [ + "futures-util", + "log", + "tokio", + "tungstenite", +] + [[package]] name = "tokio-util" -version = "0.7.10" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" +checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" dependencies = [ "bytes", "futures-core", "futures-sink", "pin-project-lite", "tokio", - "tracing", ] [[package]] name = "toml" -version = "0.8.10" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a9aad4a3066010876e8dcf5a8a06e70a558751117a145c6ce2b82c2e2054290" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" dependencies = [ "serde", "serde_spanned", @@ -3290,18 +3299,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.5" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.22.6" +version = "0.22.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c1b5fd4128cc8d3e0cb74d4ed9a9cc7c7284becd4df68f5f940e1ad123606f6" +checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" dependencies = [ "indexmap", "serde", @@ -3358,7 +3367,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.72", ] [[package]] @@ -3383,12 +3392,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] -name = "twoway" -version = "0.1.8" +name = "tungstenite" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59b11b2b5241ba34be09c3cc85a36e56e48f9888862e19cedf23336d35316ed1" +checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1" dependencies = [ - "memchr", + "byteorder", + "bytes", + "data-encoding", + "http 1.1.0", + "httparse", + "log", + "rand", + "sha1", + "thiserror", + "url", + "utf-8", ] [[package]] @@ -3418,9 +3437,9 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" @@ -3430,9 +3449,9 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" dependencies = [ "tinyvec", ] @@ -3445,9 +3464,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.0" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" dependencies = [ "form_urlencoded", "idna", @@ -3460,17 +3479,23 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "110352d4e9076c67839003c7788d8604e24dcded13e0b375af3efaa8cf468517" +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + [[package]] name = "utf8parse" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ea73390fe27785838dcbf75b91b1d84799e28f1ce71e6f372a5dc2200c80de5" +checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" dependencies = [ "getrandom", "serde", @@ -3490,9 +3515,9 @@ checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "void" @@ -3512,9 +3537,9 @@ dependencies = [ [[package]] name = "vte_generate_state_changes" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d257817081c7dffcdbab24b9e62d2def62e2ff7d00b1c20062551e6cccc145ff" +checksum = "2e369bee1b05d510a7b4ed645f5faa90619e05437111783ea5848f28d97d3c2e" dependencies = [ "proc-macro2", "quote", @@ -3548,6 +3573,37 @@ dependencies = [ "try-lock", ] +[[package]] +name = "warp" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4378d202ff965b011c64817db11d5829506d3404edeadb61f190d111da3f231c" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "headers", + "http 0.2.12", + "hyper 0.14.30", + "log", + "mime", + "mime_guess", + "multer", + "percent-encoding", + "pin-project", + "rustls-pemfile 2.1.2", + "scoped-tls", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-rustls 0.25.0", + "tokio-tungstenite", + "tokio-util", + "tower-service", + "tracing", +] + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -3556,9 +3612,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.89" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ "cfg-if 1.0.0", "wasm-bindgen-macro", @@ -3566,24 +3622,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.89" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.72", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.39" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" dependencies = [ "cfg-if 1.0.0", "js-sys", @@ -3593,9 +3649,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.89" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3603,22 +3659,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.89" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.72", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.89" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "wasm-streams" @@ -3635,9 +3691,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.66" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" dependencies = [ "js-sys", "wasm-bindgen", @@ -3645,24 +3701,23 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.26.2" +version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c452ad30530b54a4d8e71952716a212b08efd0f3562baa66c29a618b07da7c3" +checksum = "bd7c23921eeb1713a4e851530e9b9756e4fb0e89978582942612524cf09f01cd" dependencies = [ "rustls-pki-types", ] [[package]] name = "which" -version = "6.0.0" +version = "6.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fa5e0c10bf77f44aac573e498d1a82d5fbd5e91f6fc0a99e7be4b38e85e101c" +checksum = "3d9c5ed668ee1f17edb3b627225343d210006a90bb1e3745ce1f30b1fb115075" dependencies = [ "either", "home", - "once_cell", "rustix", - "windows-sys 0.52.0", + "winsafe", ] [[package]] @@ -3702,7 +3757,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.0", + "windows-targets 0.52.6", ] [[package]] @@ -3720,7 +3775,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.0", + "windows-targets 0.52.6", ] [[package]] @@ -3740,17 +3795,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] @@ -3761,9 +3817,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" @@ -3773,9 +3829,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" @@ -3785,9 +3841,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" @@ -3797,9 +3859,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" @@ -3809,9 +3871,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" @@ -3821,9 +3883,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" @@ -3833,15 +3895,15 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.6.1" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d90f4e0f530c4c69f62b80d839e9ef3855edc9cba471a160c4d692deed62b401" +checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" dependencies = [ "memchr", ] @@ -3866,22 +3928,49 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "winsafe" +version = "0.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" + [[package]] name = "xattr" -version = "1.2.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "914566e6413e7fa959cc394fb30e563ba80f3541fbd40816d4c05a0fc3f2a0f1" +checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" dependencies = [ "libc", "linux-raw-sys", "rustix", ] +[[package]] +name = "zerocopy" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "854e949ac82d619ee9a14c66a1b674ac730422372ccb759ce0c39cabcf2bf8e6" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "125139de3f6b9d625c39e2efdd73d41bdac468ccd556556440e322be0e1bbd91" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + [[package]] name = "zeroize" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" [[package]] name = "zip" @@ -3896,27 +3985,27 @@ dependencies = [ [[package]] name = "zstd" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d789b1514203a1120ad2429eae43a7bd32b90976a7bb8a05f7ec02fa88cc23a" +checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" dependencies = [ "zstd-safe", ] [[package]] name = "zstd-safe" -version = "7.1.0" +version = "7.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd99b45c6bc03a018c8b8a86025678c87e55526064e38f9df301989dce7ec0a" +checksum = "fa556e971e7b568dc775c136fc9de8c779b1c2fc3a63defaafadffdbd3181afa" dependencies = [ "zstd-sys", ] [[package]] name = "zstd-sys" -version = "2.0.10+zstd.1.5.6" +version = "2.0.12+zstd.1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c253a4914af5bafc8fa8c86ee400827e83cf6ec01195ec1f1ed8441bf00d65aa" +checksum = "0a4e40c320c3cb459d9a9ff6de98cff88f4751ee9275d140e2be94a2b74e4c13" dependencies = [ "cc", "pkg-config", diff --git a/Cargo.toml b/Cargo.toml index 9437e7369..8a9c60a15 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -71,7 +71,7 @@ regex = "1.10.3" reqsign = { version = "0.16.0", optional = true } reqwest = { version = "0.12", features = [ "json", - "blocking", + "native-tls", "stream", "rustls-tls", "rustls-tls-native-roots", @@ -107,6 +107,7 @@ zstd = "0.13" # dist-server only memmap2 = "0.9.4" +native-tls = "0.2.8" nix = { version = "0.28.0", optional = true, features = [ "mount", "user", @@ -115,11 +116,10 @@ nix = { version = "0.28.0", optional = true, features = [ "process", ] } object = "0.32" -rouille = { version = "3.6", optional = true, default-features = false, features = [ - "ssl", -] } syslog = { version = "6", optional = true } +thiserror = { version = "1.0.30", optional = true } version-compare = { version = "0.1.1", optional = true } +warp = { version = "0.3.2", optional = true, features = ["tls"] } [dev-dependencies] assert_cmd = "2.0.13" @@ -190,15 +190,17 @@ dist-client = [ ] # Enables the sccache-dist binary dist-server = [ + "reqwest/blocking", "jwt", "flate2", "libmount", "nix", "openssl", "reqwest", - "rouille", "syslog", "version-compare", + "warp", + "thiserror", ] # Enables dist tests with external requirements dist-tests = ["dist-client", "dist-server"] diff --git a/src/bin/sccache-dist/build.rs b/src/bin/sccache-dist/build.rs index 815674661..33f9f6d3c 100644 --- a/src/bin/sccache-dist/build.rs +++ b/src/bin/sccache-dist/build.rs @@ -231,7 +231,7 @@ impl OverlayBuilder { for (tc, _) in entries { warn!("Removing old un-compressed toolchain: {:?}", tc); assert!(toolchain_dir_map.remove(tc).is_some()); - fs::remove_dir_all(&self.dir.join("toolchains").join(&tc.archive_id)) + fs::remove_dir_all(self.dir.join("toolchains").join(&tc.archive_id)) .context("Failed to remove old toolchain directory")?; } } diff --git a/src/bin/sccache-dist/main.rs b/src/bin/sccache-dist/main.rs index 83d530060..365b54e07 100644 --- a/src/bin/sccache-dist/main.rs +++ b/src/bin/sccache-dist/main.rs @@ -2,7 +2,9 @@ extern crate log; use anyhow::{bail, Context, Error, Result}; +use async_trait::async_trait; use base64::Engine; +use cmdline::{AuthSubcommand, Command}; use rand::{rngs::OsRng, RngCore}; use sccache::config::{ scheduler as scheduler_config, server as server_config, INSECURE_DIST_CLIENT_TOKEN, @@ -22,8 +24,9 @@ use std::env; use std::io; use std::path::Path; use std::sync::atomic::{AtomicUsize, Ordering}; -use std::sync::{Mutex, MutexGuard}; +use std::sync::{Arc, Mutex, MutexGuard}; use std::time::{Duration, Instant}; +use tokio::runtime::Runtime; #[cfg_attr(target_os = "freebsd", path = "build_freebsd.rs")] mod build; @@ -31,8 +34,6 @@ mod build; mod cmdline; mod token_check; -use cmdline::{AuthSubcommand, Command}; - pub const INSECURE_DIST_SERVER_TOKEN: &str = "dangerously_insecure_server"; // Only supported on x86_64 Linux machines and on FreeBSD @@ -184,10 +185,10 @@ fn run(command: Command) -> Result { scheduler_config::ServerAuth::Insecure => { warn!("Scheduler starting with DANGEROUSLY_INSECURE server authentication"); let token = INSECURE_DIST_SERVER_TOKEN; - Box::new(move |server_token| check_server_token(server_token, token)) + Arc::new(move |server_token| check_server_token(server_token, token)) } scheduler_config::ServerAuth::Token { token } => { - Box::new(move |server_token| check_server_token(server_token, &token)) + Arc::new(move |server_token| check_server_token(server_token, &token)) } scheduler_config::ServerAuth::JwtHS256 { secret_key } => { let secret_key = BASE64_URL_SAFE_ENGINE @@ -203,7 +204,7 @@ fn run(command: Command) -> Result { validation.validate_nbf = false; validation }; - Box::new(move |server_token| { + Arc::new(move |server_token| { check_jwt_server_token(server_token, &secret_key, &validation) }) } @@ -217,7 +218,10 @@ fn run(command: Command) -> Result { check_client_auth, check_server_auth, ); - http_scheduler.start()?; + + // Create runtime after daemonize because Tokio doesn't work well with daemonize + let runtime = Runtime::new().context("Failed to create Tokio runtime")?; + runtime.block_on(async { http_scheduler.start().await })?; unreachable!(); } @@ -294,7 +298,8 @@ fn run(command: Command) -> Result { server, ) .context("Failed to create sccache HTTP server instance")?; - http_server.start()?; + let runtime = Runtime::new().context("Failed to create Tokio runtime")?; + runtime.block_on(async { http_server.start().await })?; unreachable!(); } } @@ -399,8 +404,9 @@ impl Default for Scheduler { } } +#[async_trait] impl SchedulerIncoming for Scheduler { - fn handle_alloc_job( + async fn handle_alloc_job( &self, requester: &dyn SchedulerOutgoing, tc: Toolchain, @@ -499,6 +505,7 @@ impl SchedulerIncoming for Scheduler { need_toolchain, } = requester .do_assign_job(server_id, job_id, tc, auth.clone()) + .await .with_context(|| { // LOCKS let mut servers = self.servers.lock().unwrap(); @@ -717,7 +724,7 @@ impl SchedulerIncoming for Scheduler { pub struct Server { builder: Box, cache: Mutex, - job_toolchains: Mutex>, + job_toolchains: tokio::sync::Mutex>, } impl Server { @@ -731,18 +738,19 @@ impl Server { Ok(Server { builder, cache: Mutex::new(cache), - job_toolchains: Mutex::new(HashMap::new()), + job_toolchains: tokio::sync::Mutex::new(HashMap::new()), }) } } +#[async_trait] impl ServerIncoming for Server { - fn handle_assign_job(&self, job_id: JobId, tc: Toolchain) -> Result { + async fn handle_assign_job(&self, job_id: JobId, tc: Toolchain) -> Result { let need_toolchain = !self.cache.lock().unwrap().contains_toolchain(&tc); assert!(self .job_toolchains .lock() - .unwrap() + .await .insert(job_id, tc) .is_none()); let state = if need_toolchain { @@ -756,18 +764,19 @@ impl ServerIncoming for Server { need_toolchain, }) } - fn handle_submit_toolchain( + async fn handle_submit_toolchain( &self, requester: &dyn ServerOutgoing, job_id: JobId, - tc_rdr: ToolchainReader, + tc_rdr: ToolchainReader<'_>, ) -> Result { requester .do_update_job_state(job_id, JobState::Ready) + .await .context("Updating job state failed")?; // TODO: need to lock the toolchain until the container has started // TODO: can start prepping container - let tc = match self.job_toolchains.lock().unwrap().get(&job_id).cloned() { + let tc = match self.job_toolchains.lock().await.get(&job_id).cloned() { Some(tc) => tc, None => return Ok(SubmitToolchainResult::JobNotFound), }; @@ -783,18 +792,19 @@ impl ServerIncoming for Server { .map(|_| SubmitToolchainResult::Success) .unwrap_or(SubmitToolchainResult::CannotCache)) } - fn handle_run_job( + async fn handle_run_job( &self, requester: &dyn ServerOutgoing, job_id: JobId, command: CompileCommand, outputs: Vec, - inputs_rdr: InputsReader, + inputs_rdr: InputsReader<'_>, ) -> Result { requester .do_update_job_state(job_id, JobState::Started) + .await .context("Updating job state failed")?; - let tc = self.job_toolchains.lock().unwrap().remove(&job_id); + let tc = self.job_toolchains.lock().await.remove(&job_id); let res = match tc { None => Ok(RunJobResult::JobNotFound), Some(tc) => { @@ -812,6 +822,7 @@ impl ServerIncoming for Server { }; requester .do_update_job_state(job_id, JobState::Complete) + .await .context("Updating job state failed")?; res } diff --git a/src/bin/sccache-dist/token_check.rs b/src/bin/sccache-dist/token_check.rs index e335ae313..cd66f8deb 100644 --- a/src/bin/sccache-dist/token_check.rs +++ b/src/bin/sccache-dist/token_check.rs @@ -1,7 +1,9 @@ use anyhow::{bail, Context, Result}; +use async_trait::async_trait; use base64::Engine; use sccache::dist::http::{ClientAuthCheck, ClientVisibleMsg}; -use sccache::util::{new_reqwest_blocking_client, BASE64_URL_SAFE_ENGINE}; +use sccache::util::new_reqwest_client; +use sccache::util::BASE64_URL_SAFE_ENGINE; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::result::Result as StdResult; @@ -54,8 +56,9 @@ pub struct EqCheck { s: String, } +#[async_trait] impl ClientAuthCheck for EqCheck { - fn check(&self, token: &str) -> StdResult<(), ClientVisibleMsg> { + async fn check(&self, token: &str) -> StdResult<(), ClientVisibleMsg> { if self.s == token { Ok(()) } else { @@ -80,14 +83,15 @@ const MOZ_USERINFO_ENDPOINT: &str = "https://auth.mozilla.auth0.com/userinfo"; /// Mozilla-specific check by forwarding the token onto the auth0 userinfo endpoint pub struct MozillaCheck { // token, token_expiry - auth_cache: Mutex>, - client: reqwest::blocking::Client, + auth_cache: tokio::sync::Mutex>, + client: reqwest::Client, required_groups: Vec, } +#[async_trait] impl ClientAuthCheck for MozillaCheck { - fn check(&self, token: &str) -> StdResult<(), ClientVisibleMsg> { - self.check_mozilla(token).map_err(|e| { + async fn check(&self, token: &str) -> StdResult<(), ClientVisibleMsg> { + self.check_mozilla(token).await.map_err(|e| { warn!("Mozilla token validation failed: {}", e); ClientVisibleMsg::from_nonsensitive( "Failed to validate Mozilla OAuth token, run sccache --dist-auth".to_owned(), @@ -99,13 +103,13 @@ impl ClientAuthCheck for MozillaCheck { impl MozillaCheck { pub fn new(required_groups: Vec) -> Self { Self { - auth_cache: Mutex::new(HashMap::new()), - client: new_reqwest_blocking_client(), + auth_cache: tokio::sync::Mutex::new(HashMap::new()), + client: new_reqwest_client(), required_groups, } } - fn check_mozilla(&self, token: &str) -> Result<()> { + async fn check_mozilla(&self, token: &str) -> Result<()> { // azp == client_id // { // "iss": "https://auth.mozilla.auth0.com/", @@ -139,7 +143,7 @@ impl MozillaCheck { } // If the token is cached and not expired, return it - let mut auth_cache = self.auth_cache.lock().unwrap(); + let mut auth_cache = self.auth_cache.lock().await; if let Some(cached_at) = auth_cache.get(token) { if cached_at.elapsed() < MOZ_SESSION_TIMEOUT { return Ok(()); @@ -158,10 +162,12 @@ impl MozillaCheck { .get(url.clone()) .bearer_auth(token) .send() + .await .context("Failed to make request to mozilla userinfo")?; let status = res.status(); let res_text = res .text() + .await .context("Failed to interpret response from mozilla userinfo as string")?; if !status.is_success() { bail!("JWT forwarded to {} returned {}: {}", url, status, res_text) @@ -245,14 +251,15 @@ fn test_auth_verify_check_mozilla_profile() { // Don't check a token is valid (it may not even be a JWT) just forward it to // an API and check for success pub struct ProxyTokenCheck { - client: reqwest::blocking::Client, + client: reqwest::Client, maybe_auth_cache: Option, Duration)>>, url: String, } +#[async_trait] impl ClientAuthCheck for ProxyTokenCheck { - fn check(&self, token: &str) -> StdResult<(), ClientVisibleMsg> { - match self.check_token_with_forwarding(token) { + async fn check(&self, token: &str) -> StdResult<(), ClientVisibleMsg> { + match self.check_token_with_forwarding(token).await { Ok(()) => Ok(()), Err(e) => { warn!("Proxying token validation failed: {}", e); @@ -269,13 +276,13 @@ impl ProxyTokenCheck { let maybe_auth_cache: Option, Duration)>> = cache_secs.map(|secs| Mutex::new((HashMap::new(), Duration::from_secs(secs)))); Self { - client: new_reqwest_blocking_client(), + client: new_reqwest_client(), maybe_auth_cache, url, } } - fn check_token_with_forwarding(&self, token: &str) -> Result<()> { + async fn check_token_with_forwarding(&self, token: &str) -> Result<()> { trace!("Validating token by forwarding to {}", self.url); // If the token is cached and not cache has not expired, return it if let Some(ref auth_cache) = self.maybe_auth_cache { @@ -294,6 +301,7 @@ impl ProxyTokenCheck { .get(&self.url) .bearer_auth(token) .send() + .await .context("Failed to make request to proxying url")?; if !res.status().is_success() { bail!("Token forwarded to {} returned {}", self.url, res.status()); @@ -315,8 +323,9 @@ pub struct ValidJWTCheck { kid_to_pkcs1: HashMap>, } +#[async_trait] impl ClientAuthCheck for ValidJWTCheck { - fn check(&self, token: &str) -> StdResult<(), ClientVisibleMsg> { + async fn check(&self, token: &str) -> StdResult<(), ClientVisibleMsg> { match self.check_jwt_validity(token) { Ok(()) => Ok(()), Err(e) => { diff --git a/src/compiler/compiler.rs b/src/compiler/compiler.rs index a37d20775..c9ecba42e 100644 --- a/src/compiler/compiler.rs +++ b/src/compiler/compiler.rs @@ -1460,7 +1460,6 @@ mod test { use std::io::{Cursor, Write}; use std::sync::Arc; use std::time::Duration; - use std::u64; use test_case::test_case; use tokio::runtime::Runtime; diff --git a/src/compiler/rust.rs b/src/compiler/rust.rs index c72fdc51b..2b58f254d 100644 --- a/src/compiler/rust.rs +++ b/src/compiler/rust.rs @@ -34,7 +34,6 @@ use fs_err as fs; use log::Level::Trace; use once_cell::sync::Lazy; #[cfg(feature = "dist-client")] -#[cfg(feature = "dist-client")] use std::borrow::Borrow; use std::borrow::Cow; #[cfg(feature = "dist-client")] diff --git a/src/dist/client_auth.rs b/src/dist/client_auth.rs index 5555411c0..6cf9acb33 100644 --- a/src/dist/client_auth.rs +++ b/src/dist/client_auth.rs @@ -85,7 +85,7 @@ mod code_grant_pkce { html_response, json_response, query_pairs, MIN_TOKEN_VALIDITY, MIN_TOKEN_VALIDITY_WARNING, REDIRECT_WITH_AUTH_JSON, }; - use crate::util::new_reqwest_blocking_client; + use crate::util::new_reqwest_client; use crate::util::BASE64_URL_SAFE_ENGINE; use base64::Engine; use bytes::Bytes; @@ -232,7 +232,7 @@ mod code_grant_pkce { Ok(response) } - pub fn code_to_token( + pub async fn code_to_token( token_url: &str, client_id: &str, code_verifier: &str, @@ -246,8 +246,8 @@ mod code_grant_pkce { grant_type: GRANT_TYPE_PARAM_VALUE, redirect_uri, }; - let client = new_reqwest_blocking_client(); - let res = client.post(token_url).json(&token_request).send()?; + let client = new_reqwest_client(); + let res = client.post(token_url).json(&token_request).send().await?; if !res.status().is_success() { bail!( "Sending code to {} failed, HTTP error: {}", @@ -258,6 +258,7 @@ mod code_grant_pkce { let (token, expires_at) = handle_token_response( res.json() + .await .context("Failed to parse token response as JSON")?, )?; if expires_at - Instant::now() < MIN_TOKEN_VALIDITY { @@ -585,8 +586,12 @@ pub fn get_token_oauth2_code_grant_pkce( let code = code_rx .try_recv() .expect("Hyper shutdown but code not available - internal error"); - code_grant_pkce::code_to_token(token_url, client_id, &verifier, &code, &redirect_uri) - .context("Failed to convert oauth2 code into a token") + + runtime.block_on(async move { + code_grant_pkce::code_to_token(token_url, client_id, &verifier, &code, &redirect_uri) + .await + .context("Failed to convert oauth2 code into a token") + }) } // https://auth0.com/docs/api-auth/tutorials/implicit-grant diff --git a/src/dist/http.rs b/src/dist/http.rs index 621fe8277..312ba73b3 100644 --- a/src/dist/http.rs +++ b/src/dist/http.rs @@ -36,21 +36,6 @@ mod common { fn bincode(self, bincode: &T) -> Result; fn bytes(self, bytes: Vec) -> Self; } - impl ReqwestRequestBuilderExt for reqwest::blocking::RequestBuilder { - fn bincode(self, bincode: &T) -> Result { - let bytes = - bincode::serialize(bincode).context("Failed to serialize body to bincode")?; - Ok(self.bytes(bytes)) - } - fn bytes(self, bytes: Vec) -> Self { - self.header( - header::CONTENT_TYPE, - mime::APPLICATION_OCTET_STREAM.to_string(), - ) - .header(header::CONTENT_LENGTH, bytes.len()) - .body(bytes) - } - } impl ReqwestRequestBuilderExt for reqwest::RequestBuilder { fn bincode(self, bincode: &T) -> Result { let bytes = @@ -67,7 +52,7 @@ mod common { } } - #[cfg(feature = "dist-client")] + #[cfg(any(feature = "dist-server", feature = "dist-client"))] pub async fn bincode_req_fut( req: reqwest::RequestBuilder, ) -> Result { @@ -243,62 +228,37 @@ pub mod urls { #[cfg(feature = "dist-server")] mod server { - use crate::util::new_reqwest_blocking_client; - use byteorder::{BigEndian, ReadBytesExt}; - use flate2::read::ZlibDecoder as ZlibReadDecoder; use once_cell::sync::Lazy; use rand::{rngs::OsRng, RngCore}; - use rouille::accept; use serde::Serialize; use std::collections::HashMap; use std::convert::Infallible; - use std::io::Read; use std::net::SocketAddr; use std::result::Result as StdResult; - use std::sync::atomic; - use std::sync::Mutex; - use std::thread; + use std::sync::Arc; use std::time::Duration; use super::common::{ - AllocJobHttpResponse, HeartbeatServerHttpRequest, JobJwt, ReqwestRequestBuilderExt, - RunJobHttpRequest, ServerCertificateHttpResponse, + bincode_req_fut, AllocJobHttpResponse, HeartbeatServerHttpRequest, JobJwt, + ReqwestRequestBuilderExt, RunJobHttpRequest, ServerCertificateHttpResponse, }; use super::urls; use crate::dist::{ - self, AllocJobResult, AssignJobResult, HeartbeatServerResult, InputsReader, JobAuthorizer, - JobId, JobState, RunJobResult, SchedulerStatusResult, ServerId, ServerNonce, - SubmitToolchainResult, Toolchain, ToolchainReader, UpdateJobStateResult, + self, AssignJobResult, HeartbeatServerResult, JobId, JobState, ServerId, ServerNonce, + Toolchain, UpdateJobStateResult, }; use crate::errors::*; + use crate::util::new_reqwest_client; const HEARTBEAT_INTERVAL: Duration = Duration::from_secs(30); const HEARTBEAT_ERROR_INTERVAL: Duration = Duration::from_secs(10); pub const HEARTBEAT_TIMEOUT: Duration = Duration::from_secs(90); + use async_trait::async_trait; + use tokio::sync::Mutex; - pub fn bincode_req( - req: reqwest::blocking::RequestBuilder, - ) -> Result { - // Work around tiny_http issue #151 by disabling HTTP pipeline with - // `Connection: close`. - let mut res = req.header(reqwest::header::CONNECTION, "close").send()?; - let status = res.status(); - let mut body = vec![]; - res.copy_to(&mut body) - .context("error reading response body")?; - if !status.is_success() { - Err(anyhow!( - "Error {} (Headers={:?}): {}", - status.as_u16(), - res.headers(), - String::from_utf8_lossy(&body) - )) - } else { - bincode::deserialize(&body).map_err(Into::into) - } - } - - fn create_https_cert_and_privkey(addr: SocketAddr) -> Result<(Vec, Vec, Vec)> { + pub(crate) fn create_https_cert_and_privkey( + addr: SocketAddr, + ) -> Result<(Vec, Vec, Vec)> { let rsa_key = openssl::rsa::Rsa::::generate(2048) .context("failed to generate rsa privkey")?; let privkey_pem = rsa_key @@ -387,10 +347,11 @@ mod server { } } + #[async_trait] pub trait ClientAuthCheck: Send + Sync { - fn check(&self, token: &str) -> StdResult<(), ClientVisibleMsg>; + async fn check(&self, token: &str) -> StdResult<(), ClientVisibleMsg>; } - pub type ServerAuthCheck = Box Option + Send + Sync>; + pub type ServerAuthCheck = Arc Option + Send + Sync>; const JWT_KEY_LENGTH: usize = 256 / 8; static JWT_HEADER: Lazy = Lazy::new(|| jwt::Header::new(jwt::Algorithm::HS256)); @@ -402,65 +363,6 @@ mod server { validation }); - // Based on rouille::input::json::json_input - #[derive(Debug)] - pub enum RouilleBincodeError { - BodyAlreadyExtracted, - WrongContentType, - ParseError(bincode::Error), - } - impl From for RouilleBincodeError { - fn from(err: bincode::Error) -> RouilleBincodeError { - RouilleBincodeError::ParseError(err) - } - } - impl std::error::Error for RouilleBincodeError { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - match *self { - RouilleBincodeError::ParseError(ref e) => Some(e), - _ => None, - } - } - } - impl std::fmt::Display for RouilleBincodeError { - fn fmt( - &self, - fmt: &mut std::fmt::Formatter<'_>, - ) -> std::result::Result<(), std::fmt::Error> { - write!( - fmt, - "{}", - match *self { - RouilleBincodeError::BodyAlreadyExtracted => { - "the body of the request was already extracted" - } - RouilleBincodeError::WrongContentType => { - "the request didn't have a binary content type" - } - RouilleBincodeError::ParseError(_) => "error while parsing the bincode body", - } - ) - } - } - fn bincode_input(request: &rouille::Request) -> std::result::Result - where - O: serde::de::DeserializeOwned, - { - if let Some(header) = request.header("Content-Type") { - if !header.starts_with("application/octet-stream") { - return Err(RouilleBincodeError::WrongContentType); - } - } else { - return Err(RouilleBincodeError::WrongContentType); - } - - if let Some(mut b) = request.data() { - bincode::deserialize_from::<_, O>(&mut b).map_err(From::from) - } else { - Err(RouilleBincodeError::BodyAlreadyExtracted) - } - } - // Based on try_or_400 in rouille, but with logging #[derive(Serialize)] pub struct ErrJson { @@ -481,122 +383,14 @@ mod server { serde_json::to_string(&self).expect("infallible serialization for ErrJson failed") } } - macro_rules! try_or_err_and_log { - ($reqid:expr, $code:expr, $result:expr) => { - match $result { - Ok(r) => r, - Err(err) => { - // TODO: would ideally just use error_chain - #[allow(unused_imports)] - use std::error::Error; - let mut err_msg = err.to_string(); - let mut maybe_cause = err.source(); - while let Some(cause) = maybe_cause { - err_msg.push_str(", caused by: "); - err_msg.push_str(&cause.to_string()); - maybe_cause = cause.source(); - } - - warn!("Res {} error: {}", $reqid, err_msg); - let err: Box = err.into(); - let json = ErrJson::from_err(&*err); - return rouille::Response::json(&json).with_status_code($code); - } - } - }; - } - macro_rules! try_or_400_log { - ($reqid:expr, $result:expr) => { - try_or_err_and_log!($reqid, 400, $result) - }; - } - macro_rules! try_or_500_log { - ($reqid:expr, $result:expr) => { - try_or_err_and_log!($reqid, 500, $result) - }; - } - fn make_401_with_body(short_err: &str, body: ClientVisibleMsg) -> rouille::Response { - rouille::Response { - status_code: 401, - headers: vec![( - "WWW-Authenticate".into(), - format!("Bearer error=\"{}\"", short_err).into(), - )], - data: rouille::ResponseBody::from_data(body.0), - upgrade: None, - } - } - fn make_401(short_err: &str) -> rouille::Response { - make_401_with_body(short_err, ClientVisibleMsg(String::new())) - } - fn bearer_http_auth(request: &rouille::Request) -> Option<&str> { - let header = request.header("Authorization")?; - - let mut split = header.splitn(2, |c| c == ' '); - - let authtype = split.next()?; - if authtype != "Bearer" { - return None; - } - - split.next() - } - /// Return `content` as a bincode-encoded `Response`. - pub fn bincode_response(content: &T) -> rouille::Response - where - T: serde::Serialize, - { - let data = bincode::serialize(content).context("Failed to serialize response body"); - let data = try_or_500_log!("bincode body serialization", data); - - rouille::Response { - status_code: 200, - headers: vec![ - ("Content-Type".into(), "application/octet-stream".into()), - ("Content-Length".into(), data.len().to_string().into()), - ], - data: rouille::ResponseBody::from_data(data), - upgrade: None, - } - } - - /// Return `content` as either a bincode or json encoded `Response` - /// depending on the Accept header in `request`. - pub fn prepare_response(request: &rouille::Request, content: &T) -> rouille::Response - where - T: serde::Serialize, - { - accept!(request, - "application/octet-stream" => bincode_response(content), - "application/json" => rouille::Response::json(content), - ) - } - - // Verification of job auth in a request - macro_rules! job_auth_or_401 { - ($request:ident, $job_authorizer:expr, $job_id:expr) => {{ - let verify_result = match bearer_http_auth($request) { - Some(token) => $job_authorizer.verify_token($job_id, token), - None => Err(anyhow!("no Authorization header")), - }; - match verify_result { - Ok(()) => (), - Err(err) => { - let err: Box = err.into(); - let json = ErrJson::from_err(&*err); - return make_401_with_body("invalid_jwt", ClientVisibleMsg(json.into_data())); - } - } - }}; - } // Generation and verification of job auth struct JWTJobAuthorizer { server_key: Vec, } impl JWTJobAuthorizer { - fn new(server_key: Vec) -> Box { - Box::new(Self { server_key }) + fn new(server_key: Vec) -> Self { + Self { server_key } } } impl dist::JobAuthorizer for JWTJobAuthorizer { @@ -625,6 +419,7 @@ mod server { #[test] fn test_job_token_verification() { + use crate::dist::JobAuthorizer; let ja = JWTJobAuthorizer::new(vec![1, 2, 2]); let job_id = JobId(55); @@ -647,80 +442,894 @@ mod server { assert!(ja2.verify_token(job_id2, &token2).is_err()); } - pub struct Scheduler { - public_addr: SocketAddr, - handler: S, - // Is this client permitted to use the scheduler? - check_client_auth: Box, - // Do we believe the server is who they appear to be? - check_server_auth: ServerAuthCheck, - } + mod distserver_api_v1 { + use thiserror::Error; + + pub use filters::api; + + #[derive(Error, Debug)] + pub enum Error { + #[error("failed to assign job")] + AssignJob, + #[error("authorization header is wrong")] + AuthorizationHeaderBroken, + #[error("bearer_auth_failed")] + BearerAuthFailed, + #[error("a bincode error has occured")] + Bincode, + } - impl Scheduler { - pub fn new( - public_addr: SocketAddr, - handler: S, - check_client_auth: Box, - check_server_auth: ServerAuthCheck, - ) -> Self { - Self { - public_addr, - handler, - check_client_auth, - check_server_auth, + impl warp::reject::Reject for Error {} + + pub(super) mod filters { + use std::convert::Infallible; + use std::sync::{atomic, Arc}; + use warp::{ + http::{ + header::{ACCEPT, AUTHORIZATION, WWW_AUTHENTICATE}, + HeaderValue, StatusCode, + }, + reply::{self, Response}, + Filter, Rejection, Reply, + }; + + use super::{handlers, Error}; + use crate::dist::{ + self, + http::server::{ClientVisibleMsg, ErrJson}, + JobAuthorizer, JobId, ServerIncoming, + }; + + fn bearer_http_auth(auth_header: &HeaderValue) -> Result { + let header = auth_header + .to_str() + .map_err(|_| Error::AuthorizationHeaderBroken)?; + + let mut split = header.splitn(2, |c| c == ' '); + + let authtype = split.next().ok_or(Error::AuthorizationHeaderBroken)?; + + if authtype != "Bearer" { + return Err(Error::AuthorizationHeaderBroken); + } + + Ok(split + .next() + .ok_or(Error::AuthorizationHeaderBroken)? + .to_string()) + } + + async fn authorize( + job_id: JobId, + authorizer: Arc, + auth_header: HeaderValue, + ) -> Result { + let token = bearer_http_auth(&auth_header)?; + + authorizer + .verify_token(job_id, &token) + .map_err(|_| Error::BearerAuthFailed)?; + + Ok(job_id) + } + + fn with_job_authorizer( + job_authorizer: Arc, + ) -> impl Filter,), Error = Infallible> + Clone + { + warp::any().map(move || job_authorizer.clone()) + } + + fn with_requester( + requester: Arc, + ) -> impl Filter,), Error = Infallible> + Clone + { + warp::any().map(move || requester.clone()) + } + + fn with_server_incoming_handler( + handler: Arc, + ) -> impl Filter,), Error = Infallible> + Clone + { + warp::any().map(move || handler.clone()) + } + + async fn prepare_response( + content: T, + accept: Option, + ) -> Result + where + T: serde::Serialize, + { + match accept { + Some(accept) if accept == "application/json" => { + Ok(warp::reply::json(&content).into_response()) + } + _ => Ok(warp::http::Response::builder() + .body(warp::hyper::Body::from( + bincode::serialize(&content).map_err(|_| Error::Bincode)?, + )) + .map_err(|_| Error::Bincode)?), + } + } + + // POST /api/v1/distserver/assign_job/{job_id: JobId} + fn assign_job( + request_counter: Arc, + job_authorizer: Arc, + handler: Arc, + ) -> impl Filter + Clone { + let with_request_id = + warp::any().map(move || request_counter.fetch_add(1, atomic::Ordering::SeqCst)); + + warp::path!("api" / "v1" / "distserver" / "assign_job" / JobId) + .and(warp::post()) + .and(with_job_authorizer(job_authorizer)) + .and(warp::header::value(AUTHORIZATION.as_str())) + .and_then(authorize) + .and(toolchain()) + .and(with_server_incoming_handler(handler)) + .and(with_request_id) + .and_then(handlers::assign_job) + .and(warp::filters::header::optional::(ACCEPT.as_str())) + .and_then(prepare_response) + } + + // POST /api/v1/distserver/submit_toolchain/{job_id: JobId} + fn submit_toolchain( + _request_counter: Arc, + job_authorizer: Arc, + handler: Arc, + requester: Arc, + ) -> impl Filter + Clone { + warp::path!("api" / "v1" / "distserver" / "submit_toolchain" / JobId) + .and(warp::post()) + .and(with_job_authorizer(job_authorizer)) + .and(warp::header::value(AUTHORIZATION.as_str())) + .and_then(authorize) + .and(with_server_incoming_handler(handler)) + .and(with_requester(requester)) + .and(warp::body::bytes()) + .and_then(handlers::submit_toolchain) + .and(warp::filters::header::optional::(ACCEPT.as_str())) + .and_then(prepare_response) + } + + // POST /api/v1/distserver/run_job/{job_id: JobId} + fn run_job( + _request_counter: Arc, + job_authorizer: Arc, + handler: Arc, + requester: Arc, + ) -> impl Filter + Clone { + warp::path!("api" / "v1" / "distserver" / "run_job" / JobId) + .and(warp::post()) + .and(with_job_authorizer(job_authorizer)) + .and(warp::header::value(AUTHORIZATION.as_str())) + .and_then(authorize) + .and(with_server_incoming_handler(handler)) + .and(with_requester(requester)) + .and(warp::body::bytes()) + .and_then(handlers::run_job) + .and(warp::filters::header::optional::(ACCEPT.as_str())) + .and_then(prepare_response) + } + + pub fn api( + job_authorizer: Arc, + server_incoming_handler: Arc, + requester: Arc, + ) -> impl Filter + Clone { + let request_count = Arc::new(atomic::AtomicUsize::new(0)); + + assign_job( + request_count.clone(), + job_authorizer.clone(), + server_incoming_handler.clone(), + ) + .or(submit_toolchain( + request_count.clone(), + job_authorizer.clone(), + server_incoming_handler.clone(), + requester.clone(), + )) + .or(run_job( + request_count, + job_authorizer, + server_incoming_handler, + requester, + )) + .recover(handle_rejection) + .with(warp::log("warp::requests")) + } + + fn make_401_with_body(short_err: &str, body: Option) -> Response { + let body = reply::with_status( + body.map(|b| b.0).unwrap_or_default(), + StatusCode::UNAUTHORIZED, + ); + + reply::with_header( + body, + WWW_AUTHENTICATE, + format!("Bearer error=\"{}\"", short_err), + ) + .into_response() + } + + fn err_and_log(err: E, status: StatusCode) -> Response { + let mut err_msg = err.to_string(); + let mut maybe_cause = err.source(); + while let Some(cause) = maybe_cause { + err_msg.push_str(", caused by: "); + err_msg.push_str(&cause.to_string()); + maybe_cause = cause.source(); + } + + warn!("Res error: {}", err_msg); + let err: Box = err.into(); + let json = ErrJson::from_err(&*err); + + reply::with_status(warp::reply::json(&json), status).into_response() + } + + async fn handle_rejection(err: Rejection) -> Result { + trace!("Rejeceted"); + if err.is_not_found() { + Ok(reply::with_status(warp::reply(), StatusCode::NOT_FOUND).into_response()) + } else if let Some(e) = err.find::() { + if e.name() == AUTHORIZATION.as_str() { + let err: Box = e.into(); + let json = ErrJson::from_err(&*err); + + Ok(make_401_with_body( + "invalid_jwt", + Some(ClientVisibleMsg(json.into_data())), + ) + .into_response()) + } else { + Ok( + warp::reply::with_status(warp::reply(), StatusCode::NOT_FOUND) + .into_response(), + ) + } + } else if let Some(e) = err.find::() { + match e { + Error::AuthorizationHeaderBroken | Error::BearerAuthFailed => { + let err: Box = e.into(); + let json = ErrJson::from_err(&*err); + Ok(make_401_with_body( + "invalid_jwt", + Some(ClientVisibleMsg(json.into_data())), + ) + .into_response()) + } + Error::Bincode => Ok(err_and_log(e, StatusCode::BAD_REQUEST)), + Error::AssignJob => Ok(err_and_log(e, StatusCode::INTERNAL_SERVER_ERROR)), + } + } else { + Ok( + warp::reply::with_status(warp::reply(), StatusCode::NOT_FOUND) + .into_response(), + ) + } + } + + async fn from_bytes(bytes: bytes::Bytes) -> Result + where + O: serde::de::DeserializeOwned, + { + let a = bincode::deserialize_from::<_, O>(bytes.as_ref()) + .map_err(|_| Error::Bincode) + .map_err(warp::reject::custom)?; + + Ok(a) + } + + fn toolchain() -> impl Filter + Clone { + warp::body::bytes().and_then(from_bytes) } } - pub fn start(self) -> Result { - let Self { - public_addr, - handler, - check_client_auth, - check_server_auth, - } = self; - let requester = SchedulerRequester { - client: Mutex::new(new_reqwest_blocking_client()), + pub(super) mod handlers { + use super::super::JobId; + use super::super::RunJobHttpRequest; + use super::Error; + use crate::dist::{ + AssignJobResult, InputsReader, RunJobResult, SubmitToolchainResult, ToolchainReader, }; + use crate::dist::{ServerIncoming, ServerOutgoing, Toolchain}; + use byteorder::{BigEndian, ReadBytesExt}; + use flate2::read::ZlibDecoder as ZlibReadDecoder; + use std::sync::Arc; + use warp::reject::Rejection; + + pub async fn assign_job( + job_id: JobId, + toolchain: Toolchain, + handler: Arc, + _req_id: usize, + ) -> Result { + let res = handler + .handle_assign_job(job_id, toolchain) + .await + .map_err(|_| warp::reject::custom(Error::AssignJob))?; + + Ok(res) + } + + pub async fn submit_toolchain( + job_id: JobId, + handler: Arc, + requester: Arc, + body: bytes::Bytes, + ) -> Result { + let toolchain_rdr = ToolchainReader(Box::new(body.as_ref())); + let res = handler + .handle_submit_toolchain(requester.as_ref(), job_id, toolchain_rdr) + .await + .map_err(|_| warp::reject::custom(Error::AssignJob))?; + + Ok(res) + } + + pub async fn run_job( + job_id: JobId, + handler: Arc, + requester: Arc, + body: bytes::Bytes, + ) -> Result { + use std::io::Read; + + let mut body = body.as_ref(); + let bincode_length = body + .read_u32::() + .map_err(|_| warp::reject::custom(Error::AssignJob))? + as u64; + + let mut bincode_reader = body.take(bincode_length); + let runjob = bincode::deserialize_from(&mut bincode_reader) + .map_err(|_| warp::reject::custom(Error::AssignJob))?; + + let RunJobHttpRequest { command, outputs } = runjob; + + let body = bincode_reader.into_inner(); + + let inputs_rdr = InputsReader(Box::new(ZlibReadDecoder::new(body))); + + let outputs = outputs.into_iter().collect(); + + let res = handler + .handle_run_job(requester.as_ref(), job_id, command, outputs, inputs_rdr) + .await + .map_err(|_| warp::reject::custom(Error::AssignJob))?; + + Ok(res) + } + } + } + + mod scheduler_api_v1 { + use thiserror::Error; + + pub use filters::api; + + #[derive(Error, Debug)] + pub enum Error { + #[error("no Authorization header")] + NoAuthorizationHeader, + #[error("authorization header is wrong")] + AuthorizationHeaderBroken, + #[error("bearer_auth_failed")] + BearerAuthFailed, + #[error("bincode error")] + Bincode, + #[error("failed to alloc job")] + AllocJob, + #[error("failed to get status")] + Status, + #[error("bad request")] + BadRequest, + #[error("invalid_bearer_token_mismatched_address")] + InvalidBearerTokenMismatchedAddress, + #[error("invalid_bearer_token")] + InvalidBearerToken, + #[error("update certs")] + UpdateCerts, + #[error("failed to interpret pem as certificate")] + BadCertificate, + #[error("failed to create a HTTP client")] + NoHTTPClient, + #[error("failed to process heartbeat")] + Heartbeat, + #[error("failed to update job state")] + UpdateJobState, + #[error("failed to create a http client")] + ClientBuildFailed, + } - macro_rules! check_server_auth_or_err { - ($request:ident) => {{ - match bearer_http_auth($request).and_then(&*check_server_auth) { - Some(server_id) => { - let origin_ip = if let Some(header_val) = $request.header("X-Real-IP") { - trace!("X-Real-IP: {:?}", header_val); - match header_val.parse() { - Ok(ip) => ip, - Err(err) => { - warn!( - "X-Real-IP value {:?} could not be parsed: {:?}", - header_val, err - ); - return rouille::Response::empty_400(); - } + impl warp::reject::Reject for Error {} + + pub(super) mod filters { + use super::super::{ + ClientAuthCheck, ClientVisibleMsg, ErrJson, SchedulerRequester, ServerAuthCheck, + }; + use super::{handlers, Error}; + use crate::dist; + use crate::dist::{JobId, ServerId}; + use bytes::Buf; + use std::collections::HashMap; + use std::convert::Infallible; + use std::net::SocketAddr; + use std::sync::Arc; + use tokio::sync::Mutex; + use warp::http::header::{ACCEPT, AUTHORIZATION, CONTENT_TYPE, WWW_AUTHENTICATE}; + use warp::{ + http::{ + header::{HeaderMap, HeaderValue}, + StatusCode, + }, + reply::{self, Response}, + Filter, Rejection, Reply, + }; + + fn make_401_with_body(short_err: &str, body: ClientVisibleMsg) -> Response { + let body = reply::with_status(body.0, StatusCode::UNAUTHORIZED); + reply::with_header( + body, + WWW_AUTHENTICATE, + format!("Bearer error=\"{}\"", short_err), + ) + .into_response() + } + + fn err_and_log(err: E, status: StatusCode) -> Response { + let mut err_msg = err.to_string(); + let mut maybe_cause = err.source(); + while let Some(cause) = maybe_cause { + err_msg.push_str(", caused by: "); + err_msg.push_str(&cause.to_string()); + maybe_cause = cause.source(); + } + + warn!("Res error: {}", err_msg); + let err: Box = err.into(); + let json = ErrJson::from_err(&*err); + + reply::with_status(warp::reply::json(&json), status).into_response() + } + + async fn handle_rejection( + err: Rejection, + ) -> Result { + if err.is_not_found() { + Ok(reply::with_status(warp::reply(), StatusCode::NOT_FOUND).into_response()) + } else if let Some(e) = err.find::() { + if e.name() == AUTHORIZATION.as_str() { + let err: Box = e.into(); + let json = ErrJson::from_err(&*err); + + Ok( + make_401_with_body("invalid_jwt", ClientVisibleMsg(json.into_data())) + .into_response(), + ) + } else { + Ok( + warp::reply::with_status(warp::reply(), StatusCode::NOT_FOUND) + .into_response(), + ) + } + } else if let Some(e) = err.find::() { + match e { + Error::NoAuthorizationHeader + | Error::BearerAuthFailed + | Error::AuthorizationHeaderBroken + | Error::InvalidBearerTokenMismatchedAddress + | Error::InvalidBearerToken => { + let err: Box = e.into(); + let json = ErrJson::from_err(&*err); + Ok(make_401_with_body( + "invalid_jwt", + ClientVisibleMsg(json.into_data()), + ) + .into_response()) + } + Error::Bincode + | Error::UpdateCerts + | Error::BadRequest + | Error::BadCertificate => Ok(err_and_log(e, StatusCode::BAD_REQUEST)), + Error::AllocJob + | Error::Heartbeat + | Error::UpdateJobState + | Error::Status + | Error::NoHTTPClient + | Error::ClientBuildFailed => { + Ok(err_and_log(e, StatusCode::INTERNAL_SERVER_ERROR)) + } + } + } else { + Ok(reply::with_status(warp::reply(), StatusCode::NOT_FOUND).into_response()) + } + } + + pub fn api( + requester: Arc, + auth: Arc, + s: Arc, + certificates: Arc, Vec)>>>, + check_server_auth: ServerAuthCheck, + ) -> impl Filter + Clone { + alloc_job( + requester.clone(), + auth.clone(), + s.clone(), + certificates.clone(), + ) + .or(server_certificate(certificates.clone())) + .or(heartbeat_server( + check_server_auth.clone(), + s.clone(), + certificates, + requester, + )) + .or(job_state(check_server_auth, s.clone())) + .or(status(s)) + .recover(handle_rejection) + .with(warp::log("warp::requests")) + } + + // POST /api/v1/scheduler/alloc_job + fn alloc_job( + requester: Arc, + auth: Arc, + s: Arc, + certificates: Arc, Vec)>>>, + ) -> impl Filter + Clone { + warp::path!("api" / "v1" / "scheduler" / "alloc_job") + .and(warp::post()) + .and(with_client_authorizer(auth)) + .and(warp::header::value(AUTHORIZATION.as_str())) + .and_then(authorize) + .untuple_one() + .and(with_handler(s)) + .and(toolchain()) + .and(with_requester(requester)) + .and(with_certificates(certificates)) + .and_then(handlers::alloc_job) + .and(warp::filters::header::optional::(ACCEPT.as_str())) + .and_then(prepare_response) + } + + // GET /api/v1/scheduler/server_certificate/{server_id: ServerId}) + fn server_certificate( + certificates: Arc, Vec)>>>, + ) -> impl Filter + Clone { + warp::path!("api" / "v1" / "scheduler" / "server_certificate" / ServerId) + .and(warp::get()) + .and(with_certificates(certificates)) + .and_then(handlers::server_certificate) + .and(warp::filters::header::optional::(ACCEPT.as_str())) + .and_then(prepare_response) + } + + // POST /api/v1/scheduler/heartbeat_server + fn heartbeat_server( + check_server_auth: ServerAuthCheck, + s: Arc, + certificates: Arc, Vec)>>>, + requester: Arc, + ) -> impl Filter + Clone { + warp::path!("api" / "v1" / "scheduler" / "heartbeat_server") + .and(warp::post()) + .and(with_server_auth(check_server_auth)) + .and(warp::header::headers_cloned()) + .and(warp::addr::remote()) + .and_then(auth_server) + .and(with_handler(s)) + .and(bincode_input()) + .and(with_certificates(certificates)) + .and(with_requester(requester)) + .and_then(handlers::heartbeat_server) + .and(warp::filters::header::optional::(ACCEPT.as_str())) + .and_then(prepare_response) + } + + // POST /api/v1/scheduler/job_state/{job_id: JobId} + fn job_state( + check_server_auth: ServerAuthCheck, + s: Arc, + ) -> impl Filter + Clone { + warp::path!("api" / "v1" / "scheduler" / "job_state" / JobId) + .and(warp::post()) + .and( + with_server_auth(check_server_auth) + .and(warp::header::headers_cloned()) + .and(warp::addr::remote()) + .and_then(auth_server), + ) + .and(with_handler(s)) + .and(bincode_input()) + .and_then(handlers::job_state) + .and(warp::filters::header::optional::(ACCEPT.as_str())) + .and_then(prepare_response) + } + + // GET /api/v1/scheduler/status + fn status( + s: Arc, + ) -> impl Filter + Clone + { + warp::path!("api" / "v1" / "scheduler" / "status") + .and(warp::get()) + .and(with_handler(s)) + .and_then(handlers::status) + .and(warp::filters::header::optional::(ACCEPT.as_str())) + .and_then(prepare_response) + } + + fn bincode_input() -> impl Filter + Clone + where + T: serde::de::DeserializeOwned + std::marker::Send, + { + warp::header::exact_ignore_case(CONTENT_TYPE.as_str(), "application/octet-stream") + .and( + warp::body::bytes().and_then(|body: bytes::Bytes| async move { + let mut reader = body.reader(); + bincode::deserialize_from::<_, T>(&mut reader) + .map_err(|_| warp::reject::custom(Error::Bincode)) + }), + ) + } + + async fn prepare_response( + content: T, + accept: Option, + ) -> Result + where + T: serde::Serialize, + { + match accept { + Some(accept) if accept == "application/json" => { + Ok(warp::reply::json(&content).into_response()) + } + _ => Ok(warp::http::Response::builder() + .header(CONTENT_TYPE, "application/octet-stream") + .body(warp::hyper::Body::from( + bincode::serialize(&content).map_err(|_| Error::Bincode)?, + )) + .map_err(|_| Error::Bincode)?), + } + } + + fn with_handler( + handler: Arc, + ) -> impl Filter,), Error = Infallible> + Clone + { + warp::any().map(move || handler.clone()) + } + + fn with_requester( + requester: Arc, + ) -> impl Filter,), Error = Infallible> + Clone + { + warp::any().map(move || requester.clone()) + } + + fn with_certificates( + certificates: Arc, Vec)>>>, + ) -> impl Filter< + Extract = (Arc, Vec)>>>,), + Error = Infallible, + > + Clone { + warp::any().map(move || certificates.clone()) + } + + fn with_server_auth( + check_server_auth: ServerAuthCheck, + ) -> impl Filter + Clone { + warp::any().map(move || check_server_auth.clone()) + } + + fn with_client_authorizer( + client_authorizer: Arc, + ) -> impl Filter,), Error = Infallible> + Clone + { + warp::any().map(move || client_authorizer.clone()) + } + + fn bearer_http_auth(auth_header: &HeaderValue) -> Result { + let header = auth_header + .to_str() + .map_err(|_| Error::AuthorizationHeaderBroken)?; + + let mut split = header.splitn(2, |c| c == ' '); + + let authtype = split.next().ok_or(Error::AuthorizationHeaderBroken)?; + + if authtype != "Bearer" { + return Err(Error::AuthorizationHeaderBroken); + } + + Ok(split + .next() + .ok_or(Error::AuthorizationHeaderBroken)? + .to_string()) + } + + async fn authorize( + check_client_auth: Arc, + auth_header: HeaderValue, + ) -> Result<(), Rejection> { + let bearer_auth = bearer_http_auth(&auth_header)?; + + check_client_auth + .check(&bearer_auth) + .await + .map_err(|_| Error::BearerAuthFailed)?; + + Ok(()) + } + + async fn auth_server( + check_server_auth: ServerAuthCheck, + headers: HeaderMap, + remote: Option, + ) -> Result { + let auth_header = headers + .get(AUTHORIZATION.as_str()) + .ok_or(Error::NoAuthorizationHeader)?; + + match check_server_auth(&bearer_http_auth(auth_header)?) { + Some(server_id) => { + let origin_ip = if let Some(header_val) = headers.get("X-Real-IP") { + trace!("X-Real-IP: {:?}", header_val); + match header_val.to_str().unwrap().parse() { + Ok(ip) => ip, + Err(err) => { + warn!( + "X-Real-IP value {:?} could not be parsed: {:?}", + header_val, err + ); + return Err(warp::reject::custom(Error::BadRequest)); } - } else { - $request.remote_addr().ip() - }; - if server_id.addr().ip() != origin_ip { - trace!("server ip: {:?}", server_id.addr().ip()); - trace!("request ip: {:?}", $request.remote_addr().ip()); - return make_401("invalid_bearer_token_mismatched_address"); - } else { - server_id } + } else { + remote.unwrap().ip() + }; + + if server_id.addr().ip() != origin_ip { + trace!("server ip: {:?}", server_id.addr().ip()); + trace!("request ip: {:?}", remote.unwrap().ip()); + Err(warp::reject::custom( + Error::InvalidBearerTokenMismatchedAddress, + )) + } else { + Ok(server_id) } - None => return make_401("invalid_bearer_token"), } - }}; + None => Err(warp::reject::custom(Error::InvalidBearerToken)), + } + } + + async fn from_bytes(bytes: bytes::Bytes) -> Result + where + O: serde::de::DeserializeOwned, + { + let a = bincode::deserialize_from::<_, O>(bytes.as_ref()) + .map_err(|_| Error::Bincode) + .map_err(warp::reject::custom)?; + + Ok(a) + } + + fn toolchain() -> impl Filter + Clone { + warp::body::bytes().and_then(from_bytes) + } + } + + pub(super) mod handlers { + use super::super::AllocJobHttpResponse; + use super::super::{HeartbeatServerHttpRequest, ServerCertificateHttpResponse}; + use super::super::{JWTJobAuthorizer, JobId, SchedulerRequester}; + use super::Error; + use crate::dist::{self, ServerId}; + use crate::dist::{ + HeartbeatServerResult, JobState, SchedulerStatusResult, UpdateJobStateResult, + }; + use std::collections::HashMap; + use std::sync::Arc; + use tokio::sync::Mutex; + use warp::reject::{self, Rejection}; + + pub async fn alloc_job( + handler: Arc, + toolchain: dist::Toolchain, + requester: Arc, + certs: Arc, Vec)>>>, + ) -> Result { + let alloc_job_res = handler + .handle_alloc_job(requester.as_ref(), toolchain) + .await + .map_err(|_| reject::custom(Error::AllocJob))?; + + let certs = certs.lock().await; + let res = AllocJobHttpResponse::from_alloc_job_result(alloc_job_res, &certs); + + Ok(res) + } + + pub async fn server_certificate( + server_id: ServerId, + certificates: Arc, Vec)>>>, + ) -> Result { + let certs = certificates.lock().await; + + let (cert_digest, cert_pem) = certs.get(&server_id).cloned().unwrap(); + let res = ServerCertificateHttpResponse { + cert_digest, + cert_pem, + }; + + Ok(res) + } + + pub async fn heartbeat_server( + server_id: ServerId, + handler: Arc, + heartbeat_server: HeartbeatServerHttpRequest, + server_certificates: Arc, Vec)>>>, + requester: Arc, + ) -> Result { + let HeartbeatServerHttpRequest { + num_cpus, + jwt_key, + server_nonce, + cert_digest, + cert_pem, + } = heartbeat_server; + + let mut client = requester.client.lock().await; + let mut certs = server_certificates.lock().await; + maybe_update_certs(&mut client, &mut certs, server_id, cert_digest, cert_pem) + .await + .map_err(|_| Error::UpdateCerts)?; + + let job_authorizer = Box::new(JWTJobAuthorizer::new(jwt_key)); + let res: HeartbeatServerResult = handler + .handle_heartbeat_server(server_id, server_nonce, num_cpus, job_authorizer) + .map_err(|_| Error::Heartbeat)?; + + Ok(res) } - fn maybe_update_certs( - client: &mut reqwest::blocking::Client, + pub async fn job_state( + job_id: JobId, + server_id: ServerId, + handler: Arc, + job_state: JobState, + ) -> Result { + let res = handler + .handle_update_job_state(job_id, server_id, job_state) + .map_err(|_| Error::UpdateJobState)?; + + Ok(res) + } + + pub async fn status( + handler: Arc, + ) -> Result { + let res: SchedulerStatusResult = + handler.handle_status().map_err(|_| Error::Status)?; + Ok(res) + } + + async fn maybe_update_certs( + client: &mut reqwest::Client, certs: &mut HashMap, Vec)>, server_id: ServerId, cert_digest: Vec, cert_pem: Vec, - ) -> Result<()> { + ) -> Result<(), Error> { if let Some((saved_cert_digest, _)) = certs.get(&server_id) { if saved_cert_digest == &cert_digest { return Ok(()); @@ -730,132 +1339,88 @@ mod server { "Adding new certificate for {} to scheduler", server_id.addr() ); - let mut client_builder = reqwest::blocking::ClientBuilder::new(); + + let _ = native_tls::Certificate::from_pem(&cert_pem) + .map_err(|_| Error::BadCertificate)?; // Add all the certificates we know about - client_builder = client_builder.add_root_certificate( - reqwest::Certificate::from_pem(&cert_pem) - .context("failed to interpret pem as certificate")?, - ); - for (_, cert_pem) in certs.values() { - client_builder = client_builder.add_root_certificate( - reqwest::Certificate::from_pem(cert_pem).expect("previously valid cert"), - ); - } - // Finish the client - let new_client = client_builder - // Disable connection pool to avoid broken connection - // between runtime - .pool_max_idle_per_host(0) - .build() - .context("failed to create a HTTP client")?; + let root_certs = + std::iter::once(&cert_pem).chain(certs.values().map(|(_, cert_pem)| cert_pem)); + let client_builder = crate::util::native_tls_no_sni_client_builder(root_certs) + .map_err(|_| Error::ClientBuildFailed)?; + + // Finish the clients + let new_client = client_builder.build().map_err(|_| Error::NoHTTPClient)?; // Use the updated certificates *client = new_client; certs.insert(server_id, (cert_digest, cert_pem)); Ok(()) } + } + } + + pub struct Scheduler { + public_addr: SocketAddr, + handler: S, + // Is this client permitted to use the scheduler? + check_client_auth: Box, + // Do we believe the server is who they appear to be? + check_server_auth: ServerAuthCheck, + } + impl Scheduler { + pub fn new( + public_addr: SocketAddr, + handler: S, + check_client_auth: Box, + check_server_auth: ServerAuthCheck, + ) -> Self { + Self { + public_addr, + handler, + check_client_auth, + check_server_auth, + } + } + + pub async fn start(self) -> Result { + let Self { + public_addr, + handler, + check_client_auth, + check_server_auth, + } = self; + let client = + crate::util::native_tls_no_sni_client_builder(std::iter::empty::>()) + .unwrap() + .build() + .unwrap(); + let requester = Arc::new(SchedulerRequester { + client: Mutex::new(client), + }); + + let check_client_auth = Arc::from(check_client_auth); + let handler = Arc::from(handler); + let server_certificates = Arc::new(Mutex::new(HashMap::new())); + let api = scheduler_api_v1::api( + requester, + check_client_auth, + handler, + server_certificates, + check_server_auth, + ); info!("Scheduler listening for clients on {}", public_addr); - let request_count = atomic::AtomicUsize::new(0); - // From server_id -> cert_digest, cert_pem - let server_certificates: Mutex, Vec)>> = - Default::default(); - - let server = rouille::Server::new(public_addr, move |request| { - let req_id = request_count.fetch_add(1, atomic::Ordering::SeqCst); - trace!("Req {} ({}): {:?}", req_id, request.remote_addr(), request); - let response = (|| router!(request, - (POST) (/api/v1/scheduler/alloc_job) => { - let bearer_auth = match bearer_http_auth(request) { - Some(s) => s, - None => return make_401("no_bearer_auth"), - }; - match check_client_auth.check(bearer_auth) { - Ok(()) => (), - Err(client_msg) => { - warn!("Bearer auth failed: {:?}", client_msg); - return make_401_with_body("bearer_auth_failed", client_msg) - }, - } - let toolchain = try_or_400_log!(req_id, bincode_input(request)); - trace!("Req {}: alloc_job: {:?}", req_id, toolchain); - - let alloc_job_res: AllocJobResult = try_or_500_log!(req_id, handler.handle_alloc_job(&requester, toolchain)); - let certs = server_certificates.lock().unwrap(); - let res = AllocJobHttpResponse::from_alloc_job_result(alloc_job_res, &certs); - prepare_response(request, &res) - }, - (GET) (/api/v1/scheduler/server_certificate/{server_id: ServerId}) => { - let certs = { - let guard = server_certificates.lock().unwrap(); - guard.get(&server_id).map(|v|v.to_owned()) - }; + warp::serve(api).run(public_addr).await; - let (cert_digest, cert_pem) = try_or_500_log!(req_id, certs - .context("server cert not available")); - let res = ServerCertificateHttpResponse { - cert_digest, - cert_pem, - }; - prepare_response(request, &res) - }, - (POST) (/api/v1/scheduler/heartbeat_server) => { - let server_id = check_server_auth_or_err!(request); - let heartbeat_server = try_or_400_log!(req_id, bincode_input(request)); - trace!("Req {}: heartbeat_server: {:?}", req_id, heartbeat_server); - - let HeartbeatServerHttpRequest { num_cpus, jwt_key, server_nonce, cert_digest, cert_pem } = heartbeat_server; - try_or_500_log!(req_id, maybe_update_certs( - &mut requester.client.lock().unwrap(), - &mut server_certificates.lock().unwrap(), - server_id, cert_digest, cert_pem - )); - let job_authorizer = JWTJobAuthorizer::new(jwt_key); - let res: HeartbeatServerResult = try_or_500_log!(req_id, handler.handle_heartbeat_server( - server_id, server_nonce, - num_cpus, - job_authorizer - )); - prepare_response(request, &res) - }, - (POST) (/api/v1/scheduler/job_state/{job_id: JobId}) => { - let server_id = check_server_auth_or_err!(request); - let job_state = try_or_400_log!(req_id, bincode_input(request)); - trace!("Req {}: job state: {:?}", req_id, job_state); - - let res: UpdateJobStateResult = try_or_500_log!(req_id, handler.handle_update_job_state( - job_id, server_id, job_state - )); - prepare_response(request, &res) - }, - (GET) (/api/v1/scheduler/status) => { - let res: SchedulerStatusResult = try_or_500_log!(req_id, handler.handle_status()); - prepare_response(request, &res) - }, - _ => { - warn!("Unknown request {:?}", request); - rouille::Response::empty_404() - }, - ))(); - trace!("Res {}: {:?}", req_id, response); - response - }).map_err(|e| anyhow!(format!("Failed to start http server for sccache scheduler: {}", e)))?; - - // This limit is rouille's default for `start_server_with_pool`, which - // we would use, except that interface doesn't permit any sort of - // error handling to be done. - let server = server.pool_size(num_cpus::get() * 8); - server.run(); - - panic!("Rouille server terminated") + panic!("Warp server terminated") } } - - struct SchedulerRequester { - client: Mutex, + pub struct SchedulerRequester { + client: tokio::sync::Mutex, } + #[async_trait] impl dist::SchedulerOutgoing for SchedulerRequester { - fn do_assign_job( + async fn do_assign_job( &self, server_id: ServerId, job_id: JobId, @@ -863,8 +1428,9 @@ mod server { auth: String, ) -> Result { let url = urls::server_assign_job(server_id, job_id); - let req = self.client.lock().unwrap().post(url); - bincode_req(req.bearer_auth(auth).bincode(&tc)?) + let req = self.client.lock().await.post(url); + bincode_req_fut(req.bearer_auth(auth).bincode(&tc)?) + .await .context("POST to scheduler assign_job failed") } } @@ -911,7 +1477,7 @@ mod server { }) } - pub fn start(self) -> Result { + pub async fn start(self) -> Result { let Self { public_addr, scheduler_url, @@ -923,6 +1489,9 @@ mod server { server_nonce, handler, } = self; + + let handler = Arc::new(handler); + let heartbeat_req = HeartbeatServerHttpRequest { num_cpus: num_cpus::get(), jwt_key: jwt_key.clone(), @@ -930,120 +1499,76 @@ mod server { cert_digest, cert_pem: cert_pem.clone(), }; - let job_authorizer = JWTJobAuthorizer::new(jwt_key); + let job_authorizer = Arc::new(JWTJobAuthorizer::new(jwt_key)); let heartbeat_url = urls::scheduler_heartbeat_server(&scheduler_url); - let requester = ServerRequester { - client: new_reqwest_blocking_client(), + let requester = Arc::new(ServerRequester { + client: new_reqwest_client(), scheduler_url, scheduler_auth: scheduler_auth.clone(), - }; + }); + + let api = distserver_api_v1::api(job_authorizer, handler, requester); - // TODO: detect if this panics - thread::spawn(move || { - let client = new_reqwest_blocking_client(); + tokio::spawn(async move { + use tokio::time; + + let client = new_reqwest_client(); loop { trace!("Performing heartbeat"); - match bincode_req( + match bincode_req_fut( client .post(heartbeat_url.clone()) .bearer_auth(scheduler_auth.clone()) .bincode(&heartbeat_req) - .expect("failed to serialize heartbeat"), - ) { + .expect("failed to serialize a heartbeat"), + ) + .await + { Ok(HeartbeatServerResult { is_new }) => { trace!("Heartbeat success is_new={}", is_new); // TODO: if is_new, terminate all running jobs - thread::sleep(HEARTBEAT_INTERVAL) + time::sleep(HEARTBEAT_INTERVAL).await; } Err(e) => { error!("Failed to send heartbeat to server: {}", e); - thread::sleep(HEARTBEAT_ERROR_INTERVAL) + time::sleep(HEARTBEAT_ERROR_INTERVAL).await; } } } }); - info!("Server listening for clients on {}", public_addr); - let request_count = atomic::AtomicUsize::new(0); - - let server = rouille::Server::new_ssl(public_addr, move |request| { - let req_id = request_count.fetch_add(1, atomic::Ordering::SeqCst); - trace!("Req {} ({}): {:?}", req_id, request.remote_addr(), request); - let response = (|| router!(request, - (POST) (/api/v1/distserver/assign_job/{job_id: JobId}) => { - job_auth_or_401!(request, &job_authorizer, job_id); - let toolchain = try_or_400_log!(req_id, bincode_input(request)); - trace!("Req {}: assign_job({}): {:?}", req_id, job_id, toolchain); - - let res: AssignJobResult = try_or_500_log!(req_id, handler.handle_assign_job(job_id, toolchain)); - prepare_response(request, &res) - }, - (POST) (/api/v1/distserver/submit_toolchain/{job_id: JobId}) => { - job_auth_or_401!(request, &job_authorizer, job_id); - trace!("Req {}: submit_toolchain({})", req_id, job_id); - - let body = request.data().expect("body was already read in submit_toolchain"); - let toolchain_rdr = ToolchainReader(Box::new(body)); - let res: SubmitToolchainResult = try_or_500_log!(req_id, handler.handle_submit_toolchain(&requester, job_id, toolchain_rdr)); - prepare_response(request, &res) - }, - (POST) (/api/v1/distserver/run_job/{job_id: JobId}) => { - job_auth_or_401!(request, &job_authorizer, job_id); - - let mut body = request.data().expect("body was already read in run_job"); - let bincode_length = try_or_500_log!(req_id, body.read_u32::() - .context("failed to read run job input length")) as u64; - - let mut bincode_reader = body.take(bincode_length); - let runjob = try_or_500_log!(req_id, bincode::deserialize_from(&mut bincode_reader) - .context("failed to deserialize run job request")); - trace!("Req {}: run_job({}): {:?}", req_id, job_id, runjob); - let RunJobHttpRequest { command, outputs } = runjob; - let body = bincode_reader.into_inner(); - let inputs_rdr = InputsReader(Box::new(ZlibReadDecoder::new(body))); - let outputs = outputs.into_iter().collect(); - - let res: RunJobResult = try_or_500_log!(req_id, handler.handle_run_job(&requester, job_id, command, outputs, inputs_rdr)); - prepare_response(request, &res) - }, - _ => { - warn!("Unknown request {:?}", request); - rouille::Response::empty_404() - }, - ))(); - trace!("Res {}: {:?}", req_id, response); - response - }, cert_pem, privkey_pem).map_err(|e| anyhow!(format!("Failed to start http server for sccache server: {}", e)))?; - - // This limit is rouille's default for `start_server_with_pool`, which - // we would use, except that interface doesn't permit any sort of - // error handling to be done. - let server = server.pool_size(num_cpus::get() * 8); - server.run(); - - panic!("Rouille server terminated") + warp::serve(api) + .tls() + .cert(cert_pem) + .key(privkey_pem) + .run(public_addr) + .await; + + panic!("Warp server terminated") } } struct ServerRequester { - client: reqwest::blocking::Client, + client: reqwest::Client, scheduler_url: reqwest::Url, scheduler_auth: String, } + #[async_trait] impl dist::ServerOutgoing for ServerRequester { - fn do_update_job_state( + async fn do_update_job_state( &self, job_id: JobId, state: JobState, ) -> Result { let url = urls::scheduler_job_state(&self.scheduler_url, job_id); - bincode_req( + bincode_req_fut( self.client .post(url) .bearer_auth(self.scheduler_auth.clone()) .bincode(&state)?, ) + .await .context("POST to scheduler job_state failed") } } @@ -1063,13 +1588,12 @@ mod client { use byteorder::{BigEndian, WriteBytesExt}; use flate2::write::ZlibEncoder as ZlibWriteEncoder; use flate2::Compression; - use futures::TryFutureExt; - use reqwest::Body; use std::collections::HashMap; use std::io::Write; use std::path::{Path, PathBuf}; - use std::sync::{Arc, Mutex}; + use std::sync::Arc; use std::time::Duration; + use tokio::sync::Mutex; use super::common::{ bincode_req_fut, AllocJobHttpResponse, ReqwestRequestBuilderExt, RunJobHttpRequest, @@ -1104,7 +1628,12 @@ mod client { ) -> Result { let timeout = Duration::new(REQUEST_TIMEOUT_SECS, 0); let connect_timeout = Duration::new(CONNECT_TIMEOUT_SECS, 0); - let client = reqwest::ClientBuilder::new() + + let builder = + crate::util::native_tls_no_sni_client_builder(std::iter::empty::>()) + .context("failed to create an async HTTP client")?; + + let client = builder .timeout(timeout) .connect_timeout(connect_timeout) // Disable connection pool to avoid broken connection @@ -1132,27 +1661,21 @@ mod client { cert_digest: Vec, cert_pem: Vec, ) -> Result<()> { - let mut client_async_builder = reqwest::ClientBuilder::new(); // Add all the certificates we know about - client_async_builder = client_async_builder.add_root_certificate( - reqwest::Certificate::from_pem(&cert_pem) - .context("failed to interpret pem as certificate")?, - ); - for cert_pem in certs.values() { - client_async_builder = client_async_builder.add_root_certificate( - reqwest::Certificate::from_pem(cert_pem).expect("previously valid cert"), - ); - } - // Finish the client + let root_certs = std::iter::once(&cert_pem).chain(certs.values()); + let client_builder = crate::util::native_tls_no_sni_client_builder(root_certs) + .context("failed to create an async HTTP client")?; + + // Finish the clients let timeout = Duration::new(REQUEST_TIMEOUT_SECS, 0); - let new_client_async = client_async_builder + let new_client = client_builder .timeout(timeout) // Disable keep-alive .pool_max_idle_per_host(0) .build() .context("failed to create an async HTTP client")?; // Use the updated certificates - *client = new_client_async; + *client = new_client; certs.insert(cert_digest, cert_pem); Ok(()) } @@ -1163,7 +1686,7 @@ mod client { async fn do_alloc_job(&self, tc: Toolchain) -> Result { let scheduler_url = self.scheduler_url.clone(); let url = urls::scheduler_alloc_job(&scheduler_url); - let mut req = self.client.lock().unwrap().post(url); + let mut req = self.client.lock().await.post(url); req = req.bearer_auth(self.auth_token.clone()).bincode(&tc)?; let client = self.client.clone(); @@ -1180,7 +1703,7 @@ mod client { job_alloc, need_toolchain, }); - if server_certs.lock().unwrap().contains_key(&cert_digest) { + if server_certs.lock().await.contains_key(&cert_digest) { return alloc_job_res; } info!( @@ -1188,31 +1711,18 @@ mod client { server_id.addr() ); let url = urls::scheduler_server_certificate(&scheduler_url, server_id); - let req = client.lock().unwrap().get(url); + let req = client.lock().await.get(url); let res: ServerCertificateHttpResponse = bincode_req_fut(req) .await .context("GET to scheduler server_certificate failed")?; - // TODO: Move to asynchronous reqwest client only. - // This function internally builds a blocking reqwest client; - // However, it does so by utilizing a runtime which it drops, - // triggering (rightfully) a sanity check that prevents from - // dropping a runtime in asynchronous context. - // For the time being, we work around this by off-loading it - // to a dedicated blocking-friendly thread pool. - let _ = self - .pool - .spawn_blocking(move || { - Self::update_certs( - &mut client.lock().unwrap(), - &mut server_certs.lock().unwrap(), - res.cert_digest, - res.cert_pem, - ) - .context("Failed to update certificate") - .unwrap_or_else(|e| warn!("Failed to update certificate: {:?}", e)); - }) - .await; + Self::update_certs( + &mut *client.lock().await, + &mut *server_certs.lock().await, + res.cert_digest, + res.cert_pem, + ) + .unwrap_or_else(|e| warn!("Failed to update certificate: {:?}", e)); alloc_job_res } @@ -1223,7 +1733,8 @@ mod client { async fn do_get_status(&self) -> Result { let scheduler_url = self.scheduler_url.clone(); let url = urls::scheduler_status(&scheduler_url); - let req = self.client.lock().unwrap().get(url); + let req = self.client.lock().await.get(url); + bincode_req_fut(req).await } @@ -1235,10 +1746,17 @@ mod client { match self.tc_cache.get_toolchain(&tc) { Ok(Some(toolchain_file)) => { let url = urls::server_submit_toolchain(job_alloc.server_id, job_alloc.job_id); - let req = self.client.lock().unwrap().post(url); - let toolchain_file = tokio::fs::File::from_std(toolchain_file.into()); - let toolchain_file_stream = tokio_util::io::ReaderStream::new(toolchain_file); - let body = Body::wrap_stream(toolchain_file_stream); + let req = self.client.lock().await.post(url); + + let _toolchain_file_exists = toolchain_file.metadata()?; + + use tokio_util::codec::{BytesCodec, FramedRead}; + let toolchain_file = toolchain_file.into_parts().0; + let toolchain_file = tokio::fs::File::from_std(toolchain_file); + let stream = FramedRead::new(toolchain_file, BytesCodec::new()); + + let body = reqwest::Body::wrap_stream(stream); + let req = req.bearer_auth(job_alloc.auth).body(body); bincode_req_fut(req).await } @@ -1255,14 +1773,14 @@ mod client { inputs_packager: Box, ) -> Result<(RunJobResult, PathTransformer)> { let url = urls::server_run_job(job_alloc.server_id, job_alloc.job_id); + let req = self.client.lock().await.post(url); - let (body, path_transformer) = self + let (path_transformer, compressed_body) = self .pool - .spawn_blocking(move || -> Result<_> { + .spawn_blocking(move || { let bincode = bincode::serialize(&RunJobHttpRequest { command, outputs }) .context("failed to serialize run job request")?; let bincode_length = bincode.len(); - let mut body = vec![]; body.write_u32::(bincode_length as u32) .expect("Infallible write of bincode length to vec failed"); @@ -1282,15 +1800,16 @@ mod client { ); compressor.finish().context("failed to finish compressor")?; } - - Ok((body, path_transformer)) + ::core::result::Result::<_, anyhow::Error>::Ok((path_transformer, body)) }) .await??; - let mut req = self.client.lock().unwrap().post(url); - req = req.bearer_auth(job_alloc.auth.clone()).bytes(body); - bincode_req_fut(req) - .map_ok(|res| (res, path_transformer)) - .await + + let req = req + .bearer_auth(job_alloc.auth.clone()) + .bytes(compressed_body); + let res = bincode_req_fut(req).await?; + + Ok((res, path_transformer)) } async fn put_toolchain( diff --git a/src/dist/mod.rs b/src/dist/mod.rs index 93a6859cf..48bf323b3 100644 --- a/src/dist/mod.rs +++ b/src/dist/mod.rs @@ -609,15 +609,18 @@ pub struct BuildResult { // bound on the instance (e.g. scheduler) we pass to the actual communication (e.g. // http implementation) they need to be public, which has knock-on effects for private // structs - -pub struct ToolchainReader<'a>(Box); +#[cfg(feature = "dist-server")] +pub struct ToolchainReader<'a>(Box); +#[cfg(feature = "dist-server")] impl<'a> Read for ToolchainReader<'a> { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.0.read(buf) } } +#[cfg(feature = "dist-server")] pub struct InputsReader<'a>(Box); +#[cfg(feature = "dist-server")] impl<'a> Read for InputsReader<'a> { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.0.read(buf) @@ -628,9 +631,10 @@ impl<'a> Read for InputsReader<'a> { type ExtResult = ::std::result::Result; #[cfg(feature = "dist-server")] -pub trait SchedulerOutgoing { +#[async_trait] +pub trait SchedulerOutgoing: Send + Sync { // To Server - fn do_assign_job( + async fn do_assign_job( &self, server_id: ServerId, job_id: JobId, @@ -640,22 +644,28 @@ pub trait SchedulerOutgoing { } #[cfg(feature = "dist-server")] -pub trait ServerOutgoing { +#[async_trait] +pub trait ServerOutgoing: Send + Sync { // To Scheduler - fn do_update_job_state(&self, job_id: JobId, state: JobState) -> Result; + async fn do_update_job_state( + &self, + job_id: JobId, + state: JobState, + ) -> Result; } // Trait to handle the creation and verification of job authorization tokens #[cfg(feature = "dist-server")] -pub trait JobAuthorizer: Send { +pub trait JobAuthorizer: Send + Sync { fn generate_token(&self, job_id: JobId) -> Result; fn verify_token(&self, job_id: JobId, token: &str) -> Result<()>; } #[cfg(feature = "dist-server")] +#[async_trait] pub trait SchedulerIncoming: Send + Sync { // From Client - fn handle_alloc_job( + async fn handle_alloc_job( &self, requester: &dyn SchedulerOutgoing, tc: Toolchain, @@ -680,18 +690,23 @@ pub trait SchedulerIncoming: Send + Sync { } #[cfg(feature = "dist-server")] +#[async_trait] pub trait ServerIncoming: Send + Sync { // From Scheduler - fn handle_assign_job(&self, job_id: JobId, tc: Toolchain) -> ExtResult; + async fn handle_assign_job( + &self, + job_id: JobId, + tc: Toolchain, + ) -> ExtResult; // From Client - fn handle_submit_toolchain( + async fn handle_submit_toolchain( &self, requester: &dyn ServerOutgoing, job_id: JobId, tc_rdr: ToolchainReader<'_>, ) -> ExtResult; // From Client - fn handle_run_job( + async fn handle_run_job( &self, requester: &dyn ServerOutgoing, job_id: JobId, diff --git a/src/lib.rs b/src/lib.rs index a893a155f..79b5e97a7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,9 +22,6 @@ #[macro_use] extern crate log; -#[cfg(feature = "rouille")] -#[macro_use(router)] -extern crate rouille; // To get macros in scope, this has to be first. #[cfg(test)] #[macro_use] diff --git a/src/server.rs b/src/server.rs index 0128a4adf..e05201e6d 100644 --- a/src/server.rs +++ b/src/server.rs @@ -55,7 +55,6 @@ use std::task::{Context, Poll, Waker}; use std::time::Duration; #[cfg(feature = "dist-client")] use std::time::Instant; -use std::u64; use tokio::sync::Mutex; use tokio::sync::RwLock; use tokio::{ diff --git a/src/test/tests.rs b/src/test/tests.rs index d5c3ee0e9..cf41b04cf 100644 --- a/src/test/tests.rs +++ b/src/test/tests.rs @@ -34,7 +34,6 @@ use std::process::Command; use std::sync::{mpsc, Arc, Mutex}; use std::thread; use std::time::Duration; -use std::u64; use tokio::runtime::Runtime; /// Options for running the server in tests. diff --git a/src/util.rs b/src/util.rs index 2000ae832..9e5ea4d0a 100644 --- a/src/util.rs +++ b/src/util.rs @@ -938,13 +938,50 @@ pub fn daemonize() -> Result<()> { /// /// More details could be found at https://github.com/mozilla/sccache/pull/1563 #[cfg(any(feature = "dist-server", feature = "dist-client"))] -pub fn new_reqwest_blocking_client() -> reqwest::blocking::Client { - reqwest::blocking::Client::builder() +pub fn new_reqwest_client() -> reqwest::Client { + reqwest::Client::builder() .pool_max_idle_per_host(0) .build() .expect("http client must build with success") } +// This function builds a custom `native-tls`-based `reqwest` client. +// +// It main goal is to dodge the currently existing issue that `request` +// is not able to connect to tls hosts by their IP addrs since it tries +// to put these addrs into the SNI extentions. As of this day falling back +// to a `native-tls` backend seems to be the only way to disable the `SNI` feature +// in `request`. Also all the intended root certificates have to be passed +// to the `native-tls` builder; using the higher-level `request` bulider API will +// not work. +// +// More context: +// https://github.com/seanmonstar/reqwest/issues/1328 +// https://github.com/briansmith/webpki/issues/54 +#[cfg(any(feature = "dist-client", feature = "dist-server"))] +pub fn native_tls_no_sni_client_builder(root_certs: I) -> Result +where + I: Iterator, + T: AsRef<[u8]>, +{ + let mut tls_builder = native_tls::TlsConnector::builder(); + + for root_cert in root_certs { + tls_builder.add_root_certificate(native_tls::Certificate::from_pem(root_cert.as_ref())?); + } + + tls_builder.use_sni(false); + + let tls = tls_builder.build()?; + + let client_builder = reqwest::ClientBuilder::new() + .pool_max_idle_per_host(0) + .use_native_tls() + .use_preconfigured_tls(tls); + + Ok(client_builder) +} + #[cfg(test)] mod tests { use super::{OsStrExt, TimeMacroFinder}; diff --git a/tests/dist.rs b/tests/dist.rs index 3db27d115..c67d6e35b 100644 --- a/tests/dist.rs +++ b/tests/dist.rs @@ -7,14 +7,16 @@ extern crate sccache; extern crate serde_json; use crate::harness::{ - get_stats, sccache_command, start_local_daemon, stop_local_daemon, write_json_cfg, write_source, + get_stats, start_local_daemon, stop_local_daemon, write_json_cfg, write_source, }; -use assert_cmd::prelude::*; +use async_trait::async_trait; +use harness::sccache_command; use sccache::config::HTTPUrl; use sccache::dist::{ AssignJobResult, CompileCommand, InputsReader, JobId, JobState, RunJobResult, ServerIncoming, ServerOutgoing, SubmitToolchainResult, Toolchain, ToolchainReader, }; +use serial_test::serial; use std::ffi::OsStr; use std::path::Path; @@ -22,7 +24,7 @@ use sccache::errors::*; mod harness; -fn basic_compile(tmpdir: &Path, sccache_cfg_path: &Path, sccache_cached_cfg_path: &Path) { +async fn basic_compile(tmpdir: &Path, sccache_cfg_path: &Path, sccache_cached_cfg_path: &Path) { let envs: Vec<(_, &OsStr)> = vec![ ("RUST_BACKTRACE", "1".as_ref()), ("SCCACHE_LOG", "debug".as_ref()), @@ -32,7 +34,10 @@ fn basic_compile(tmpdir: &Path, sccache_cfg_path: &Path, sccache_cached_cfg_path let source_file = "x.c"; let obj_file = "x.o"; write_source(tmpdir, source_file, "#if !defined(SCCACHE_TEST_DEFINE)\n#error SCCACHE_TEST_DEFINE is not defined\n#endif\nint x() { return 5; }"); - sccache_command() + + let mut command: tokio::process::Command = sccache_command().into(); + + let _ = command .args([ std::env::var("CC") .unwrap_or_else(|_| "gcc".to_string()) @@ -44,7 +49,9 @@ fn basic_compile(tmpdir: &Path, sccache_cfg_path: &Path, sccache_cached_cfg_path .arg("-o") .arg(tmpdir.join(obj_file)) .envs(envs) - .assert() + .status() + .await + .unwrap() .success(); } @@ -58,9 +65,10 @@ pub fn dist_test_sccache_client_cfg( sccache_cfg } -#[test] +#[tokio::test] #[cfg_attr(not(feature = "dist-tests"), ignore)] -fn test_dist_basic() { +#[serial] +async fn test_dist_basic() { let tmpdir = tempfile::Builder::new() .prefix("sccache_dist_test") .tempdir() @@ -69,8 +77,8 @@ fn test_dist_basic() { let sccache_dist = harness::sccache_dist_path(); let mut system = harness::DistSystem::new(&sccache_dist, tmpdir); - system.add_scheduler(); - system.add_server(); + system.add_scheduler().await; + system.add_server().await; let sccache_cfg = dist_test_sccache_client_cfg(tmpdir, system.scheduler_url()); let sccache_cfg_path = tmpdir.join("sccache-cfg.json"); @@ -79,7 +87,7 @@ fn test_dist_basic() { stop_local_daemon(); start_local_daemon(&sccache_cfg_path, &sccache_cached_cfg_path); - basic_compile(tmpdir, &sccache_cfg_path, &sccache_cached_cfg_path); + basic_compile(tmpdir, &sccache_cfg_path, &sccache_cached_cfg_path).await; get_stats(|info| { assert_eq!(1, info.stats.dist_compiles.values().sum::()); @@ -91,9 +99,10 @@ fn test_dist_basic() { }); } -#[test] +#[tokio::test] #[cfg_attr(not(feature = "dist-tests"), ignore)] -fn test_dist_restartedserver() { +#[serial] +async fn test_dist_restartedserver() { let tmpdir = tempfile::Builder::new() .prefix("sccache_dist_test") .tempdir() @@ -102,8 +111,8 @@ fn test_dist_restartedserver() { let sccache_dist = harness::sccache_dist_path(); let mut system = harness::DistSystem::new(&sccache_dist, tmpdir); - system.add_scheduler(); - let server_handle = system.add_server(); + system.add_scheduler().await; + let server_handle = system.add_server().await; let sccache_cfg = dist_test_sccache_client_cfg(tmpdir, system.scheduler_url()); let sccache_cfg_path = tmpdir.join("sccache-cfg.json"); @@ -112,10 +121,10 @@ fn test_dist_restartedserver() { stop_local_daemon(); start_local_daemon(&sccache_cfg_path, &sccache_cached_cfg_path); - basic_compile(tmpdir, &sccache_cfg_path, &sccache_cached_cfg_path); + basic_compile(tmpdir, &sccache_cfg_path, &sccache_cached_cfg_path).await; - system.restart_server(&server_handle); - basic_compile(tmpdir, &sccache_cfg_path, &sccache_cached_cfg_path); + system.restart_server(&server_handle).await; + basic_compile(tmpdir, &sccache_cfg_path, &sccache_cached_cfg_path).await; get_stats(|info| { assert_eq!(2, info.stats.dist_compiles.values().sum::()); @@ -127,9 +136,10 @@ fn test_dist_restartedserver() { }); } -#[test] +#[tokio::test] #[cfg_attr(not(feature = "dist-tests"), ignore)] -fn test_dist_nobuilder() { +#[serial] +async fn test_dist_nobuilder() { let tmpdir = tempfile::Builder::new() .prefix("sccache_dist_test") .tempdir() @@ -138,7 +148,7 @@ fn test_dist_nobuilder() { let sccache_dist = harness::sccache_dist_path(); let mut system = harness::DistSystem::new(&sccache_dist, tmpdir); - system.add_scheduler(); + system.add_scheduler().await; let sccache_cfg = dist_test_sccache_client_cfg(tmpdir, system.scheduler_url()); let sccache_cfg_path = tmpdir.join("sccache-cfg.json"); @@ -147,7 +157,7 @@ fn test_dist_nobuilder() { stop_local_daemon(); start_local_daemon(&sccache_cfg_path, &sccache_cached_cfg_path); - basic_compile(tmpdir, &sccache_cfg_path, &sccache_cached_cfg_path); + basic_compile(tmpdir, &sccache_cfg_path, &sccache_cached_cfg_path).await; get_stats(|info| { assert_eq!(0, info.stats.dist_compiles.values().sum::()); @@ -160,8 +170,9 @@ fn test_dist_nobuilder() { } struct FailingServer; +#[async_trait] impl ServerIncoming for FailingServer { - fn handle_assign_job(&self, _job_id: JobId, _tc: Toolchain) -> Result { + async fn handle_assign_job(&self, _job_id: JobId, _tc: Toolchain) -> Result { let need_toolchain = false; let state = JobState::Ready; Ok(AssignJobResult { @@ -169,32 +180,34 @@ impl ServerIncoming for FailingServer { state, }) } - fn handle_submit_toolchain( + async fn handle_submit_toolchain( &self, _requester: &dyn ServerOutgoing, _job_id: JobId, - _tc_rdr: ToolchainReader, + _tc_rdr: ToolchainReader<'_>, ) -> Result { panic!("should not have submitted toolchain") } - fn handle_run_job( + async fn handle_run_job( &self, requester: &dyn ServerOutgoing, job_id: JobId, _command: CompileCommand, _outputs: Vec, - _inputs_rdr: InputsReader, + _inputs_rdr: InputsReader<'_>, ) -> Result { requester .do_update_job_state(job_id, JobState::Started) + .await .context("Updating job state failed")?; bail!("internal build failure") } } -#[test] +#[tokio::test] #[cfg_attr(not(feature = "dist-tests"), ignore)] -fn test_dist_failingserver() { +#[serial] +async fn test_dist_failingserver() { let tmpdir = tempfile::Builder::new() .prefix("sccache_dist_test") .tempdir() @@ -203,9 +216,9 @@ fn test_dist_failingserver() { let sccache_dist = harness::sccache_dist_path(); let mut system = harness::DistSystem::new(&sccache_dist, tmpdir); - system.add_scheduler(); - system.add_custom_server(FailingServer); + system.add_scheduler().await; + let handle = system.add_custom_server(FailingServer).await; let sccache_cfg = dist_test_sccache_client_cfg(tmpdir, system.scheduler_url()); let sccache_cfg_path = tmpdir.join("sccache-cfg.json"); write_json_cfg(tmpdir, "sccache-cfg.json", &sccache_cfg); @@ -213,7 +226,7 @@ fn test_dist_failingserver() { stop_local_daemon(); start_local_daemon(&sccache_cfg_path, &sccache_cached_cfg_path); - basic_compile(tmpdir, &sccache_cfg_path, &sccache_cached_cfg_path); + basic_compile(tmpdir, &sccache_cfg_path, &sccache_cached_cfg_path).await; get_stats(|info| { assert_eq!(0, info.stats.dist_compiles.values().sum::()); @@ -223,4 +236,9 @@ fn test_dist_failingserver() { assert_eq!(0, info.stats.cache_hits.all()); assert_eq!(1, info.stats.cache_misses.all()); }); + stop_local_daemon(); + if let harness::ServerHandle::AsyncTask { handle, url: _ } = handle { + handle.abort(); + let _ = handle.await; + } } diff --git a/tests/harness/mod.rs b/tests/harness/mod.rs index f5997934c..186390620 100644 --- a/tests/harness/mod.rs +++ b/tests/harness/mod.rs @@ -1,28 +1,24 @@ use fs_err as fs; +// use nix::unistd::ForkResult; #[cfg(any(feature = "dist-client", feature = "dist-server"))] use sccache::config::HTTPUrl; use sccache::dist::{self, SchedulerStatusResult, ServerId}; use sccache::server::ServerInfo; use std::env; use std::io::Write; -use std::net::{self, IpAddr, SocketAddr}; +use std::net::{IpAddr, SocketAddr}; use std::path::{Path, PathBuf}; use std::process::{Command, Output, Stdio}; use std::str::{self, FromStr}; use std::thread; -use std::time::{Duration, Instant}; +use std::time::Duration; +use tokio::net; use assert_cmd::prelude::*; -#[cfg(feature = "dist-server")] -use nix::{ - sys::{ - signal::Signal, - wait::{WaitPidFlag, WaitStatus}, - }, - unistd::{ForkResult, Pid}, -}; use predicates::prelude::*; use serde::Serialize; +#[cfg(feature = "dist-server")] +use tokio::task::JoinHandle; use uuid::Uuid; const CONTAINER_NAME_PREFIX: &str = "sccache_dist_test"; @@ -212,8 +208,14 @@ fn create_server_token(server_id: ServerId, auth_token: &str) -> String { #[cfg(feature = "dist-server")] pub enum ServerHandle { - Container { cid: String, url: HTTPUrl }, - Process { pid: Pid, url: HTTPUrl }, + Container { + cid: String, + url: HTTPUrl, + }, + AsyncTask { + handle: JoinHandle<()>, + url: HTTPUrl, + }, } #[cfg(feature = "dist-server")] @@ -223,7 +225,8 @@ pub struct DistSystem { scheduler_name: Option, server_names: Vec, - server_pids: Vec, + server_handles: Vec>, + client: reqwest::Client, } #[cfg(feature = "dist-server")] @@ -249,17 +252,20 @@ impl DistSystem { let tmpdir = tmpdir.join("distsystem"); fs::create_dir(&tmpdir).unwrap(); + let client = native_tls_no_sni_client_builder_danger().build().unwrap(); + Self { sccache_dist: sccache_dist.to_owned(), tmpdir, scheduler_name: None, server_names: vec![], - server_pids: vec![], + server_handles: vec![], + client, } } - pub fn add_scheduler(&mut self) { + pub async fn add_scheduler(&mut self) { let scheduler_cfg_relpath = "scheduler-cfg.json"; let scheduler_cfg_path = self.tmpdir.join(scheduler_cfg_relpath); let scheduler_cfg_container_path = @@ -312,29 +318,40 @@ impl DistSystem { check_output(&output); let scheduler_url = self.scheduler_url(); - wait_for_http(scheduler_url, Duration::from_millis(100), MAX_STARTUP_WAIT); - wait_for( - || { + wait_for_http( + &self.client, + scheduler_url, + Duration::from_millis(100), + MAX_STARTUP_WAIT, + ) + .await; + + let status_fut = async move { + loop { let status = self.scheduler_status(); - if matches!( - status, - SchedulerStatusResult { - num_servers: 0, - num_cpus: _, - in_progress: 0 + + tokio::select! { + s = status => { + if matches!( + s, + SchedulerStatusResult { + num_servers: 0, + num_cpus: _, + in_progress: 0 + } + ) { + break Ok(()); + } } - ) { - Ok(()) - } else { - Err(format!("{:?}", status)) + _ = tokio::time::sleep(Duration::from_millis(100)) => {} } - }, - Duration::from_millis(100), - MAX_STARTUP_WAIT, - ); + } + }; + + wait_for(status_fut, MAX_STARTUP_WAIT).await; } - pub fn add_server(&mut self) -> ServerHandle { + pub async fn add_server(&mut self) -> ServerHandle { let server_cfg_relpath = format!("server-cfg-{}.json", self.server_names.len()); let server_cfg_path = self.tmpdir.join(&server_cfg_relpath); let server_cfg_container_path = Path::new(CONFIGS_CONTAINER_PATH).join(server_cfg_relpath); @@ -395,86 +412,90 @@ impl DistSystem { cid: server_name, url, }; - self.wait_server_ready(&handle); + self.wait_server_ready(&handle).await; handle } - pub fn add_custom_server( + pub async fn add_custom_server( &mut self, handler: S, ) -> ServerHandle { let server_addr = { let ip = IpAddr::from_str("127.0.0.1").unwrap(); - let listener = net::TcpListener::bind(SocketAddr::from((ip, 0))).unwrap(); + let listener = net::TcpListener::bind(SocketAddr::from((ip, 12346))) + .await + .unwrap(); listener.local_addr().unwrap() }; let token = create_server_token(ServerId::new(server_addr), DIST_SERVER_TOKEN); let server = dist::http::Server::new(server_addr, self.scheduler_url().to_url(), token, handler) .unwrap(); - let pid = match unsafe { nix::unistd::fork() }.unwrap() { - ForkResult::Parent { child } => { - self.server_pids.push(child); - child - } - ForkResult::Child => { - env::set_var("SCCACHE_LOG", "sccache=trace"); - env_logger::try_init().unwrap(); - server.start().unwrap(); - unreachable!(); - } - }; + + let handle = tokio::spawn(async move { + println!("Starting server"); + server.start().await.unwrap(); + println!("Should be unreachable"); + unreachable!(); + }); let url = HTTPUrl::from_url(reqwest::Url::parse(&format!("https://{}", server_addr)).unwrap()); - let handle = ServerHandle::Process { pid, url }; - self.wait_server_ready(&handle); + let handle = ServerHandle::AsyncTask { handle, url }; + self.wait_server_ready(&handle).await; handle } - pub fn restart_server(&mut self, handle: &ServerHandle) { + pub async fn restart_server(&mut self, handle: &ServerHandle) { match handle { ServerHandle::Container { cid, url: _ } => { - let output = Command::new("docker") - .args(["restart", cid]) - .output() - .unwrap(); + let output = Command::new("docker").args(["restart", cid]).unwrap(); check_output(&output); } - ServerHandle::Process { pid: _, url: _ } => { + ServerHandle::AsyncTask { handle: _, url: _ } => { // TODO: pretty easy, just no need yet panic!("restart not yet implemented for pids") } } - self.wait_server_ready(handle) + self.wait_server_ready(handle).await } - pub fn wait_server_ready(&mut self, handle: &ServerHandle) { + pub async fn wait_server_ready(&mut self, handle: &ServerHandle) { let url = match handle { - ServerHandle::Container { cid: _, url } | ServerHandle::Process { pid: _, url } => { - url.clone() - } + ServerHandle::Container { cid: _, url } + | ServerHandle::AsyncTask { handle: _, url } => url.clone(), }; - wait_for_http(url, Duration::from_millis(100), MAX_STARTUP_WAIT); - wait_for( - || { + wait_for_http( + &self.client, + url, + Duration::from_millis(100), + MAX_STARTUP_WAIT, + ) + .await; + + let status_fut = async move { + loop { let status = self.scheduler_status(); - if matches!( - status, - SchedulerStatusResult { - num_servers: 1, - num_cpus: _, - in_progress: 0 + + tokio::select! { + s = status => { + if matches!( + s, + SchedulerStatusResult { + num_servers: 1, + num_cpus: _, + in_progress: 0 + } + ) { + break Ok(()); + } } - ) { - Ok(()) - } else { - Err(format!("{:?}", status)) + _ = tokio::time::sleep(Duration::from_millis(100)) => {} } - }, - Duration::from_millis(100), - MAX_STARTUP_WAIT, - ); + } + }; + + wait_for(status_fut, MAX_STARTUP_WAIT).await; } pub fn scheduler_url(&self) -> HTTPUrl { @@ -482,13 +503,14 @@ impl DistSystem { HTTPUrl::from_url(reqwest::Url::parse(&url).unwrap()) } - fn scheduler_status(&self) -> SchedulerStatusResult { - let res = reqwest::blocking::get(dist::http::urls::scheduler_status( - &self.scheduler_url().to_url(), - )) - .unwrap(); + async fn scheduler_status(&self) -> SchedulerStatusResult { + let url = dist::http::urls::scheduler_status(&self.scheduler_url().to_url()); + let client = reqwest::Client::new(); + + let res = client.get(url).send().await.unwrap(); assert!(res.status().is_success()); - bincode::deserialize_from(res).unwrap() + let bytes = res.bytes().await.unwrap(); + bincode::deserialize_from(bytes.as_ref()).unwrap() } } @@ -515,7 +537,6 @@ impl Drop for DistSystem { let mut logs = vec![]; let mut outputs = vec![]; - let mut exits = vec![]; if let Some(scheduler_name) = self.scheduler_name.as_ref() { droperr!(Command::new("docker") @@ -545,31 +566,9 @@ impl Drop for DistSystem { .output() .map(|o| outputs.push((server_name, o)))); } - for &pid in self.server_pids.iter() { - droperr!(nix::sys::signal::kill(pid, Signal::SIGINT)); - thread::sleep(Duration::from_millis(100)); - let mut killagain = true; // Default to trying to kill again, e.g. if there was an error waiting on the pid - droperr!( - nix::sys::wait::waitpid(pid, Some(WaitPidFlag::WNOHANG)).map(|ws| { - if ws != WaitStatus::StillAlive { - killagain = false; - exits.push(ws) - } - }) - ); - if killagain { - eprintln!("SIGINT didn't kill process, trying SIGKILL"); - droperr!(nix::sys::signal::kill(pid, Signal::SIGKILL)); - droperr!(nix::sys::wait::waitpid(pid, Some(WaitPidFlag::WNOHANG)) - .map_err(|e| e.to_string()) - .and_then(|ws| if ws == WaitStatus::StillAlive { - Err("process alive after sigkill".to_owned()) - } else { - exits.push(ws); - Ok(()) - })); - } - } + // TODO: they will die with the runtime, but correctly waiting for them + // may be only possible when we have async Drop. + for _handle in self.server_handles.iter() {} for ( container, @@ -605,9 +604,6 @@ impl Drop for DistSystem { String::from_utf8_lossy(&stderr) ); } - for exit in exits { - println!("EXIT: {:?}", exit) - } if did_err && !thread::panicking() { panic!("Encountered failures during dist system teardown") @@ -633,34 +629,46 @@ fn check_output(output: &Output) { } #[cfg(feature = "dist-server")] -fn wait_for_http(url: HTTPUrl, interval: Duration, max_wait: Duration) { - // TODO: after upgrading to reqwest >= 0.9, use 'danger_accept_invalid_certs' and stick with that rather than tcp - wait_for( - || { - let url = url.to_url(); - let url = url.socket_addrs(|| None).unwrap(); - match net::TcpStream::connect(url.as_slice()) { - Ok(_) => Ok(()), - Err(e) => Err(e.to_string()), - } - }, - interval, - max_wait, - ) +fn native_tls_no_sni_client_builder_danger() -> reqwest::ClientBuilder { + let tls = native_tls::TlsConnector::builder() + .danger_accept_invalid_certs(true) + .danger_accept_invalid_hostnames(true) + .use_sni(false) + .build() + .unwrap(); + + reqwest::ClientBuilder::new() + .pool_max_idle_per_host(0) + .use_native_tls() + .use_preconfigured_tls(tls) } -fn wait_for Result<(), String>>(f: F, interval: Duration, max_wait: Duration) { - let start = Instant::now(); - let mut lasterr; - loop { - match f() { - Ok(()) => return, - Err(e) => lasterr = e, - } - if start.elapsed() > max_wait { - break; +#[cfg(feature = "dist-server")] +async fn wait_for_http( + client: &reqwest::Client, + url: HTTPUrl, + interval: Duration, + max_wait: Duration, +) { + let try_connect = async move { + let url = url.to_url(); + + loop { + if let Ok(Ok(_)) = tokio::time::timeout(interval, client.get(url.clone()).send()).await + { + break; + } } - thread::sleep(interval) + }; + + if let Err(e) = tokio::time::timeout(max_wait, try_connect).await { + panic!("wait timed out, last error result: {}", e) } - panic!("wait timed out, last error result: {}", lasterr) +} + +async fn wait_for>>(f: F, max_wait: Duration) { + tokio::time::timeout(max_wait, f) + .await + .unwrap() + .expect("wait timed out"); } diff --git a/tests/system.rs b/tests/system.rs index 386805a24..78a070282 100644 --- a/tests/system.rs +++ b/tests/system.rs @@ -207,7 +207,7 @@ fn test_basic_compile(compiler: Compiler, tempdir: &Path) { let out_file = tempdir.join(OUTPUT); trace!("compile"); sccache_command() - .args(&compile_cmdline(name, &exe, INPUT, OUTPUT, Vec::new())) + .args(compile_cmdline(name, &exe, INPUT, OUTPUT, Vec::new())) .current_dir(tempdir) .envs(env_vars.clone()) .assert() @@ -226,7 +226,7 @@ fn test_basic_compile(compiler: Compiler, tempdir: &Path) { trace!("compile"); fs::remove_file(&out_file).unwrap(); sccache_command() - .args(&compile_cmdline(name, &exe, INPUT, OUTPUT, Vec::new())) + .args(compile_cmdline(name, &exe, INPUT, OUTPUT, Vec::new())) .current_dir(tempdir) .envs(env_vars) .assert() @@ -564,7 +564,7 @@ fn test_cuda_compiles(compiler: &Compiler, tempdir: &Path) { let out_file = tempdir.join(OUTPUT); trace!("compile A"); sccache_command() - .args(&compile_cuda_cmdline( + .args(compile_cuda_cmdline( name, exe, INPUT_FOR_CUDA_A, @@ -589,7 +589,7 @@ fn test_cuda_compiles(compiler: &Compiler, tempdir: &Path) { trace!("compile A"); fs::remove_file(&out_file).unwrap(); sccache_command() - .args(&compile_cuda_cmdline( + .args(compile_cuda_cmdline( name, exe, INPUT_FOR_CUDA_A, @@ -617,7 +617,7 @@ fn test_cuda_compiles(compiler: &Compiler, tempdir: &Path) { // phase is correctly running and outputting text trace!("compile B"); sccache_command() - .args(&compile_cuda_cmdline( + .args(compile_cuda_cmdline( name, exe, INPUT_FOR_CUDA_B, @@ -658,7 +658,7 @@ fn test_proper_lang_stat_tracking(compiler: Compiler, tempdir: &Path) { let out_file = tempdir.join(OUTPUT); trace!("compile CUDA A"); sccache_command() - .args(&compile_cmdline( + .args(compile_cmdline( name, &exe, INPUT_FOR_CUDA_C, @@ -672,7 +672,7 @@ fn test_proper_lang_stat_tracking(compiler: Compiler, tempdir: &Path) { fs::remove_file(&out_file).unwrap(); trace!("compile CUDA A"); sccache_command() - .args(&compile_cmdline( + .args(compile_cmdline( name, &exe, INPUT_FOR_CUDA_C, @@ -686,7 +686,7 @@ fn test_proper_lang_stat_tracking(compiler: Compiler, tempdir: &Path) { fs::remove_file(&out_file).unwrap(); trace!("compile C++ A"); sccache_command() - .args(&compile_cmdline(name, &exe, INPUT, OUTPUT, Vec::new())) + .args(compile_cmdline(name, &exe, INPUT, OUTPUT, Vec::new())) .current_dir(tempdir) .envs(env_vars.clone()) .assert() @@ -694,7 +694,7 @@ fn test_proper_lang_stat_tracking(compiler: Compiler, tempdir: &Path) { fs::remove_file(&out_file).unwrap(); trace!("compile C++ A"); sccache_command() - .args(&compile_cmdline(name, &exe, INPUT, OUTPUT, Vec::new())) + .args(compile_cmdline(name, &exe, INPUT, OUTPUT, Vec::new())) .current_dir(tempdir) .envs(env_vars) .assert() @@ -734,7 +734,7 @@ fn test_hip_compiles(compiler: &Compiler, tempdir: &Path) { let out_file = tempdir.join(OUTPUT); trace!("compile A"); sccache_command() - .args(&compile_hip_cmdline( + .args(compile_hip_cmdline( name, exe, INPUT_FOR_HIP_A, @@ -760,7 +760,7 @@ fn test_hip_compiles(compiler: &Compiler, tempdir: &Path) { trace!("compile A"); fs::remove_file(&out_file).unwrap(); sccache_command() - .args(&compile_hip_cmdline( + .args(compile_hip_cmdline( name, exe, INPUT_FOR_HIP_A, @@ -789,7 +789,7 @@ fn test_hip_compiles(compiler: &Compiler, tempdir: &Path) { // phase is correctly running and outputting text trace!("compile B"); sccache_command() - .args(&compile_hip_cmdline( + .args(compile_hip_cmdline( name, exe, INPUT_FOR_HIP_B, @@ -831,7 +831,7 @@ fn test_hip_compiles_multi_targets(compiler: &Compiler, tempdir: &Path) { let out_file = tempdir.join(OUTPUT); trace!("compile A with gfx900 and gfx1030"); sccache_command() - .args(&compile_hip_cmdline( + .args(compile_hip_cmdline( name, exe, INPUT_FOR_HIP_A, @@ -858,7 +858,7 @@ fn test_hip_compiles_multi_targets(compiler: &Compiler, tempdir: &Path) { trace!("compile A with with gfx900 and gfx1030 again"); fs::remove_file(&out_file).unwrap(); sccache_command() - .args(&compile_hip_cmdline( + .args(compile_hip_cmdline( name, exe, INPUT_FOR_HIP_A, @@ -888,7 +888,7 @@ fn test_hip_compiles_multi_targets(compiler: &Compiler, tempdir: &Path) { // phase is correctly running and outputting text trace!("compile B with gfx900 and gfx1030"); sccache_command() - .args(&compile_hip_cmdline( + .args(compile_hip_cmdline( name, exe, INPUT_FOR_HIP_B, @@ -967,7 +967,7 @@ fn test_clang_cache_whitespace_normalization( println!("compile whitespace"); sccache_command() - .args(&compile_cmdline( + .args(compile_cmdline( name, &exe, INPUT_WITH_WHITESPACE, @@ -988,7 +988,7 @@ fn test_clang_cache_whitespace_normalization( println!("compile whitespace_alt"); sccache_command() - .args(&compile_cmdline( + .args(compile_cmdline( name, &exe, INPUT_WITH_WHITESPACE_ALT, From df88e70325cb7f67a261f0a5d4d85e6fd6691899 Mon Sep 17 00:00:00 2001 From: "sarunas.gincas" Date: Thu, 8 Aug 2024 14:33:37 +0300 Subject: [PATCH 2/3] Refactor Co-authored-by: Fedor Sakharov --- Cargo.toml | 6 +++--- src/dist/http.rs | 2 -- tests/harness/mod.rs | 3 +-- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8a9c60a15..b91932110 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -107,7 +107,7 @@ zstd = "0.13" # dist-server only memmap2 = "0.9.4" -native-tls = "0.2.8" +native-tls = "0.2.12" nix = { version = "0.28.0", optional = true, features = [ "mount", "user", @@ -117,9 +117,9 @@ nix = { version = "0.28.0", optional = true, features = [ ] } object = "0.32" syslog = { version = "6", optional = true } -thiserror = { version = "1.0.30", optional = true } +thiserror = { version = "1.0.63", optional = true } version-compare = { version = "0.1.1", optional = true } -warp = { version = "0.3.2", optional = true, features = ["tls"] } +warp = { version = "0.3.7", optional = true, features = ["tls"] } [dev-dependencies] assert_cmd = "2.0.13" diff --git a/src/dist/http.rs b/src/dist/http.rs index 312ba73b3..6d192c993 100644 --- a/src/dist/http.rs +++ b/src/dist/http.rs @@ -640,7 +640,6 @@ mod server { requester, )) .recover(handle_rejection) - .with(warp::log("warp::requests")) } fn make_401_with_body(short_err: &str, body: Option) -> Response { @@ -975,7 +974,6 @@ mod server { .or(job_state(check_server_auth, s.clone())) .or(status(s)) .recover(handle_rejection) - .with(warp::log("warp::requests")) } // POST /api/v1/scheduler/alloc_job diff --git a/tests/harness/mod.rs b/tests/harness/mod.rs index 186390620..4daf59fc4 100644 --- a/tests/harness/mod.rs +++ b/tests/harness/mod.rs @@ -1,5 +1,4 @@ use fs_err as fs; -// use nix::unistd::ForkResult; #[cfg(any(feature = "dist-client", feature = "dist-server"))] use sccache::config::HTTPUrl; use sccache::dist::{self, SchedulerStatusResult, ServerId}; @@ -422,7 +421,7 @@ impl DistSystem { ) -> ServerHandle { let server_addr = { let ip = IpAddr::from_str("127.0.0.1").unwrap(); - let listener = net::TcpListener::bind(SocketAddr::from((ip, 12346))) + let listener = net::TcpListener::bind(SocketAddr::from((ip, 0))) .await .unwrap(); listener.local_addr().unwrap() From 134e1a25648e925261a3271915ee8be10d68e4ed Mon Sep 17 00:00:00 2001 From: "sarunas.gincas" Date: Thu, 8 Aug 2024 16:23:06 +0300 Subject: [PATCH 3/3] Remove no_sni_client_builder Co-authored-by: Fedor Sakharov --- Cargo.toml | 2 +- src/dist/http.rs | 67 ++++++++++++++++++++++++------------------------ src/util.rs | 37 -------------------------- 3 files changed, 35 insertions(+), 71 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b91932110..adf1564c2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -69,7 +69,7 @@ openssl = { version = "0.10.64", optional = true } rand = "0.8.4" regex = "1.10.3" reqsign = { version = "0.16.0", optional = true } -reqwest = { version = "0.12", features = [ +reqwest = { version = "0.12.5", features = [ "json", "native-tls", "stream", diff --git a/src/dist/http.rs b/src/dist/http.rs index 6d192c993..b1dd7cb47 100644 --- a/src/dist/http.rs +++ b/src/dist/http.rs @@ -843,8 +843,6 @@ mod server { Heartbeat, #[error("failed to update job state")] UpdateJobState, - #[error("failed to create a http client")] - ClientBuildFailed, } impl warp::reject::Reject for Error {} @@ -941,8 +939,7 @@ mod server { | Error::Heartbeat | Error::UpdateJobState | Error::Status - | Error::NoHTTPClient - | Error::ClientBuildFailed => { + | Error::NoHTTPClient => { Ok(err_and_log(e, StatusCode::INTERNAL_SERVER_ERROR)) } } @@ -1320,7 +1317,6 @@ mod server { handler.handle_status().map_err(|_| Error::Status)?; Ok(res) } - async fn maybe_update_certs( client: &mut reqwest::Client, certs: &mut HashMap, Vec)>, @@ -1337,20 +1333,27 @@ mod server { "Adding new certificate for {} to scheduler", server_id.addr() ); - - let _ = native_tls::Certificate::from_pem(&cert_pem) - .map_err(|_| Error::BadCertificate)?; + let mut client_builder = reqwest::ClientBuilder::new(); // Add all the certificates we know about - let root_certs = - std::iter::once(&cert_pem).chain(certs.values().map(|(_, cert_pem)| cert_pem)); - let client_builder = crate::util::native_tls_no_sni_client_builder(root_certs) - .map_err(|_| Error::ClientBuildFailed)?; - - // Finish the clients - let new_client = client_builder.build().map_err(|_| Error::NoHTTPClient)?; + client_builder = client_builder.add_root_certificate( + reqwest::Certificate::from_pem(&cert_pem).map_err(|_| Error::BadCertificate)?, + ); + for (_, cert_pem) in certs.values() { + client_builder = client_builder.add_root_certificate( + reqwest::Certificate::from_pem(cert_pem) + .map_err(|_| Error::BadCertificate)?, + ); + } + // Finish the client + let new_client = client_builder + // Disable connection pool to avoid broken connection + // between runtime + .pool_max_idle_per_host(0) + .build() + .map_err(|_| Error::NoHTTPClient)?; // Use the updated certificates - *client = new_client; certs.insert(server_id, (cert_digest, cert_pem)); + *client = new_client; Ok(()) } } @@ -1387,11 +1390,7 @@ mod server { check_client_auth, check_server_auth, } = self; - let client = - crate::util::native_tls_no_sni_client_builder(std::iter::empty::>()) - .unwrap() - .build() - .unwrap(); + let client = crate::util::new_reqwest_client(); let requester = Arc::new(SchedulerRequester { client: Mutex::new(client), }); @@ -1627,11 +1626,7 @@ mod client { let timeout = Duration::new(REQUEST_TIMEOUT_SECS, 0); let connect_timeout = Duration::new(CONNECT_TIMEOUT_SECS, 0); - let builder = - crate::util::native_tls_no_sni_client_builder(std::iter::empty::>()) - .context("failed to create an async HTTP client")?; - - let client = builder + let client = reqwest::Client::builder() .timeout(timeout) .connect_timeout(connect_timeout) // Disable connection pool to avoid broken connection @@ -1659,21 +1654,27 @@ mod client { cert_digest: Vec, cert_pem: Vec, ) -> Result<()> { + let mut client_async_builder = reqwest::ClientBuilder::new(); // Add all the certificates we know about - let root_certs = std::iter::once(&cert_pem).chain(certs.values()); - let client_builder = crate::util::native_tls_no_sni_client_builder(root_certs) - .context("failed to create an async HTTP client")?; - - // Finish the clients + client_async_builder = client_async_builder.add_root_certificate( + reqwest::Certificate::from_pem(&cert_pem) + .context("failed to interpret pem as certificate")?, + ); + for cert_pem in certs.values() { + client_async_builder = client_async_builder.add_root_certificate( + reqwest::Certificate::from_pem(cert_pem).expect("previously valid cert"), + ); + } + // Finish the client let timeout = Duration::new(REQUEST_TIMEOUT_SECS, 0); - let new_client = client_builder + let new_client_async = client_async_builder .timeout(timeout) // Disable keep-alive .pool_max_idle_per_host(0) .build() .context("failed to create an async HTTP client")?; // Use the updated certificates - *client = new_client; + *client = new_client_async; certs.insert(cert_digest, cert_pem); Ok(()) } diff --git a/src/util.rs b/src/util.rs index 9e5ea4d0a..a2868a192 100644 --- a/src/util.rs +++ b/src/util.rs @@ -945,43 +945,6 @@ pub fn new_reqwest_client() -> reqwest::Client { .expect("http client must build with success") } -// This function builds a custom `native-tls`-based `reqwest` client. -// -// It main goal is to dodge the currently existing issue that `request` -// is not able to connect to tls hosts by their IP addrs since it tries -// to put these addrs into the SNI extentions. As of this day falling back -// to a `native-tls` backend seems to be the only way to disable the `SNI` feature -// in `request`. Also all the intended root certificates have to be passed -// to the `native-tls` builder; using the higher-level `request` bulider API will -// not work. -// -// More context: -// https://github.com/seanmonstar/reqwest/issues/1328 -// https://github.com/briansmith/webpki/issues/54 -#[cfg(any(feature = "dist-client", feature = "dist-server"))] -pub fn native_tls_no_sni_client_builder(root_certs: I) -> Result -where - I: Iterator, - T: AsRef<[u8]>, -{ - let mut tls_builder = native_tls::TlsConnector::builder(); - - for root_cert in root_certs { - tls_builder.add_root_certificate(native_tls::Certificate::from_pem(root_cert.as_ref())?); - } - - tls_builder.use_sni(false); - - let tls = tls_builder.build()?; - - let client_builder = reqwest::ClientBuilder::new() - .pool_max_idle_per_host(0) - .use_native_tls() - .use_preconfigured_tls(tls); - - Ok(client_builder) -} - #[cfg(test)] mod tests { use super::{OsStrExt, TimeMacroFinder};