diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f80f9273b3085a7f00396128f4bbe9249614fc8a..79b83de015af1072e28064f479b5467c1bf0f5bd 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -66,7 +66,7 @@ rust-nightly-clippy: - target/ <<: *rust_template script: - - cargo clippy --all --verbose -- -D warnings + - cargo clippy --all --tests --verbose -- -D warnings rust-nightly-docker: stage: image @@ -96,3 +96,24 @@ helm-lint: changes: - contrib/chart/**/* script: /usr/bin/helm lint contrib/charts/espresso + +pages: + stage: build + image: rustlang/rust:nightly + needs: + - rust-nightly + cache: + key: "$CI_COMMIT_REF_SLUG" + paths: + - cargo/ + - target/ + policy: pull + <<: *rust_template + script: + - cargo doc --no-deps + - rm -rf public + - mkdir public + - cp -R target/doc/* public + artifacts: + paths: + - public diff --git a/Cargo.lock b/Cargo.lock index ae06f6038a9cb96f3b855f2d3ba40238b170bf30..7bbac100b6fcbcd37621bf6c1af98b8f8fd29b4c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,28 +1,29 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "actix" -version = "0.9.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4af87564ff659dee8f9981540cac9418c45e910c8072fdedd643a262a38fcaf" +checksum = "f728064aca1c318585bf4bb04ffcfac9e75e508ab4e8b1bd9ba5dfe04e2cbed5" dependencies = [ - "actix-http", - "actix-rt", + "actix-rt 2.7.0", "actix_derive", "bitflags", - "bytes", + "bytes 1.2.1", "crossbeam-channel", - "derive_more", - "futures", - "lazy_static", + "futures-core", + "futures-sink", + "futures-task", + "futures-util", "log", - "parking_lot 0.10.2", - "pin-project", + "once_cell", + "parking_lot 0.12.1", + "pin-project-lite 0.2.9", "smallvec", - "tokio", - "tokio-util 0.2.0", - "trust-dns-proto", - "trust-dns-resolver", + "tokio 1.21.2", + "tokio-util 0.7.4", ] [[package]] @@ -32,24 +33,41 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09e55f0a5c2ca15795035d90c46bd0e73a5123b72f68f12596d6ba5282051380" dependencies = [ "bitflags", - "bytes", + "bytes 0.5.6", "futures-core", "futures-sink", "log", - "tokio", + "tokio 0.2.25", "tokio-util 0.2.0", ] +[[package]] +name = "actix-codec" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57a7559404a7f3573127aab53c08ce37a6c6a315c374a31070f3c91cd1b4a7fe" +dependencies = [ + "bitflags", + "bytes 1.2.1", + "futures-core", + "futures-sink", + "log", + "memchr", + "pin-project-lite 0.2.9", + "tokio 1.21.2", + "tokio-util 0.7.4", +] + [[package]] name = "actix-connect" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c95cc9569221e9802bf4c377f6c18b90ef10227d787611decf79fd47d2a8e76c" dependencies = [ - "actix-codec", - "actix-rt", - "actix-service", - "actix-utils", + "actix-codec 0.2.0", + "actix-rt 1.1.1", + "actix-service 1.0.6", + "actix-utils 1.0.6", "derive_more", "either", "futures", @@ -59,58 +77,151 @@ dependencies = [ "trust-dns-resolver", ] +[[package]] +name = "actix-files" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d832782fac6ca7369a70c9ee9a20554623c5e51c76e190ad151780ebea1cf689" +dependencies = [ + "actix-http 3.2.2", + "actix-service 2.0.2", + "actix-utils 3.0.1", + "actix-web", + "askama_escape", + "bitflags", + "bytes 1.2.1", + "derive_more", + "futures-core", + "http-range", + "log", + "mime", + "mime_guess", + "percent-encoding", + "pin-project-lite 0.2.9", +] + [[package]] name = "actix-http" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c16664cc4fdea8030837ad5a845eb231fb93fc3c5c171edfefb52fad92ce9019" dependencies = [ - "actix-codec", + "actix-codec 0.2.0", "actix-connect", - "actix-rt", - "actix-service", + "actix-rt 1.1.1", + "actix-service 1.0.6", "actix-threadpool", - "actix-utils", + "actix-utils 1.0.6", "base64 0.11.0", "bitflags", - "brotli2", - "bytes", + "bytes 0.5.6", "chrono", "copyless", "derive_more", "either", "encoding_rs", - "failure", - "flate2", "futures-channel", "futures-core", "futures-util", "fxhash", - "h2", + "h2 0.2.7", "http", "httparse", "indexmap", - "language-tags", + "language-tags 0.2.2", "lazy_static", "log", "mime", "percent-encoding", - "pin-project", - "rand", + "pin-project 0.4.30", + "rand 0.7.3", "regex", "serde", "serde_json", - "serde_urlencoded", - "sha1", + "serde_urlencoded 0.6.1", + "sha1 0.6.1", + "slab", + "time 0.1.44", +] + +[[package]] +name = "actix-http" +version = "3.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c83abf9903e1f0ad9973cc4f7b9767fd5a03a583f51a5b7a339e07987cd2724" +dependencies = [ + "actix-codec 0.5.0", + "actix-rt 2.7.0", + "actix-service 2.0.2", + "actix-utils 3.0.1", + "ahash", + "base64 0.13.1", + "bitflags", + "brotli", + "bytes 1.2.1", + "bytestring", + "derive_more", + "encoding_rs", + "flate2", + "futures-core", + "h2 0.3.15", + "http", + "httparse", + "httpdate", + "itoa 1.0.4", + "language-tags 0.3.2", + "local-channel", + "mime", + "percent-encoding", + "pin-project-lite 0.2.9", + "rand 0.8.5", + "sha1 0.10.5", + "smallvec", + "tracing", + "zstd", +] + +[[package]] +name = "actix-http-test" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40511826540d084fbcd68ee65b75b1849961c1760a193b09180a4851f20075b" +dependencies = [ + "actix-codec 0.5.0", + "actix-rt 2.7.0", + "actix-server", + "actix-service 2.0.2", + "actix-tls", + "actix-utils 3.0.1", + "awc", + "base64 0.13.1", + "bytes 1.2.1", + "futures-core", + "http", + "log", + "serde", + "serde_json", + "serde_urlencoded 0.7.1", "slab", - "time 0.1.43", + "socket2 0.4.7", + "tokio 1.21.2", ] [[package]] name = "actix-macros" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a60f9ba7c4e6df97f3aacb14bb5c0cd7d98a49dcbaed0d7f292912ad9a6a3ed2" +checksum = "b4ca8ce00b267af8ccebbd647de0d61e0674b6e61185cc7a592ff88772bed655" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "actix-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "465a6172cf69b960917811022d8f29bc0b7fa1398bc4f78b3c466673db1213b6" dependencies = [ "quote", "syn", @@ -118,15 +229,15 @@ dependencies = [ [[package]] name = "actix-router" -version = "0.2.4" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d7a10ca4d94e8c8e7a87c5173aba1b97ba9a6563ca02b0e1cd23531093d3ec8" +checksum = "d66ff4d247d2b160861fa2866457e85706833527840e4133f8f49aa423a38799" dependencies = [ "bytestring", "http", - "log", "regex", "serde", + "tracing", ] [[package]] @@ -135,33 +246,42 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "143fcc2912e0d1de2bcf4e2f720d2a60c28652ab4179685a1ee159e0fb3db227" dependencies = [ - "actix-macros", + "actix-macros 0.1.3", "actix-threadpool", "copyless", "futures-channel", "futures-util", "smallvec", - "tokio", + "tokio 0.2.25", +] + +[[package]] +name = "actix-rt" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ea16c295198e958ef31930a6ef37d0fb64e9ca3b6116e6b93a8bdae96ee1000" +dependencies = [ + "actix-macros 0.2.3", + "futures-core", + "tokio 1.21.2", ] [[package]] name = "actix-server" -version = "1.0.3" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d74b464215a473c973a2d7d03a69cc10f4ce1f4b38a7659c5193dc5c675630" +checksum = "0da34f8e659ea1b077bb4637948b815cd3768ad5a188fdcd74ff4d84240cd824" dependencies = [ - "actix-codec", - "actix-rt", - "actix-service", - "actix-utils", - "futures-channel", + "actix-rt 2.7.0", + "actix-service 2.0.2", + "actix-utils 3.0.1", + "futures-core", "futures-util", - "log", - "mio", - "mio-uds", + "mio 0.8.5", "num_cpus", - "slab", - "socket2", + "socket2 0.4.7", + "tokio 1.21.2", + "tracing", ] [[package]] @@ -171,21 +291,41 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0052435d581b5be835d11f4eb3bce417c8af18d87ddf8ace99f8e67e595882bb" dependencies = [ "futures-util", - "pin-project", + "pin-project 0.4.30", ] [[package]] -name = "actix-testing" -version = "1.0.1" +name = "actix-service" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47239ca38799ab74ee6a8a94d1ce857014b2ac36f242f70f3f75a66f691e791c" +checksum = "3b894941f818cfdc7ccc4b9e60fa7e53b5042a2e8567270f9147d5591893373a" dependencies = [ - "actix-macros", - "actix-rt", - "actix-server", - "actix-service", + "futures-core", + "paste", + "pin-project-lite 0.2.9", +] + +[[package]] +name = "actix-test" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "546b075f2ee13e081a040b60b95a08f0eceaac6bc759309026611234dc80abfe" +dependencies = [ + "actix-codec 0.5.0", + "actix-http 3.2.2", + "actix-http-test", + "actix-rt 2.7.0", + "actix-service 2.0.2", + "actix-utils 3.0.1", + "actix-web", + "awc", + "futures-core", + "futures-util", "log", - "socket2", + "serde", + "serde_json", + "serde_urlencoded 0.7.1", + "tokio 1.21.2", ] [[package]] @@ -199,24 +339,25 @@ dependencies = [ "lazy_static", "log", "num_cpus", - "parking_lot 0.11.0", + "parking_lot 0.11.2", "threadpool", ] [[package]] name = "actix-tls" -version = "1.0.0" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4e5b4faaf105e9a6d389c606c298dcdb033061b00d532af9df56ff3a54995a8" +checksum = "9fde0cf292f7cdc7f070803cb9a0d45c018441321a78b1042ffbbb81ec333297" dependencies = [ - "actix-codec", - "actix-rt", - "actix-service", - "actix-utils", - "derive_more", - "either", - "futures", + "actix-codec 0.5.0", + "actix-rt 2.7.0", + "actix-service 2.0.2", + "actix-utils 3.0.1", + "futures-core", + "http", "log", + "pin-project-lite 0.2.9", + "tokio-util 0.7.4", ] [[package]] @@ -225,60 +366,76 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcf8f5631bf01adec2267808f00e228b761c60c0584cc9fa0b5364f41d147f4e" dependencies = [ - "actix-codec", - "actix-rt", - "actix-service", + "actix-codec 0.2.0", + "actix-rt 1.1.1", + "actix-service 1.0.6", "bitflags", - "bytes", + "bytes 0.5.6", "either", "futures", "log", - "pin-project", + "pin-project 0.4.30", "slab", ] +[[package]] +name = "actix-utils" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88a1dcdff1466e3c2488e1cb5c36a71822750ad43839937f85d2f4d9f8b705d8" +dependencies = [ + "local-waker", + "pin-project-lite 0.2.9", +] + [[package]] name = "actix-web" -version = "2.0.0" +version = "4.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3158e822461040822f0dbf1735b9c2ce1f95f93b651d7a7aded00b1efbb1f635" +checksum = "d48f7b6534e06c7bfc72ee91db7917d4af6afe23e7d223b51e68fffbb21e96b9" dependencies = [ - "actix-codec", - "actix-http", - "actix-macros", + "actix-codec 0.5.0", + "actix-http 3.2.2", + "actix-macros 0.2.3", "actix-router", - "actix-rt", + "actix-rt 2.7.0", "actix-server", - "actix-service", - "actix-testing", - "actix-threadpool", - "actix-tls", - "actix-utils", + "actix-service 2.0.2", + "actix-utils 3.0.1", "actix-web-codegen", - "awc", - "bytes", + "ahash", + "bytes 1.2.1", + "bytestring", + "cfg-if 1.0.0", + "cookie", "derive_more", "encoding_rs", - "futures", - "fxhash", + "futures-core", + "futures-util", + "http", + "itoa 1.0.4", + "language-tags 0.3.2", "log", "mime", - "net2", - "pin-project", + "once_cell", + "pin-project-lite 0.2.9", "regex", "serde", "serde_json", - "serde_urlencoded", - "time 0.1.43", + "serde_urlencoded 0.7.1", + "smallvec", + "socket2 0.4.7", + "time 0.3.17", "url", ] [[package]] name = "actix-web-codegen" -version = "0.2.2" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a71bf475cbe07281d0b3696abb48212db118e7e23219f13596ce865235ff5766" +checksum = "1fa9362663c8643d67b2d5eafba49e4cb2c8a053a29ed00a0bea121f17c76b13" dependencies = [ + "actix-router", "proc-macro2", "quote", "syn", @@ -286,9 +443,9 @@ dependencies = [ [[package]] name = "actix_derive" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b95aceadaf327f18f0df5962fedc1bde2f870566a0b9f65c89508a3b1f79334c" +checksum = "6d44b8fee1ced9671ba043476deddef739dd0959bf77030b26b738cc591737a7" dependencies = [ "proc-macro2", "quote", @@ -297,184 +454,125 @@ dependencies = [ [[package]] name = "addr2line" -version = "0.13.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b6a2d3371669ab3ca9797670853d61402b03d0b4b9ebf33d677dfa720203072" +checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" dependencies = [ "gimli", ] [[package]] name = "adler" -version = "0.2.3" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] -name = "aho-corasick" -version = "0.7.13" +name = "ahash" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "043164d8ba5c4c3035fec9bbee8647c0261d788f3474306f93bb65901cae0e86" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" dependencies = [ - "memchr", + "getrandom 0.2.8", + "once_cell", + "version_check", ] [[package]] -name = "anyhow" -version = "1.0.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b602bfe940d21c130f3895acd65221e8a61270debe89d628b9cb4e3ccb8569b" - -[[package]] -name = "arc-swap" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d25d88fd6b8041580a654f9d0c581a047baee2b3efee13275f2fc392fc75034" - -[[package]] -name = "arrayref" -version = "0.3.6" +name = "aho-corasick" +version = "0.7.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" +checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e" +dependencies = [ + "memchr", +] [[package]] -name = "arrayvec" -version = "0.5.1" +name = "alloc-no-stdlib" +version = "2.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" [[package]] -name = "async-channel" -version = "1.4.2" +name = "alloc-stdlib" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21279cfaa4f47df10b1816007e738ca3747ef2ee53ffc51cdbf57a8bb266fee3" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" dependencies = [ - "concurrent-queue", - "event-listener", - "futures-core", + "alloc-no-stdlib", ] [[package]] -name = "async-compat" -version = "0.1.3" +name = "android_system_properties" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4316ce79a7185ddb5cbb692bc5e992e3bbdb68a00382fa0b0ee248f05c16ecd7" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" dependencies = [ - "futures-core", - "futures-io", - "once_cell", - "pin-project-lite 0.1.7", - "tokio", + "libc", ] [[package]] -name = "async-compression" -version = "0.3.7" +name = "anyhow" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b72c1f1154e234325b50864a349b9c8e56939e266a4c307c0f159812df2f9537" -dependencies = [ - "flate2", - "futures-core", - "memchr", - "pin-project-lite 0.2.0", - "tokio", -] +checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6" [[package]] -name = "async-executor" -version = "0.1.2" +name = "askama_escape" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f47c78ea98277cb1f5e6f60ba4fc762f5eafe9f6511bc2f7dfd8b75c225650" -dependencies = [ - "async-io", - "futures-lite", - "multitask", - "parking 1.0.6", - "scoped-tls", - "waker-fn", -] +checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341" [[package]] -name = "async-io" -version = "0.1.11" +name = "async-compression" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ae22a338d28c75b53702b66f77979062cb29675db376d99e451af4fa79dedb3" +checksum = "942c7cd7ae39e91bde4820d74132e9862e62c2f386c3aa90ccf55949f5bad63a" dependencies = [ - "cfg-if", - "concurrent-queue", - "futures-lite", - "libc", - "once_cell", - "parking 2.0.0", - "polling", - "socket2", - "vec-arena", - "wepoll-sys-stjepang", - "winapi 0.3.9", + "flate2", + "futures-core", + "memchr", + "pin-project-lite 0.2.9", + "tokio 1.21.2", ] [[package]] -name = "async-mutex" -version = "1.3.0" +name = "async-recursion" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66941c2577c4fa351e4ce5fdde8f86c69b88d623f3b955be1bc7362a23434632" +checksum = "2cda8f4bcc10624c4e85bc66b3f452cca98cfa5ca002dc83a16aad2367641bea" dependencies = [ - "event-listener", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "async-std" -version = "1.6.3" +name = "async-stream" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c8da367da62b8ff2313c406c9ac091c1b31d67a165becdd2de380d846260f7" +checksum = "dad5c83079eae9969be7fadefe640a1c566901f05ff91ab221de4b6f68d9507e" dependencies = [ - "async-executor", - "async-io", - "async-mutex", - "async-task", - "blocking", - "crossbeam-utils", - "futures-channel", + "async-stream-impl", "futures-core", - "futures-io", - "futures-lite", - "futures-timer", - "kv-log-macro", - "log", - "memchr", - "num_cpus", - "once_cell", - "pin-project-lite 0.1.7", - "pin-utils", - "slab", - "wasm-bindgen-futures", ] [[package]] -name = "async-tar" -version = "0.3.0" +name = "async-stream-impl" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb619eae01ab289095debb1ff7c02710d5124c20edde1b2eca926572a34c3998" +checksum = "10f203db73a71dfa2fb6dd22763990fa26f3d2625a6da2da900d23b87d26be27" dependencies = [ - "async-std", - "filetime", - "libc", - "pin-project", - "redox_syscall", - "xattr", + "proc-macro2", + "quote", + "syn", ] -[[package]] -name = "async-task" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17772156ef2829aadc587461c7753af20b7e8db1529bc66855add962a3b35d3" - [[package]] name = "async-trait" -version = "0.1.40" +version = "0.1.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "687c230d85c0a52504709705fc8a53e4a692b83a2184f03dae73e38e1e93a783" +checksum = "1e805d94e6b5001b651426cf4cd446b1ab5f319d27bab5c644f61de0a804360c" dependencies = [ "proc-macro2", "quote", @@ -482,10 +580,13 @@ dependencies = [ ] [[package]] -name = "atomic-waker" -version = "1.0.0" +name = "atomic" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a" +checksum = "b88d82667eca772c4aa12f0f1348b3ae643424c8876448f3f7bd5787032e234c" +dependencies = [ + "autocfg", +] [[package]] name = "atty" @@ -500,53 +601,104 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "awc" -version = "1.0.1" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7601d4d1d7ef2335d6597a41b5fe069f6ab799b85f53565ab390e7b7065aac5" +checksum = "80ca7ff88063086d2e2c70b9f3b29b2fcd999bac68ac21731e66781970d68519" dependencies = [ - "actix-codec", - "actix-http", - "actix-rt", - "actix-service", - "base64 0.11.0", - "bytes", + "actix-codec 0.5.0", + "actix-http 3.2.2", + "actix-rt 2.7.0", + "actix-service 2.0.2", + "actix-tls", + "actix-utils 3.0.1", + "ahash", + "base64 0.13.1", + "bytes 1.2.1", + "cfg-if 1.0.0", + "cookie", "derive_more", "futures-core", + "futures-util", + "h2 0.3.15", + "http", + "itoa 1.0.4", "log", "mime", "percent-encoding", - "rand", + "pin-project-lite 0.2.9", + "rand 0.8.5", "serde", "serde_json", - "serde_urlencoded", + "serde_urlencoded 0.7.1", + "tokio 1.21.2", +] + +[[package]] +name = "axum" +version = "0.5.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acee9fd5073ab6b045a275b3e709c163dd36c90685219cb21804a147b58dba43" +dependencies = [ + "async-trait", + "axum-core", + "bitflags", + "bytes 1.2.1", + "futures-util", + "http", + "http-body", + "hyper", + "itoa 1.0.4", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite 0.2.9", + "serde", + "sync_wrapper", + "tokio 1.21.2", + "tower", + "tower-http", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-core" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37e5939e02c56fecd5c017c37df4238c0a839fa76b7f97acdd7efb804fd181cc" +dependencies = [ + "async-trait", + "bytes 1.2.1", + "futures-util", + "http", + "http-body", + "mime", + "tower-layer", + "tower-service", ] [[package]] name = "backtrace" -version = "0.3.50" +version = "0.3.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46254cf2fdcdf1badb5934448c1bcbe046a56537b3987d96c51a7afc5d03f293" +checksum = "cab84319d616cfb654d03394f38ab7e6f0919e181b1b57e1fd15e7fb4077d9a7" dependencies = [ "addr2line", - "cfg-if", + "cc", + "cfg-if 1.0.0", "libc", "miniz_oxide", "object", "rustc-demangle", ] -[[package]] -name = "base-x" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b20b618342cf9891c292c4f5ac2cde7287cc5c87e87e9c769d617793607dec1" - [[package]] name = "base64" version = "0.11.0" @@ -555,38 +707,15 @@ checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" [[package]] name = "base64" -version = "0.12.3" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "bitflags" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" - -[[package]] -name = "blake2b_simd" -version = "0.5.10" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a" -dependencies = [ - "arrayref", - "arrayvec", - "constant_time_eq", -] - -[[package]] -name = "block-buffer" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" -dependencies = [ - "block-padding", - "byte-tools", - "byteorder", - "generic-array 0.12.3", -] +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "block-buffer" @@ -594,68 +723,50 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ - "generic-array 0.14.4", + "generic-array", ] [[package]] -name = "block-padding" -version = "0.1.5" +name = "block-buffer" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" +checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" dependencies = [ - "byte-tools", + "generic-array", ] [[package]] -name = "blocking" -version = "0.5.2" +name = "brotli" +version = "3.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea5800d29218fea137b0880387e5948694a23c93fcdde157006966693a865c7c" +checksum = "a1a0b1dbcc8ae29329621f8d4f0d835787c1c38bb1401979b49d13b0b305ff68" dependencies = [ - "async-channel", - "atomic-waker", - "futures-lite", - "once_cell", - "waker-fn", + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", ] [[package]] -name = "brotli-sys" -version = "0.3.2" +name = "brotli-decompressor" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4445dea95f4c2b41cde57cc9fee236ae4dbae88d8fcbdb4750fc1bb5d86aaecd" +checksum = "59ad2d4653bf5ca36ae797b1f4bb4dbddb60ce49ca4aed8a2ce4829f60425b80" dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "brotli2" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cb036c3eade309815c15ddbacec5b22c4d1f3983a774ab2eac2e3e9ea85568e" -dependencies = [ - "brotli-sys", - "libc", + "alloc-no-stdlib", + "alloc-stdlib", ] [[package]] name = "bumpalo" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820" - -[[package]] -name = "byte-tools" -version = "0.3.1" +version = "3.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" +checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" [[package]] name = "byteorder" -version = "1.3.4" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" @@ -664,25 +775,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" [[package]] -name = "bytestring" -version = "0.1.5" +name = "bytes" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7c05fa5172da78a62d9949d662d2ac89d4cc7355d7b49adee5163f1fb3f363" -dependencies = [ - "bytes", -] +checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" [[package]] -name = "cache-padded" -version = "1.1.1" +name = "bytestring" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "631ae5198c9be5e753e5cc215e1bd73c2b466a3565173db433f52bb9d3e66dba" +checksum = "f7f83e57d9154148e355404702e2694463241880b939570d7c97c014da7a69a1" +dependencies = [ + "bytes 1.2.1", +] [[package]] name = "cc" -version = "1.0.58" +version = "1.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a06fb2e53271d7c279ec1efea6ab691c35a2ae67ec0d91d7acec0caf13b518" +checksum = "76a284da2e6fe2092f2353e51713435363112dfd60030e22add80be333fb928f" +dependencies = [ + "jobserver", +] [[package]] name = "cfg-if" @@ -690,42 +804,50 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + [[package]] name = "chrono" -version = "0.4.15" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942f72db697d8767c22d46a598e01f2d3b475501ea43d0db4f16d90259182d0b" +checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1" dependencies = [ + "iana-time-zone", + "js-sys", "num-integer", "num-traits", "serde", - "time 0.1.43", + "time 0.1.44", + "wasm-bindgen", + "winapi 0.3.9", ] [[package]] name = "clap" -version = "3.0.0-beta.2" +version = "3.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bd1061998a501ee7d4b6d449020df3266ca3124b941ec56cf2005c3779ca142" +checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5" dependencies = [ "atty", "bitflags", "clap_derive", + "clap_lex", "indexmap", - "lazy_static", - "os_str_bytes", + "once_cell", "strsim", "termcolor", "textwrap", - "unicode-width", - "vec_map", ] [[package]] name = "clap_derive" -version = "3.0.0-beta.2" +version = "3.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "370f715b81112975b1b69db93e0b56ea4cd4e5002ac43b2da8474106a54096a1" +checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65" dependencies = [ "heck", "proc-macro-error", @@ -735,51 +857,92 @@ dependencies = [ ] [[package]] -name = "cloudabi" -version = "0.0.3" +name = "clap_lex" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" dependencies = [ - "bitflags", + "os_str_bytes", ] [[package]] -name = "cloudabi" -version = "0.1.0" +name = "codespan-reporting" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4344512281c643ae7638bbabc3af17a11307803ec8f0fcad9fae512a8bf36467" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" dependencies = [ - "bitflags", + "termcolor", + "unicode-width", ] [[package]] name = "collective" version = "0.1.2" -source = "git+https://gitlab.chromabits.com/etcinit/collective.git?tag=0.1.2#137121204a41de9ef30b4c458b041ac680c308e8" +source = "git+https://gitlab.chromabits.com/etcinit/collective.git?rev=f6f46f690d63f142ad6c5e95dd806d24b9cea6d4#f6f46f690d63f142ad6c5e95dd806d24b9cea6d4" dependencies = [ "clap", "figment", + "lazy_static", "log", "pretty_env_logger", "serde", "thiserror", "toml", + "xdg", ] [[package]] -name = "concurrent-queue" -version = "1.2.2" +name = "console-api" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3" +checksum = "e57ff02e8ad8e06ab9731d5dc72dc23bef9200778eae1a89d555d8c42e5d4a86" dependencies = [ - "cache-padded", + "prost", + "prost-types", + "tonic", + "tracing-core", ] [[package]] -name = "constant_time_eq" -version = "0.1.5" +name = "console-subscriber" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22a3a81dfaf6b66bce5d159eddae701e3a002f194d378cbf7be5f053c281d9be" +dependencies = [ + "console-api", + "crossbeam-channel", + "crossbeam-utils", + "futures", + "hdrhistogram", + "humantime 2.1.0", + "prost-types", + "serde", + "serde_json", + "thread_local", + "tokio 1.21.2", + "tokio-stream", + "tonic", + "tracing", + "tracing-core", + "tracing-subscriber", +] + +[[package]] +name = "convert_case" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "cookie" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "344adc371239ef32293cb1c4fe519592fcf21206c79c02854320afcdf3ab4917" +dependencies = [ + "percent-encoding", + "time 0.3.17", + "version_check", +] [[package]] name = "copyless" @@ -789,9 +952,9 @@ checksum = "a2df960f5d869b2dd8532793fde43eb5427cceb126c929747a26823ab0eeb536" [[package]] name = "core-foundation" -version = "0.7.0" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57d24c7a13c43e870e37c1556b74555437870a04514f7685f5b354e090567171" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" dependencies = [ "core-foundation-sys", "libc", @@ -799,74 +962,122 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.7.0" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" [[package]] -name = "cpuid-bool" -version = "0.1.2" +name = "cpufeatures" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634" +checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +dependencies = [ + "libc", +] [[package]] name = "crc32fast" -version = "1.2.0" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", ] [[package]] name = "crossbeam-channel" -version = "0.4.3" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ee0cc8804d5393478d743b035099520087a5186f3b93fa58cec08fa62407b6" +checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.7.2" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" +checksum = "edbafec5fa1f196ca66527c1b12c2ec4745ca14b50f1ad8f9f6f720b55d11fac" dependencies = [ - "autocfg", - "cfg-if", - "lazy_static", + "cfg-if 1.0.0", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", ] [[package]] name = "crypto-mac" -version = "0.8.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" +checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" dependencies = [ - "generic-array 0.14.4", + "generic-array", "subtle", ] [[package]] -name = "derive_more" -version = "0.99.9" +name = "cxx" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "298998b1cf6b5b2c8a7b023dfd45821825ce3ba8a8af55c921a0e734e4653f76" +checksum = "97abf9f0eca9e52b7f81b945524e76710e6cb2366aead23b7d4fbf72e281f888" dependencies = [ + "cc", + "cxxbridge-flags", + "cxxbridge-macro", + "link-cplusplus", +] + +[[package]] +name = "cxx-build" +version = "1.0.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cc32cc5fea1d894b77d269ddb9f192110069a8a9c1f1d441195fba90553dea3" +dependencies = [ + "cc", + "codespan-reporting", + "once_cell", "proc-macro2", "quote", + "scratch", "syn", ] [[package]] -name = "digest" -version = "0.8.1" +name = "cxxbridge-flags" +version = "1.0.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ca220e4794c934dc6b1207c3b42856ad4c302f2df1712e9f8d2eec5afaacf1f" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" +checksum = "b846f081361125bfc8dc9d3940c84e1fd83ba54bbca7b17cd29483c828be0704" dependencies = [ - "generic-array 0.12.3", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn", ] [[package]] @@ -875,24 +1086,43 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" dependencies = [ - "generic-array 0.14.4", + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adfbc57365a37acbd2ebf2b64d7e69bb766e2fea813521ed536f5d0520dcf86c" +dependencies = [ + "block-buffer 0.10.3", + "crypto-common", ] [[package]] name = "dirs" -version = "2.0.2" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3" +checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" dependencies = [ - "cfg-if", "dirs-sys", ] +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if 1.0.0", + "dirs-sys-next", +] + [[package]] name = "dirs-sys" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e93d7f5705de3e49895a2b5e0b8855a1c27f080192ae9c32a6432d50741a57a" +checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" dependencies = [ "libc", "redox_users", @@ -900,10 +1130,15 @@ dependencies = [ ] [[package]] -name = "discard" -version = "1.0.4" +name = "dirs-sys-next" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi 0.3.9", +] [[package]] name = "doc-comment" @@ -913,30 +1148,30 @@ checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" [[package]] name = "dtoa" -version = "0.4.6" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134951f4028bdadb9b84baf4232681efbf277da25144b9b0ad65df75946c422b" +checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0" [[package]] name = "either" -version = "1.6.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd56b59865bce947ac5958779cfa508f6c3b9497cc762b7e24a12d11ccde2c4f" +checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" [[package]] name = "encoding_rs" -version = "0.8.23" +version = "0.8.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8ac63f94732332f44fe654443c46f6375d1939684c17b0afb6cb56b0456e171" +checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", ] [[package]] name = "enum-as-inner" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c5f0096a91d210159eceb2ff5e1c4da18388a170e1e3ce948aac9c8fdbbf595" +checksum = "570d109b813e904becc80d8d5da38376818a143348413f7149f1340fe04754d4" dependencies = [ "heck", "proc-macro2", @@ -951,7 +1186,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" dependencies = [ "atty", - "humantime", + "humantime 1.3.0", "log", "regex", "termcolor", @@ -959,22 +1194,24 @@ dependencies = [ [[package]] name = "espresso" -version = "1.0.1" +version = "2.0.0" dependencies = [ "actix", - "actix-http", - "actix-rt", - "actix-service", + "actix-files", + "actix-http 1.0.1", + "actix-rt 2.7.0", + "actix-service 2.0.2", + "actix-test", "actix-web", "anyhow", - "async-compat", "async-compression", - "async-tar", + "async-recursion", "async-trait", "bitflags", - "bytes", + "bytes 1.2.1", "clap", "collective", + "console-subscriber", "futures-core", "futures-util", "handlebars", @@ -993,19 +1230,14 @@ dependencies = [ "serde_derive", "serde_json", "snafu", - "tokio", + "tokio 1.21.2", + "tokio-stream", "tokio-tar", - "tokio-util 0.3.1", + "tokio-util 0.7.4", "toml", "url", ] -[[package]] -name = "event-listener" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cd41440ae7e4734bbd42302f63eaba892afc93a3912dad84006247f0dedb0e" - [[package]] name = "failure" version = "0.1.8" @@ -1028,26 +1260,26 @@ dependencies = [ "synstructure", ] -[[package]] -name = "fake-simd" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" - [[package]] name = "fastrand" -version = "1.3.5" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c85295147490b8fcf2ea3d104080a105a8b2c63f9c319e82c02d8e952388919" +checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" +dependencies = [ + "instant", +] [[package]] name = "figment" -version = "0.10.0" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f273b2f81f067bb5553f562feb98794d6c704f049d333f920d69211965a30448" +checksum = "4e56602b469b2201400dec66a66aec5a9b8761ee97cd1b8c96ab2483fcc16cc9" dependencies = [ + "atomic", "pear", "serde", + "serde_json", + "serde_yaml", "toml", "uncased", "version_check", @@ -1055,25 +1287,23 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.12" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed85775dcc68644b5c950ac06a2b23768d3bc9390464151aaf27136998dcf9e" +checksum = "4b9663d381d07ae25dc88dbdf27df458faa83a9b25336bcac83d5e452b5fc9d3" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "libc", "redox_syscall", - "winapi 0.3.9", + "windows-sys 0.42.0", ] [[package]] name = "flate2" -version = "1.0.16" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68c90b0fc46cf89d227cc78b40e494ff81287a92dd07631e5af0d06fe3cf885e" +checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6" dependencies = [ - "cfg-if", "crc32fast", - "libc", "miniz_oxide", ] @@ -1098,6 +1328,15 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" +[[package]] +name = "form_urlencoded" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +dependencies = [ + "percent-encoding", +] + [[package]] name = "fuchsia-zircon" version = "0.3.3" @@ -1116,9 +1355,9 @@ checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" [[package]] name = "futures" -version = "0.3.5" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e05b85ec287aac0dc34db7d4a569323df697f9c55b99b15d6b4ef8cde49f613" +checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0" dependencies = [ "futures-channel", "futures-core", @@ -1131,9 +1370,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.5" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f366ad74c28cca6ba456d95e6422883cfb4b252a83bed929c83abfdbbf2967d5" +checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" dependencies = [ "futures-core", "futures-sink", @@ -1141,15 +1380,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.5" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59f5fff90fd5d971f936ad674802482ba441b6f09ba5e15fd8b39145582ca399" +checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" [[package]] name = "futures-executor" -version = "0.3.5" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10d6bb888be1153d3abeb9006b11b02cf5e9b209fda28693c31ae1e4e012e314" +checksum = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2" dependencies = [ "futures-core", "futures-task", @@ -1158,32 +1397,16 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.5" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de27142b013a8e869c14957e6d2edeef89e97c289e69d042ee3a49acd8b51789" - -[[package]] -name = "futures-lite" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97999970129b808f0ccba93211201d431fcc12d7e1ffae03a61b5cedd1a7ced2" -dependencies = [ - "fastrand", - "futures-core", - "futures-io", - "memchr", - "parking 2.0.0", - "pin-project-lite 0.1.7", - "waker-fn", -] +checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb" [[package]] name = "futures-macro" -version = "0.3.5" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0b5a30a4328ab5473878237c447333c093297bded83a4983d10f4deea240d39" +checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" dependencies = [ - "proc-macro-hack", "proc-macro2", "quote", "syn", @@ -1191,34 +1414,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.5" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f2032893cb734c7a05d85ce0cc8b8c4075278e93b24b66f9de99d6eb0fa8acc" +checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9" [[package]] name = "futures-task" -version = "0.3.5" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdb66b5f09e22019b1ab0830f7785bcea8e7a42148683f99214f73f8ec21a626" -dependencies = [ - "once_cell", -] - -[[package]] -name = "futures-timer" -version = "3.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" -dependencies = [ - "gloo-timers", - "send_wrapper", -] +checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" [[package]] name = "futures-util" -version = "0.3.5" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8764574ff08b701a084482c3c7031349104b07ac897393010494beaa18ce32c6" +checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" dependencies = [ "futures-channel", "futures-core", @@ -1227,10 +1437,8 @@ dependencies = [ "futures-sink", "futures-task", "memchr", - "pin-project", + "pin-project-lite 0.2.9", "pin-utils", - "proc-macro-hack", - "proc-macro-nested", "slab", ] @@ -1245,60 +1453,69 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.12.3" +version = "0.14.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" dependencies = [ "typenum", + "version_check", ] [[package]] -name = "generic-array" -version = "0.14.4" +name = "getrandom" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ - "typenum", - "version_check", + "cfg-if 1.0.0", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", ] [[package]] name = "getrandom" -version = "0.1.14" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", ] [[package]] name = "gimli" -version = "0.22.0" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaf91faf136cb47367fa430cd46e37a788775e7fa104f8b4bcb3861dc389b724" +checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d" [[package]] -name = "gloo-timers" -version = "0.2.1" +name = "h2" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47204a46aaff920a1ea58b11d03dec6f704287d27561724a4631e450654a891f" +checksum = "5e4728fd124914ad25e99e3d15a9361a879f6620f63cb56bbb08f95abb97a535" dependencies = [ - "futures-channel", + "bytes 0.5.6", + "fnv", "futures-core", - "js-sys", - "wasm-bindgen", - "web-sys", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio 0.2.25", + "tokio-util 0.3.1", + "tracing", + "tracing-futures", ] [[package]] name = "h2" -version = "0.2.6" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "993f9e0baeed60001cf565546b0d3dbe6a6ad23f2bd31644a133c641eccf6d53" +checksum = "5f9f29bc9dda355256b2916cf526ab02ce0aeaaaf2bad60d65ef3f12f11dd0f4" dependencies = [ - "bytes", + "bytes 1.2.1", "fnv", "futures-core", "futures-sink", @@ -1306,63 +1523,70 @@ dependencies = [ "http", "indexmap", "slab", - "tokio", - "tokio-util 0.3.1", + "tokio 1.21.2", + "tokio-util 0.7.4", "tracing", ] [[package]] name = "handlebars" -version = "3.4.0" +version = "3.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5deefd4816fb852b1ff3cb48f6c41da67be2d0e1d20b26a7a3b076da11f064b1" +checksum = "4498fc115fa7d34de968184e473529abb40eeb6be8bc5f7faba3d08c316cb3e3" dependencies = [ "log", "pest", "pest_derive", - "quick-error 2.0.0", + "quick-error 2.0.1", "serde", "serde_json", ] [[package]] name = "hashbrown" -version = "0.8.2" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hdrhistogram" +version = "7.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b62f79061a0bc2e046024cb7ba44b08419ed238ecbd9adbd787434b9e8c25" +checksum = "7f19b9f54f7c7f55e31401bb647626ce0cf0f67b0004982ce815b3ee72a02aa8" dependencies = [ - "autocfg", + "base64 0.13.1", + "byteorder", + "flate2", + "nom", + "num-traits", ] [[package]] name = "heck" -version = "0.3.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" -dependencies = [ - "unicode-segmentation", -] +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" [[package]] name = "hermit-abi" -version = "0.1.15" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" dependencies = [ "libc", ] [[package]] name = "hex" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hmac" -version = "0.8.1" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" +checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" dependencies = [ "crypto-mac", "digest 0.9.0", @@ -1381,30 +1605,49 @@ dependencies = [ [[package]] name = "http" -version = "0.2.1" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d569972648b2c512421b5f2a405ad6ac9666547189d0c5477a3f200f3e02f9" +checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" dependencies = [ - "bytes", + "bytes 1.2.1", "fnv", - "itoa", + "itoa 1.0.4", ] [[package]] name = "http-body" -version = "0.3.1" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13d5ff830006f7646652e057693569bfe0d51760c0085a071769d142a205111b" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ - "bytes", + "bytes 1.2.1", "http", + "pin-project-lite 0.2.9", ] +[[package]] +name = "http-range" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21dec9db110f5f872ed9699c3ecf50cf16f423502706ba5c72462e28d3157573" + +[[package]] +name = "http-range-header" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bfe8eed0a9285ef776bb792479ea3834e8b94e13d615c2f66d03dd50a435a29" + [[package]] name = "httparse" -version = "1.3.4" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" [[package]] name = "humantime" @@ -1415,59 +1658,111 @@ dependencies = [ "quick-error 1.2.3", ] +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + [[package]] name = "hyper" -version = "0.13.7" +version = "0.14.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e68a8dd9716185d9e64ea473ea6ef63529252e3e27623295a0378a19665d5eb" +checksum = "034711faac9d2166cb1baf1a2fb0b60b1f277f8492fd72176c17f3515e1abd3c" dependencies = [ - "bytes", + "bytes 1.2.1", "futures-channel", "futures-core", "futures-util", - "h2", + "h2 0.3.15", "http", "http-body", "httparse", - "itoa", - "pin-project", - "socket2", - "time 0.1.43", - "tokio", + "httpdate", + "itoa 1.0.4", + "pin-project-lite 0.2.9", + "socket2 0.4.7", + "tokio 1.21.2", "tower-service", "tracing", "want", ] +[[package]] +name = "hyper-timeout" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" +dependencies = [ + "hyper", + "pin-project-lite 0.2.9", + "tokio 1.21.2", + "tokio-io-timeout", +] + [[package]] name = "hyper-tls" -version = "0.4.3" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d979acc56dcb5b8dddba3917601745e877576475aa046df3226eabdecef78eed" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ - "bytes", + "bytes 1.2.1", "hyper", "native-tls", - "tokio", - "tokio-tls", + "tokio 1.21.2", + "tokio-native-tls", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "winapi 0.3.9", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" +dependencies = [ + "cxx", + "cxx-build", ] [[package]] name = "idna" -version = "0.2.0" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" dependencies = [ "matches", "unicode-bidi", "unicode-normalization", ] +[[package]] +name = "idna" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "indexmap" -version = "1.5.1" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b45e59b16c76b11bf9738fd5d38879d3bd28ad292d7b313608becb17ae2df9" +checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" dependencies = [ "autocfg", "hashbrown", @@ -1475,24 +1770,24 @@ dependencies = [ [[package]] name = "indoc" -version = "1.0.2" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "644defcefee68d7805653a682e99a2e2a5014a1fc3cc9be7059a215844eeea6f" -dependencies = [ - "unindent", -] +checksum = "adab1eaa3408fb7f0c777a73e7465fd5656136fc93b670eb6df3c88c2c1344e3" [[package]] name = "inlinable_string" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3094308123a0e9fd59659ce45e22de9f53fc1d2ac6e1feb9fef988e4f76cad77" +checksum = "c8fae54786f62fb2918dcfae3d568594e50eb9b5c25bf04371af6fe7516452fb" [[package]] name = "instant" -version = "0.1.6" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b141fdc7836c525d4d594027d318c84161ca17aaf8113ab1f81ab93ae897485" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if 1.0.0", +] [[package]] name = "iovec" @@ -1509,23 +1804,47 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7e2f18aece9709094573a9f24f483c4f65caa4298e2f7ae1b71cc65d853fad7" dependencies = [ - "socket2", + "socket2 0.3.19", "widestring", "winapi 0.3.9", "winreg", ] +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" + [[package]] name = "itoa" -version = "0.4.6" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" + +[[package]] +name = "jobserver" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" +checksum = "068b1ee6743e4d11fb9c6a1e6064b3693a1b600e7f5f5988047d98b3dc9fb90b" +dependencies = [ + "libc", +] [[package]] name = "js-sys" -version = "0.3.44" +version = "0.3.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85a7e2c92a4804dd459b86c339278d0fe87cf93757fae222c3fa3ae75458bc73" +checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" dependencies = [ "wasm-bindgen", ] @@ -1541,19 +1860,16 @@ dependencies = [ ] [[package]] -name = "kv-log-macro" -version = "1.0.7" +name = "language-tags" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" -dependencies = [ - "log", -] +checksum = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" [[package]] name = "language-tags" -version = "0.2.2" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" +checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388" [[package]] name = "lazy_static" @@ -1563,41 +1879,60 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.74" +version = "0.2.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" + +[[package]] +name = "link-cplusplus" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2f02823cf78b754822df5f7f268fb59822e7296276d3e069d8e8cb26a14bd10" +checksum = "9272ab7b96c9046fbc5bc56c06c117cb639fe2d509df0c421cad82d2915cf369" +dependencies = [ + "cc", +] [[package]] name = "linked-hash-map" -version = "0.5.3" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] -name = "lock_api" -version = "0.3.4" +name = "local-channel" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75" +checksum = "7f303ec0e94c6c54447f84f3b0ef7af769858a9c4ef56ef2a986d3dcd4c3fc9c" dependencies = [ - "scopeguard", + "futures-core", + "futures-sink", + "futures-util", + "local-waker", ] +[[package]] +name = "local-waker" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e34f76eb3611940e0e7d53a9aaa4e6a3151f69541a282fd0dad5571420c53ff1" + [[package]] name = "lock_api" -version = "0.4.1" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28247cc5a5be2f05fbcd76dd0cf2c7d3b5400cb978a28042abcd4fa0b3f8261c" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" dependencies = [ + "autocfg", "scopeguard", ] [[package]] name = "log" -version = "0.4.11" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", ] [[package]] @@ -1610,34 +1945,48 @@ dependencies = [ ] [[package]] -name = "maplit" -version = "1.0.2" +name = "match_cfg" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" [[package]] -name = "match_cfg" +name = "matchers" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata", +] [[package]] name = "matches" -version = "0.1.8" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" + +[[package]] +name = "matchit" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" +checksum = "73cbba799671b762df5a175adf59ce145165747bb891505c43d09aefbbf38beb" [[package]] -name = "md5" -version = "0.7.0" +name = "md-5" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" +checksum = "7b5a279bb9607f9f53c22d496eade00d138d1bdcccd07d74650387cf94942a15" +dependencies = [ + "block-buffer 0.9.0", + "digest 0.9.0", + "opaque-debug", +] [[package]] name = "memchr" -version = "2.3.3" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "mime" @@ -1647,52 +1996,58 @@ checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" [[package]] name = "mime_guess" -version = "2.0.3" +version = "2.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2684d4c2e97d99848d30b324b00c8fcc7e5c897b7cbb5819b09e7c90e8baf212" +checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" dependencies = [ "mime", "unicase", ] +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" -version = "0.4.0" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be0f75932c1f6cfae3c04000e40114adf955636e19040f9c0a2c380702aa1c7f" +checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34" dependencies = [ "adler", ] [[package]] name = "mio" -version = "0.6.22" +version = "0.6.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fce347092656428bc8eaf6201042cb551b8d67855af7374542a92a0fbfcac430" +checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "fuchsia-zircon", "fuchsia-zircon-sys", "iovec", "kernel32-sys", "libc", "log", - "miow 0.2.1", + "miow", "net2", "slab", "winapi 0.2.8", ] [[package]] -name = "mio-named-pipes" -version = "0.1.7" +name = "mio" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0840c1c50fd55e521b247f949c241c9997709f23bd7f023b9762cd561e935656" +checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" dependencies = [ + "libc", "log", - "mio", - "miow 0.3.5", - "winapi 0.3.9", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.42.0", ] [[package]] @@ -1703,14 +2058,14 @@ checksum = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0" dependencies = [ "iovec", "libc", - "mio", + "mio 0.6.23", ] [[package]] name = "miow" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" +checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" dependencies = [ "kernel32-sys", "net2", @@ -1718,32 +2073,11 @@ dependencies = [ "ws2_32-sys", ] -[[package]] -name = "miow" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07b88fb9795d4d36d62a012dfbf49a8f5cf12751f36d31a9dbe66d528e58979e" -dependencies = [ - "socket2", - "winapi 0.3.9", -] - -[[package]] -name = "multitask" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c09c35271e7dcdb5f709779111f2c8e8ab8e06c1b587c1c6a9e179d865aaa5b4" -dependencies = [ - "async-task", - "concurrent-queue", - "fastrand", -] - [[package]] name = "native-tls" -version = "0.2.4" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b0d88c06fe90d5ee94048ba40409ef1d9315d86f6f38c2efdaad4fb50c58b2d" +checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" dependencies = [ "lazy_static", "libc", @@ -1759,20 +2093,30 @@ dependencies = [ [[package]] name = "net2" -version = "0.2.34" +version = "0.2.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ba7c918ac76704fb42afcbbb43891e72731f3dcca3bef2a19786297baf14af7" +checksum = "74d0df99cfcd2530b2e694f6e17e7f37b8e26bb23983ac530c0c97408837c631" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "libc", "winapi 0.3.9", ] +[[package]] +name = "nom" +version = "7.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "num-integer" -version = "0.1.43" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" dependencies = [ "autocfg", "num-traits", @@ -1780,18 +2124,18 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.12" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" dependencies = [ "autocfg", ] [[package]] name = "num_cpus" -version = "1.13.0" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5" dependencies = [ "hermit-abi", "libc", @@ -1799,21 +2143,18 @@ dependencies = [ [[package]] name = "object" -version = "0.20.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ab52be62400ca80aa00285d25253d7f7c437b7375c4de678f5405d3afe82ca5" +checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53" +dependencies = [ + "memchr", +] [[package]] name = "once_cell" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "260e51e7efe62b592207e9e13a68e43692a7a279171d6ba57abd208bf23645ad" - -[[package]] -name = "opaque-debug" -version = "0.2.3" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" +checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" [[package]] name = "opaque-debug" @@ -1823,29 +2164,41 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "openssl" -version = "0.10.30" +version = "0.10.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d575eff3665419f9b83678ff2815858ad9d11567e082f5ac1814baba4e2bcb4" +checksum = "12fc0523e3bd51a692c8850d075d74dc062ccf251c0110668cbd921917118a13" dependencies = [ "bitflags", - "cfg-if", + "cfg-if 1.0.0", "foreign-types", - "lazy_static", "libc", + "once_cell", + "openssl-macros", "openssl-sys", ] +[[package]] +name = "openssl-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "openssl-probe" -version = "0.1.2" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.58" +version = "0.9.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a842db4709b604f0fe5d1170ae3565899be2ad3d9cbc72dedc789ac0511f78de" +checksum = "b03b84c3b2d099b81f0953422b4d4ad58761589d0229b5506356afca05a3670a" dependencies = [ "autocfg", "cc", @@ -1856,51 +2209,39 @@ dependencies = [ [[package]] name = "os_str_bytes" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afb2e1c3ee07430c2cf76151675e583e0f19985fa6efae47d6848a3e2c824f85" - -[[package]] -name = "parking" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cb300f271742d4a2a66c01b6b2fa0c83dfebd2e0bf11addb879a3547b4ed87c" - -[[package]] -name = "parking" -version = "2.0.0" +version = "6.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" +checksum = "7b5bf27447411e9ee3ff51186bf7a08e16c341efdde93f4d823e8844429bed7e" [[package]] name = "parking_lot" -version = "0.10.2" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3a704eb390aafdc107b0e392f56a82b668e3a71366993b5340f5833fd62505e" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" dependencies = [ - "lock_api 0.3.4", - "parking_lot_core 0.7.2", + "instant", + "lock_api", + "parking_lot_core 0.8.5", ] [[package]] name = "parking_lot" -version = "0.11.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4893845fa2ca272e647da5d0e46660a314ead9c2fdd9a883aabc32e481a8733" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ - "instant", - "lock_api 0.4.1", - "parking_lot_core 0.8.0", + "lock_api", + "parking_lot_core 0.9.4", ] [[package]] name = "parking_lot_core" -version = "0.7.2" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d58c7c768d4ba344e3e8d72518ac13e259d7c7ade24167003b8488e10b6740a3" +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" dependencies = [ - "cfg-if", - "cloudabi 0.0.3", + "cfg-if 1.0.0", + "instant", "libc", "redox_syscall", "smallvec", @@ -1909,24 +2250,28 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.8.0" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c361aa727dd08437f2f1447be8b59a33b0edd15e0fcee698f935613d9efbca9b" +checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0" dependencies = [ - "cfg-if", - "cloudabi 0.1.0", - "instant", + "cfg-if 1.0.0", "libc", "redox_syscall", "smallvec", - "winapi 0.3.9", + "windows-sys 0.42.0", ] +[[package]] +name = "paste" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1" + [[package]] name = "pear" -version = "0.2.0" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09f612cbd0f9dd03f5dd28a191c48e4148c3b027e41207b32eee130373c6c941" +checksum = "15e44241c5e4c868e3eaa78b7c1848cadd6344ed4f54d029832d32b415a58702" dependencies = [ "inlinable_string", "pear_codegen", @@ -1935,9 +2280,9 @@ dependencies = [ [[package]] name = "pear_codegen" -version = "0.2.0" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "602cf1780ee9bbca663ea75769e05643e16fe87d7c8ac9f4f385a2ed8940a75c" +checksum = "82a5ca643c2303ecb740d506539deba189e16f2754040a42901cd8105d0282d0" dependencies = [ "proc-macro2", "proc-macro2-diagnostics", @@ -1947,24 +2292,25 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" +checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" [[package]] name = "pest" -version = "2.1.3" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" +checksum = "a528564cc62c19a7acac4d81e01f39e53e25e17b934878f4c6d25cc2836e62f8" dependencies = [ + "thiserror", "ucd-trie", ] [[package]] name = "pest_derive" -version = "2.1.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0" +checksum = "d5fd9bc6500181952d34bd0b2b0163a54d794227b498be0b7afa7698d0a7b18f" dependencies = [ "pest", "pest_generator", @@ -1972,9 +2318,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.1.3" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55" +checksum = "d2610d5ac5156217b4ff8e46ddcef7cdf44b273da2ac5bca2ecbfa86a330e7c4" dependencies = [ "pest", "pest_meta", @@ -1985,29 +2331,49 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.1.3" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "824749bf7e21dd66b36fbe26b3f45c713879cccd4a009a917ab8e045ca8246fe" +dependencies = [ + "once_cell", + "pest", + "sha1 0.10.5", +] + +[[package]] +name = "pin-project" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ef0f924a5ee7ea9cbcea77529dba45f8a9ba9f622419fe3386ca581a3ae9d5a" +dependencies = [ + "pin-project-internal 0.4.30", +] + +[[package]] +name = "pin-project" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d" +checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" dependencies = [ - "maplit", - "pest", - "sha-1", + "pin-project-internal 1.0.12", ] [[package]] -name = "pin-project" -version = "0.4.23" +name = "pin-project-internal" +version = "0.4.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca4433fff2ae79342e497d9f8ee990d174071408f28f726d6d83af93e58e48aa" +checksum = "851c8d0ce9bebe43790dedfc86614c23494ac9f423dd618d3a61fc693eafe61e" dependencies = [ - "pin-project-internal", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "pin-project-internal" -version = "0.4.23" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c0e815c3ee9a031fdf5af21c10aa17c573c9c6a566328d99e3936c34e36461f" +checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" dependencies = [ "proc-macro2", "quote", @@ -2016,15 +2382,15 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.1.7" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282adbf10f2698a7a77f8e983a74b2d18176c19a7fd32a45446139ae7b02b715" +checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777" [[package]] name = "pin-project-lite" -version = "0.2.0" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b063f57ec186e6140e2b8b6921e5f1bd89c7356dda5b33acc5401203ca6131c" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" [[package]] name = "pin-utils" @@ -2034,28 +2400,15 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.18" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d36492546b6af1463394d46f0c834346f31548646f6ba10849802c9c9a27ac33" - -[[package]] -name = "polling" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fffa183f6bd5f1a8a3e1f60ce2f8d5621e350eed84a62d6daaa5b9d1aaf6fbd" -dependencies = [ - "cfg-if", - "libc", - "log", - "wepoll-sys-stjepang", - "winapi 0.3.9", -] +checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" [[package]] name = "ppv-lite86" -version = "0.2.8" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "pretty_env_logger" @@ -2091,25 +2444,13 @@ dependencies = [ "version_check", ] -[[package]] -name = "proc-macro-hack" -version = "0.5.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99c605b9a0adc77b7211c6b1f722dcb613d68d66859a44f3d485a6da332b0598" - -[[package]] -name = "proc-macro-nested" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eba180dafb9038b050a4c280019bbedf9f2467b61e5d892dcad585bb57aadc5a" - [[package]] name = "proc-macro2" -version = "1.0.19" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04f5f085b5d71e2188cb8271e5da0161ad52c3f227a661a3c135fdf28e258b12" +checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" dependencies = [ - "unicode-xid", + "unicode-ident", ] [[package]] @@ -2125,6 +2466,39 @@ dependencies = [ "yansi", ] +[[package]] +name = "prost" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0841812012b2d4a6145fae9a6af1534873c32aa67fff26bd09f8fa42c83f95a" +dependencies = [ + "bytes 1.2.1", + "prost-derive", +] + +[[package]] +name = "prost-derive" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "164ae68b6587001ca506d3bf7f1000bfa248d0e1217b618108fba4ec1d0cc306" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "prost-types" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "747761bc3dc48f9a34553bf65605cf6cb6288ba219f3450b4275dbd81539551a" +dependencies = [ + "bytes 1.2.1", + "prost", +] + [[package]] name = "quick-error" version = "1.2.3" @@ -2133,15 +2507,15 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quick-error" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ac73b1112776fc109b2e61909bc46c7e1bf0d7f690ffb1676553acce16d5cda" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" [[package]] name = "quote" -version = "1.0.7" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" dependencies = [ "proc-macro2", ] @@ -2152,13 +2526,24 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ - "getrandom", + "getrandom 0.1.16", "libc", - "rand_chacha", - "rand_core", + "rand_chacha 0.2.2", + "rand_core 0.5.1", "rand_hc", ] +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + [[package]] name = "rand_chacha" version = "0.2.2" @@ -2166,7 +2551,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", ] [[package]] @@ -2175,7 +2570,16 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" dependencies = [ - "getrandom", + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.8", ] [[package]] @@ -2184,43 +2588,54 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" dependencies = [ - "rand_core", + "rand_core 0.5.1", ] [[package]] name = "redox_syscall" -version = "0.1.57" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags", +] [[package]] name = "redox_users" -version = "0.3.5" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ - "getrandom", + "getrandom 0.2.8", "redox_syscall", - "rust-argon2", + "thiserror", ] [[package]] name = "regex" -version = "1.3.9" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6" +checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a" dependencies = [ "aho-corasick", "memchr", "regex-syntax", - "thread_local", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax", ] [[package]] name = "regex-syntax" -version = "0.6.18" +version = "0.6.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8" +checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" [[package]] name = "remove_dir_all" @@ -2243,13 +2658,13 @@ dependencies = [ [[package]] name = "rusoto_core" -version = "0.45.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e977941ee0658df96fca7291ecc6fc9a754600b21ad84b959eb1dbbc9d5abcc7" +checksum = "1db30db44ea73551326269adcf7a2169428a054f14faf9e1768f2163494f2fa2" dependencies = [ "async-trait", - "base64 0.12.3", - "bytes", + "base64 0.13.1", + "bytes 1.2.1", "crc32fast", "futures", "http", @@ -2257,46 +2672,41 @@ dependencies = [ "hyper-tls", "lazy_static", "log", - "md5", - "percent-encoding", - "pin-project", "rusoto_credential", "rusoto_signature", "rustc_version", "serde", "serde_json", - "tokio", + "tokio 1.21.2", "xml-rs", ] [[package]] name = "rusoto_credential" -version = "0.45.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ac05563f83489b19b4d413607a30821ab08bbd9007d14fa05618da3ef09d8b" +checksum = "ee0a6c13db5aad6047b6a44ef023dbbc21a056b6dab5be3b79ce4283d5c02d05" dependencies = [ "async-trait", "chrono", - "dirs", + "dirs-next", "futures", "hyper", - "pin-project", - "regex", "serde", "serde_json", "shlex", - "tokio", + "tokio 1.21.2", "zeroize", ] [[package]] name = "rusoto_s3" -version = "0.45.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1146e37a7c1df56471ea67825fe09bbbd37984b5f6e201d8b2e0be4ee15643d8" +checksum = "7aae4677183411f6b0b412d66194ef5403293917d66e70ab118f07cc24c5b14d" dependencies = [ "async-trait", - "bytes", + "bytes 1.2.1", "futures", "rusoto_core", "xml-rs", @@ -2304,89 +2714,78 @@ dependencies = [ [[package]] name = "rusoto_signature" -version = "0.45.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97a740a88dde8ded81b6f2cff9cd5e054a5a2e38a38397260f7acdd2c85d17dd" +checksum = "a5ae95491c8b4847931e291b151127eccd6ff8ca13f33603eb3d0035ecb05272" dependencies = [ - "base64 0.12.3", - "bytes", + "base64 0.13.1", + "bytes 1.2.1", + "chrono", + "digest 0.9.0", "futures", "hex", "hmac", "http", "hyper", "log", - "md5", + "md-5", "percent-encoding", - "pin-project", + "pin-project-lite 0.2.9", "rusoto_credential", "rustc_version", "serde", "sha2", - "time 0.2.16", - "tokio", -] - -[[package]] -name = "rust-argon2" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dab61250775933275e84053ac235621dfb739556d5c54a2f2e9313b7cf43a19" -dependencies = [ - "base64 0.12.3", - "blake2b_simd", - "constant_time_eq", - "crossbeam-utils", + "tokio 1.21.2", ] [[package]] name = "rustc-demangle" -version = "0.1.16" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" [[package]] name = "rustc_version" -version = "0.2.3" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ "semver", ] [[package]] name = "ryu" -version = "1.0.5" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" +checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" [[package]] name = "schannel" -version = "0.1.19" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75" +checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" dependencies = [ "lazy_static", - "winapi 0.3.9", + "windows-sys 0.36.1", ] -[[package]] -name = "scoped-tls" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" - [[package]] name = "scopeguard" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "scratch" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898" + [[package]] name = "security-framework" -version = "0.4.4" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64808902d7d99f78eaddd2b4e2509713babc3dc3c85ad6f4c447680f3c01e535" +checksum = "2bc1bb97804af6631813c55739f771071e0f2ed33ee20b68c86ec505d906356c" dependencies = [ "bitflags", "core-foundation", @@ -2397,9 +2796,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "0.4.3" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17bf11d99252f512695eb468de5516e5cf75455521e69dfe343f3b74e4748405" +checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" dependencies = [ "core-foundation-sys", "libc", @@ -2407,39 +2806,24 @@ dependencies = [ [[package]] name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - -[[package]] -name = "send_wrapper" -version = "0.4.0" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0" +checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4" [[package]] name = "serde" -version = "1.0.115" +version = "1.0.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e54c9a88f2da7238af84b5101443f0c0d0a3bbdc455e34a5c9497b1903ed55d5" +checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.115" +version = "1.0.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "609feed1d0a73cc36a0182a840a9b37b4a82f0b1150369f0536a9e3f2a31dc48" +checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852" dependencies = [ "proc-macro2", "quote", @@ -2448,11 +2832,11 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.57" +version = "1.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "164eacbdb13512ec2745fb09d51fd5b22b0d65ed294a1dcf7285a360c80a675c" +checksum = "6ce777b7b150d76b9cf60d28b55f5847135a003f7d7350c6be7a773508ce7d45" dependencies = [ - "itoa", + "itoa 1.0.4", "ryu", "serde", ] @@ -2464,75 +2848,119 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ec5d77e2d4c73717816afac02670d5c4f534ea95ed430442cad02e7a6e32c97" dependencies = [ "dtoa", - "itoa", + "itoa 0.4.8", "serde", "url", ] [[package]] -name = "sha-1" -version = "0.8.2" +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa 1.0.4", + "ryu", + "serde", +] + +[[package]] +name = "serde_yaml" +version = "0.9.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" +checksum = "6d232d893b10de3eb7258ff01974d6ee20663d8e833263c99409d4b13a0209da" dependencies = [ - "block-buffer 0.7.3", - "digest 0.8.1", - "fake-simd", - "opaque-debug 0.2.3", + "indexmap", + "itoa 1.0.4", + "ryu", + "serde", + "unsafe-libyaml", ] [[package]] name = "sha1" -version = "0.6.0" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770" +dependencies = [ + "sha1_smol", +] + +[[package]] +name = "sha1" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.10.5", +] + +[[package]] +name = "sha1_smol" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" +checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" [[package]] name = "sha2" -version = "0.9.1" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2933378ddfeda7ea26f48c555bdad8bb446bf8a3d17832dc83e380d444cfb8c1" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" dependencies = [ "block-buffer 0.9.0", - "cfg-if", - "cpuid-bool", + "cfg-if 1.0.0", + "cpufeatures", "digest 0.9.0", - "opaque-debug 0.3.0", + "opaque-debug", +] + +[[package]] +name = "sharded-slab" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +dependencies = [ + "lazy_static", ] [[package]] name = "shlex" -version = "0.1.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" +checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" [[package]] name = "signal-hook-registry" -version = "1.2.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e12110bc539e657a646068aaf5eb5b63af9d0c1f7b29c97113fad80e15f035" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" dependencies = [ - "arc-swap", "libc", ] [[package]] name = "slab" -version = "0.4.2" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" +checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +dependencies = [ + "autocfg", +] [[package]] name = "smallvec" -version = "1.4.2" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbee7696b84bbf3d89a1c2eccff0850e3047ed46bfcd2e92c29a2d074d57e252" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" [[package]] name = "snafu" -version = "0.6.8" +version = "0.6.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7f5aed652511f5c9123cf2afbe9c244c29db6effa2abb05c866e965c82405ce" +checksum = "eab12d3c261b2308b0d80c26fffb58d17eba81a4be97890101f416b478c79ca7" dependencies = [ "doc-comment", "snafu-derive", @@ -2540,9 +2968,9 @@ dependencies = [ [[package]] name = "snafu-derive" -version = "0.6.8" +version = "0.6.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebf8f7d5720104a9df0f7076a8682024e958bba0fe9848767bb44f251f3648e9" +checksum = "1508efa03c362e23817f96cde18abed596a25219a8b2c66e8db33c03543d315b" dependencies = [ "proc-macro2", "quote", @@ -2551,74 +2979,25 @@ dependencies = [ [[package]] name = "socket2" -version = "0.3.12" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03088793f677dce356f3ccc2edb1b314ad191ab702a5de3faf49304f7e104918" +checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "libc", - "redox_syscall", "winapi 0.3.9", ] [[package]] -name = "standback" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33a71ea1ea5f8747d1af1979bfb7e65c3a025a70609f04ceb78425bc5adad8e6" -dependencies = [ - "version_check", -] - -[[package]] -name = "stdweb" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" -dependencies = [ - "discard", - "rustc_version", - "stdweb-derive", - "stdweb-internal-macros", - "stdweb-internal-runtime", - "wasm-bindgen", -] - -[[package]] -name = "stdweb-derive" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" -dependencies = [ - "proc-macro2", - "quote", - "serde", - "serde_derive", - "syn", -] - -[[package]] -name = "stdweb-internal-macros" -version = "0.2.9" +name = "socket2" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" +checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" dependencies = [ - "base-x", - "proc-macro2", - "quote", - "serde", - "serde_derive", - "serde_json", - "sha1", - "syn", + "libc", + "winapi 0.3.9", ] -[[package]] -name = "stdweb-internal-runtime" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" - [[package]] name = "strsim" version = "0.10.0" @@ -2627,26 +3006,32 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "subtle" -version = "2.2.3" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "502d53007c02d7605a05df1c1a73ee436952781653da5d0bf57ad608f66932c1" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.38" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e69abc24912995b3038597a7a593be5053eb0fb44f3cc5beec0deb421790c1f4" +checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d" dependencies = [ "proc-macro2", "quote", - "unicode-xid", + "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20518fe4a4c9acf048008599e464deb21beeae3d3578418951a189c235a7a9a8" + [[package]] name = "synstructure" -version = "0.12.4" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ "proc-macro2", "quote", @@ -2656,13 +3041,13 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.1.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", + "fastrand", "libc", - "rand", "redox_syscall", "remove_dir_all", "winapi 0.3.9", @@ -2670,36 +3055,33 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.1.0" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" dependencies = [ "winapi-util", ] [[package]] name = "textwrap" -version = "0.12.1" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "203008d98caf094106cfaba70acfed15e18ed3ddb7d94e49baec153a2b462789" -dependencies = [ - "unicode-width", -] +checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" -version = "1.0.21" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "318234ffa22e0920fe9a40d7b8369b5f649d490980cf7aadcf1eb91594869b42" +checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.21" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cae2447b6282786c3493999f40a9be2a6ad20cb8bd268b0a0dbf5a065535c0ab" +checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" dependencies = [ "proc-macro2", "quote", @@ -2708,11 +3090,11 @@ dependencies = [ [[package]] name = "thread_local" -version = "1.0.1" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" +checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" dependencies = [ - "lazy_static", + "once_cell", ] [[package]] @@ -2726,86 +3108,113 @@ dependencies = [ [[package]] name = "time" -version = "0.1.43" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" dependencies = [ "libc", + "wasi 0.10.0+wasi-snapshot-preview1", "winapi 0.3.9", ] [[package]] name = "time" -version = "0.2.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a51cadc5b1eec673a685ff7c33192ff7b7603d0b75446fb354939ee615acb15" +checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" dependencies = [ - "cfg-if", - "libc", - "standback", - "stdweb", + "itoa 1.0.4", + "serde", + "time-core", "time-macros", - "version_check", - "winapi 0.3.9", ] [[package]] -name = "time-macros" +name = "time-core" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ae9b6e9f095bc105e183e3cd493d72579be3181ad4004fceb01adbe9eecab2d" +checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" + +[[package]] +name = "time-macros" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d967f99f534ca7e495c575c62638eebc2898a8c84c119b89e250477bc4ba16b2" dependencies = [ - "proc-macro-hack", - "time-macros-impl", + "time-core", ] [[package]] -name = "time-macros-impl" -version = "0.1.1" +name = "tinyvec" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5c3be1edfad6027c69f5491cf4cb310d1a71ecd6af742788c6ff8bced86b8fa" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" dependencies = [ - "proc-macro-hack", - "proc-macro2", - "quote", - "standback", - "syn", + "tinyvec_macros", ] [[package]] -name = "tinyvec" -version = "0.3.3" +name = "tinyvec_macros" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53953d2d3a5ad81d9f844a32f14ebb121f50b650cd59d0ee2a07cf13c617efed" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "0.2.22" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d34ca54d84bf2b5b4d7d31e901a8464f7b60ac145a284fba25ceb801f2ddccd" +checksum = "6703a273949a90131b290be1fe7b039d0fc884aa1935860dfcbe056f28cd8092" dependencies = [ - "bytes", - "fnv", + "bytes 0.5.6", "futures-core", "iovec", "lazy_static", "libc", "memchr", - "mio", - "mio-named-pipes", + "mio 0.6.23", "mio-uds", - "pin-project-lite 0.1.7", + "pin-project-lite 0.1.12", "signal-hook-registry", "slab", + "winapi 0.3.9", +] + +[[package]] +name = "tokio" +version = "1.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e03c497dc955702ba729190dc4aac6f2a0ce97f913e5b1b5912fc5039d9099" +dependencies = [ + "autocfg", + "bytes 1.2.1", + "libc", + "memchr", + "mio 0.8.5", + "num_cpus", + "parking_lot 0.12.1", + "pin-project-lite 0.2.9", + "signal-hook-registry", + "socket2 0.4.7", "tokio-macros", + "tracing", "winapi 0.3.9", ] +[[package]] +name = "tokio-io-timeout" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" +dependencies = [ + "pin-project-lite 0.2.9", + "tokio 1.21.2", +] + [[package]] name = "tokio-macros" -version = "0.2.5" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0c3acc6aa564495a0f2e1d59fab677cd7f81a19994cfc7f3ad0e64301560389" +checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" dependencies = [ "proc-macro2", "quote", @@ -2813,27 +3222,38 @@ dependencies = [ ] [[package]] -name = "tokio-tar" -version = "0.2.0" +name = "tokio-native-tls" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3a9e415c93375be93253134543229563114a2be8d46440d6d8f25b2ec62a7fb" +checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" dependencies = [ - "filetime", - "futures-core", - "libc", - "redox_syscall", - "tokio", - "xattr", + "native-tls", + "tokio 1.21.2", ] [[package]] -name = "tokio-tls" -version = "0.3.1" +name = "tokio-stream" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a70f4fcd7b3b24fb194f837560168208f669ca8cb70d0c4b862944452396343" +checksum = "d660770404473ccd7bc9f8b28494a811bc18542b915c0855c51e8f419d5223ce" dependencies = [ - "native-tls", - "tokio", + "futures-core", + "pin-project-lite 0.2.9", + "tokio 1.21.2", +] + +[[package]] +name = "tokio-tar" +version = "0.3.0" +source = "git+https://github.com/vorot93/tokio-tar.git?rev=1bd30fbd1a219e8982571da48eb68f34317d1e15#1bd30fbd1a219e8982571da48eb68f34317d1e15" +dependencies = [ + "filetime", + "futures-core", + "libc", + "redox_syscall", + "tokio 1.21.2", + "tokio-stream", + "xattr", ] [[package]] @@ -2842,12 +3262,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "571da51182ec208780505a32528fc5512a8fe1443ab960b3f2f3ef093cd16930" dependencies = [ - "bytes", + "bytes 0.5.6", "futures-core", "futures-sink", "log", - "pin-project-lite 0.1.7", - "tokio", + "pin-project-lite 0.1.12", + "tokio 0.2.25", ] [[package]] @@ -2856,47 +3276,177 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be8242891f2b6cbef26a2d7e8605133c2c554cd35b3e4948ea892d6d68436499" dependencies = [ - "bytes", + "bytes 0.5.6", "futures-core", "futures-sink", "log", - "pin-project-lite 0.1.7", - "tokio", + "pin-project-lite 0.1.12", + "tokio 0.2.25", +] + +[[package]] +name = "tokio-util" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" +dependencies = [ + "bytes 1.2.1", + "futures-core", + "futures-sink", + "pin-project-lite 0.2.9", + "tokio 1.21.2", + "tracing", ] [[package]] name = "toml" -version = "0.5.6" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a" +checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" dependencies = [ "serde", ] +[[package]] +name = "tonic" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55b9af819e54b8f33d453655bef9b9acc171568fb49523078d0cc4e7484200ec" +dependencies = [ + "async-stream", + "async-trait", + "axum", + "base64 0.13.1", + "bytes 1.2.1", + "futures-core", + "futures-util", + "h2 0.3.15", + "http", + "http-body", + "hyper", + "hyper-timeout", + "percent-encoding", + "pin-project 1.0.12", + "prost", + "prost-derive", + "tokio 1.21.2", + "tokio-stream", + "tokio-util 0.7.4", + "tower", + "tower-layer", + "tower-service", + "tracing", + "tracing-futures", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "indexmap", + "pin-project 1.0.12", + "pin-project-lite 0.2.9", + "rand 0.8.5", + "slab", + "tokio 1.21.2", + "tokio-util 0.7.4", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c530c8675c1dbf98facee631536fa116b5fb6382d7dd6dc1b118d970eafe3ba" +dependencies = [ + "bitflags", + "bytes 1.2.1", + "futures-core", + "futures-util", + "http", + "http-body", + "http-range-header", + "pin-project-lite 0.2.9", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + [[package]] name = "tower-service" -version = "0.3.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e987b6bf443f4b5b3b6f38704195592cca41c5bb7aedd3c3693c7081f8289860" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.19" +version = "0.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d79ca061b032d6ce30c660fded31189ca0b9922bf483cd70759f13a2d86786c" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "log", + "pin-project-lite 0.2.9", + "tracing-attributes", "tracing-core", ] +[[package]] +name = "tracing-attributes" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "tracing-core" -version = "0.1.14" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db63662723c316b43ca36d833707cc93dff82a02ba3d7e354f342682cc8b3545" +checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" dependencies = [ - "lazy_static", + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-futures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +dependencies = [ + "pin-project 1.0.12", + "tracing", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70" +dependencies = [ + "matchers", + "once_cell", + "regex", + "sharded-slab", + "thread_local", + "tracing", + "tracing-core", ] [[package]] @@ -2909,13 +3459,13 @@ dependencies = [ "enum-as-inner", "failure", "futures", - "idna", + "idna 0.2.3", "lazy_static", "log", - "rand", + "rand 0.7.3", "smallvec", - "socket2", - "tokio", + "socket2 0.3.19", + "tokio 0.2.25", "url", ] @@ -2925,7 +3475,7 @@ version = "0.18.0-alpha.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f90b1502b226f8b2514c6d5b37bafa8c200d7ca4102d57dc36ee0f3b7a04a2f" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "failure", "futures", "ipconfig", @@ -2934,7 +3484,7 @@ dependencies = [ "lru-cache", "resolv-conf", "smallvec", - "tokio", + "tokio 0.2.25", "trust-dns-proto", ] @@ -2946,21 +3496,21 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" [[package]] name = "typenum" -version = "1.12.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" [[package]] name = "ucd-trie" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" +checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" [[package]] name = "uncased" -version = "0.9.3" +version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "369fa7fd7969c5373541d3c9a40dc1b76ce676fc87aba30d87c0ad3b97fad179" +checksum = "09b01702b0fd0b3fadcf98e098780badda8742d4f4a7676615cad90e8ac73622" dependencies = [ "version_check", ] @@ -2976,86 +3526,71 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.4" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" -dependencies = [ - "matches", -] +checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" + +[[package]] +name = "unicode-ident" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" [[package]] name = "unicode-normalization" -version = "0.1.13" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb19cf769fa8c6a80a162df694621ebeb4dafb606470b2b2fce0be40a98a977" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" dependencies = [ "tinyvec", ] -[[package]] -name = "unicode-segmentation" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0" - [[package]] name = "unicode-width" -version = "0.1.8" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" [[package]] name = "unicode-xid" -version = "0.2.1" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" [[package]] -name = "unindent" -version = "0.1.6" +name = "unsafe-libyaml" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af41d708427f8fd0e915dcebb2cae0f0e6acb2a939b2d399c265c39a38a18942" +checksum = "c1e5fa573d8ac5f1a856f8d7be41d390ee973daf97c806b2c1a465e4e1406e68" [[package]] name = "url" -version = "2.1.1" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "829d4a8476c35c9bf0bbce5a3b23f4106f79728039b726d292bb93bc106787cb" +checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" dependencies = [ - "idna", - "matches", + "form_urlencoded", + "idna 0.3.0", "percent-encoding", ] [[package]] -name = "vcpkg" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6454029bf181f092ad1b853286f23e2c507d8e8194d01d92da4a55c274a5508c" - -[[package]] -name = "vec-arena" -version = "0.5.2" +name = "valuable" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cb18268690309760d59ee1a9b21132c126ba384f374c59a94db4bc03adeb561" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" [[package]] -name = "vec_map" -version = "0.8.2" +name = "vcpkg" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "version_check" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" - -[[package]] -name = "waker-fn" -version = "1.1.0" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "want" @@ -3073,48 +3608,48 @@ version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + [[package]] name = "wasm-bindgen" -version = "0.2.67" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0563a9a4b071746dd5aedbc3a28c6fe9be4586fb3fbadb67c400d4f53c6b16c" +checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.67" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc71e4c5efa60fb9e74160e89b93353bc24059999c0ae0fb03affc39770310b0" +checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" dependencies = [ "bumpalo", - "lazy_static", "log", + "once_cell", "proc-macro2", "quote", "syn", "wasm-bindgen-shared", ] -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95f8d235a77f880bcef268d379810ea6c0af2eacfa90b1ad5af731776e0c4699" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - [[package]] name = "wasm-bindgen-macro" -version = "0.2.67" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97c57cefa5fa80e2ba15641578b44d36e7a64279bc5ed43c6dbaf329457a2ed2" +checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3122,9 +3657,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.67" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841a6d1c35c6f596ccea1f82504a192a60378f64b3bb0261904ad8f2f5657556" +checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" dependencies = [ "proc-macro2", "quote", @@ -3135,34 +3670,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.67" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93b162580e34310e5931c4b792560108b10fd14d64915d7fff8ff00180e70092" - -[[package]] -name = "web-sys" -version = "0.3.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dda38f4e5ca63eda02c059d243aa25b5f35ab98451e518c51612cd0f1bd19a47" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "wepoll-sys-stjepang" -version = "1.0.6" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fd319e971980166b53e17b1026812ad66c6b54063be879eb182342b55284694" -dependencies = [ - "cc", -] +checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" [[package]] name = "widestring" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a763e303c0e0f23b0da40888724762e802a8ffefbc22de4127ef42493c2ea68c" +checksum = "c168940144dd21fd8046987c16a46a33d5fc84eec29ef9dcddc2ac9e31526b7c" [[package]] name = "winapi" @@ -3207,6 +3723,106 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc 0.36.1", + "windows_i686_gnu 0.36.1", + "windows_i686_msvc 0.36.1", + "windows_x86_64_gnu 0.36.1", + "windows_x86_64_msvc 0.36.1", +] + +[[package]] +name = "windows-sys" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc 0.42.0", + "windows_i686_gnu 0.42.0", + "windows_i686_msvc 0.42.0", + "windows_x86_64_gnu 0.42.0", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc 0.42.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" + +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" + +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" + [[package]] name = "winreg" version = "0.6.2" @@ -3228,27 +3844,65 @@ dependencies = [ [[package]] name = "xattr" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "244c3741f4240ef46274860397c7c74e50eb23624996930e484c16679633a54c" +checksum = "6d1526bbe5aaeb5eb06885f4d987bcdfa5e23187055de9b83fe00156a821fabc" dependencies = [ "libc", ] +[[package]] +name = "xdg" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4583db5cbd4c4c0303df2d15af80f0539db703fa1c68802d4cbbd2dd0f88f6" +dependencies = [ + "dirs", +] + [[package]] name = "xml-rs" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b07db065a5cf61a7e4ba64f29e67db906fb1787316516c4e6e5ff0fea1efcd8a" +checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3" [[package]] name = "yansi" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc79f4a1e39857fc00c3f662cbf2651c771f00e9c15fe2abc341806bd46bd71" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" [[package]] name = "zeroize" -version = "1.1.0" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" + +[[package]] +name = "zstd" +version = "0.11.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "5.0.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.1+zstd.1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cbac2ed2ba24cc90f5e06485ac8c7c1e5449fe8911aef4d8877218af021a5b8" +checksum = "9fd07cbbc53846d9145dbffdf6dd09a7a0aa52be46741825f5c97bdd4f73f12b" +dependencies = [ + "cc", + "libc", +] diff --git a/Cargo.toml b/Cargo.toml index a468e9deccc37bde92bcc9195b112e3f79a2ea84..aa0352abb4764e84cbf6e2c183ea6a3f8075623f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,58 +1,69 @@ [package] name = "espresso" -version = "1.0.1" +version = "2.0.0" authors = ["Eduardo Trujillo <ed@chromabits.com>"] edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -actix = "0.9.0" -actix-web = "2.0.0" -actix-rt = "1.0" -bitflags = "1.2.1" +actix = "0.13" +actix-files = "0.6" actix-http = "1.0.1" -mime_guess = "2.0.3" -mime = "0.3.16" -futures-util = "0.3.5" -actix-service = "1.0.6" -percent-encoding = "2.1.0" +actix-rt = "2.6" +actix-service = "2.0" +actix-web = "4.2" +anyhow = "1.0" +async-recursion = "1.0" +async-trait = "0.1.40" +bitflags = "1.2.1" +bytes = "1.2.1" +clap = { version = "3.1", features = ["derive"]} +console-subscriber = { version = "0.1.8", optional = true } futures-core = "0.3.5" -bytes = "0.5.6" +futures-util = "0.3.5" +handlebars = "3.4" +indoc = "1.0" +lazy_static = "1.4.0" log = "0.4" -snafu = "0.6.8" +mime = "0.3.16" +mime_guess = "2.0.3" +percent-encoding = "2.1.0" +pretty_env_logger = "0.4.0" +regex = "1.3" +rusoto_core = "0.48.0" +rusoto_credential = "0.48.0" +rusoto_s3 = "0.48.0" serde = "1.0.115" serde_derive = "1.0.115" serde_json = "1.0" +snafu = "0.6.8" +tokio-stream = "0.1" toml = "0.5" -pretty_env_logger = "0.4.0" -rusoto_core = "0.45.0" -rusoto_s3 = "0.45.0" -rusoto_credential = "0.45.0" -async-trait = "0.1.40" -async-tar = "0.3" -async-compat = "0.1.3" -lazy_static = "1.4.0" -anyhow = "1.0" url = "2.1" -indoc = "1.0" -handlebars = "3.4" -regex = "1.3" -tokio-tar = "0.2.0" -clap = "3.0.0-beta.2" [dependencies.collective] git = "https://gitlab.chromabits.com/etcinit/collective.git" -tag = "0.1.2" +rev = "f6f46f690d63f142ad6c5e95dd806d24b9cea6d4" [dependencies.tokio] -version = "0.2" -features = ["stream", "signal", "macros"] +version = "1.0" +features = ["signal", "macros", "fs", "sync"] [dependencies.tokio-util] -version = "0.3.0" +version = "0.7" features = ["codec"] +[dependencies.tokio-tar] +git = "https://github.com/vorot93/tokio-tar.git" +rev = "1bd30fbd1a219e8982571da48eb68f34317d1e15" + [dependencies.async-compression] -version = "0.3.7" -features = ["gzip", "tokio-02"] \ No newline at end of file +version = "0.3" +features = ["gzip", "tokio"] + +[dev-dependencies] +actix-test = "0.1.0" + +[features] +console-subscriber = ["dep:console-subscriber", "tokio/tracing"] \ No newline at end of file diff --git a/README.md b/README.md index de28913a456683cc8d2ef844f77c4bb3237077a4..24574e2941f3dfa0f3ba7f68a7b0fafc2a92d1b3 100644 --- a/README.md +++ b/README.md @@ -71,3 +71,11 @@ minikube service --url espresso `RUST_LOG=info cargo run` to build and run the server. `RUST_LOG=info cargo test` to run all tests. + +**tokio-console:** + +Support for `tokio-console` can be enabled with the `console-subscriber` flag: + +```sh +RUSTFLAGS="--cfg tokio_unstable" cargo run -F console-subscriber +``` \ No newline at end of file diff --git a/src/bundle/local_dir/poller.rs b/src/bundle/local_dir/poller.rs index 0a10c8760660415d4711e461bd541c458b9c8c72..ed385869ac04aecca64a729e3a520cfb96854c95 100644 --- a/src/bundle/local_dir/poller.rs +++ b/src/bundle/local_dir/poller.rs @@ -19,7 +19,7 @@ impl LocalBundlePoller { impl BundlePoller for LocalBundlePoller { async fn poll(&self, active_bundle: &Option<Bundle>) -> Result<PollResult> { if active_bundle.is_none() { - info!( + log::info!( "LocalBundlePoller: Updating bundle (Local dir: {}).", self.dir.display() ); @@ -30,13 +30,13 @@ impl BundlePoller for LocalBundlePoller { }); } - info!("LocalBundlePoller: Local dir. No update needed."); + log::info!("LocalBundlePoller: Local dir. No update needed."); Ok(PollResult::Skip) } async fn retrieve(&self, _bundle_id: &str, _path: PathBuf) -> Result<()> { - warn!("LocalBundlePoller: retrieve is not supported. Ignoring."); + log::warn!("LocalBundlePoller: retrieve is not supported. Ignoring."); Ok(()) } diff --git a/src/bundle/mod.rs b/src/bundle/mod.rs index 68cd98e2880fd3120e92ed0668b6722267d2ad66..191aa17676a063db376eaacadb0b0d26b56415d2 100644 --- a/src/bundle/mod.rs +++ b/src/bundle/mod.rs @@ -1,32 +1,31 @@ use crate::config::Config; -use rundir::RunDir; +use collective::rundir::{self, RunDir}; use s3::packager::S3BundlePackager; use serde::Serialize; use snafu::{ResultExt, Snafu}; -use std::{ - path::PathBuf, - sync::{Arc, RwLock}, +use std::{path::PathBuf, sync::Arc}; +use tokio::{ + sync::RwLock, + time::{interval, Duration}, }; -use tokio::time::{interval, Duration}; use self::{local_dir::poller::LocalBundlePoller, s3::poller::S3BundlePoller}; pub mod local_dir; pub mod packager; pub mod poller; -pub mod rundir; pub mod s3; #[derive(Snafu, Debug)] pub enum Error { - InitRunDir { source: rundir::Error }, - DeinitRunDir { source: rundir::Error }, + InitRunDir { source: rundir::RunDirError }, + DeinitRunDir { source: rundir::RunDirError }, LockRead, LockWrite, AttachSignalHook { source: std::io::Error }, MissingETag, PollError { source: poller::Error }, - SubDirError { source: rundir::Error }, + SubDirError { source: rundir::RunDirError }, } type Result<T, E = Error> = std::result::Result<T, E>; @@ -145,20 +144,20 @@ impl Unbundler { } } - pub fn get_status(&self) -> Result<UnbundlerStatus> { - let state = self.state.read().map_err(|_| Error::LockRead)?; + pub async fn get_status(&self) -> Result<UnbundlerStatus> { + let state = self.state.read().await; Ok(state.status) } - pub fn get_serve_dir(&self) -> Result<Option<PathBuf>> { - let serve_dir = self.serve_dir.read().map_err(|_| Error::LockRead)?; + pub async fn get_serve_dir(&self) -> Result<Option<PathBuf>> { + let serve_dir = self.serve_dir.read().await; Ok(serve_dir.clone()) } pub async fn enter(&self) -> Result<()> { - self.init()?; + self.init().await?; let mut interval = interval(Duration::from_secs(self.config.unbundler.poll_seconds)); let ctrl_c_fut = tokio::signal::ctrl_c(); @@ -175,19 +174,19 @@ impl Unbundler { _ = interval.tick() => { match me.poll().await { Ok(_) => {} - Err(err) => error!("Unbundler: Got an error while invoking poller: {:?}", err), + Err(err) => log::error!("Unbundler: Got an error while invoking poller: {:?}", err), }; } } } - self.deinit() + self.deinit().await } - fn init(&self) -> Result<()> { - info!("Unbundler: Initializing..."); + async fn init(&self) -> Result<()> { + log::info!("Unbundler: Initializing..."); - let mut state = self.state.write().map_err(|_| Error::LockWrite)?; + let mut state = self.state.write().await; state.rundir.initialize().context(InitRunDir)?; state.temp_dir = Some(state.rundir.create_subdir("temp").context(InitRunDir)?); @@ -198,14 +197,14 @@ impl Unbundler { } async fn poll(&self) -> Result<()> { - info!("Unbundler: Checking for updates..."); + log::info!("Unbundler: Checking for updates..."); // Update state on a spearate scope to avoid holding a write lock while // the poller runs. // // Lock will be released when `initial_state` goes out of scope. let active_bundle = { - let mut initial_state = self.state.write().map_err(|_| Error::LockWrite)?; + let mut initial_state = self.state.write().await; let active_bundle = initial_state.active_bundle.clone(); if active_bundle.is_none() { @@ -220,7 +219,7 @@ impl Unbundler { // Invoke the poller. let result = match self.poller.poll(&active_bundle).await { Err(err) => { - let mut state = self.state.write().map_err(|_| Error::LockWrite)?; + let mut state = self.state.write().await; // Rollback status if the poll fails. if active_bundle.is_none() { @@ -237,33 +236,33 @@ impl Unbundler { match result { poller::PollResult::Skip => { - let mut state = self.state.write().map_err(|_| Error::LockWrite)?; + let mut state = self.state.write().await; state.status = UnbundlerStatus::Ready; - info!("Unbundler: No updates from poller."); + log::info!("Unbundler: No updates from poller."); Ok(()) } poller::PollResult::StaticUpdateReady { etag, path } => { - let mut state = self.state.write().map_err(|_| Error::LockWrite)?; + let mut state = self.state.write().await; // Replacing active bundle. state.active_bundle = Some(Bundle { etag }); state.staging_bundle = None; state.status = UnbundlerStatus::Ready; - let mut serve_dir = self.serve_dir.write().map_err(|_| Error::LockWrite)?; + let mut serve_dir = self.serve_dir.write().await; serve_dir.replace(path); Ok(()) } poller::PollResult::UpdateReady { etag } => { - let mut state = self.state.write().map_err(|_| Error::LockWrite)?; + let mut state = self.state.write().await; if state.rundir.subdir_exists(&etag).context(SubDirError)? { - warn!("Unbundler: Skipping update. Subdir already exists."); + log::warn!("Unbundler: Skipping update. Subdir already exists."); return Ok(()); } @@ -277,7 +276,7 @@ impl Unbundler { let result = self.poller.retrieve(&etag, newdir.clone()).await; if result.is_err() { - warn!("Unbundler: Poller failed to retrieve new bundle. Rolling back."); + log::warn!("Unbundler: Poller failed to retrieve new bundle. Rolling back."); state.staging_bundle = None; state.status = UnbundlerStatus::Ready; @@ -292,7 +291,7 @@ impl Unbundler { state.staging_bundle = None; state.status = UnbundlerStatus::Ready; - let mut serve_dir = self.serve_dir.write().map_err(|_| Error::LockWrite)?; + let mut serve_dir = self.serve_dir.write().await; serve_dir.replace(newdir); @@ -301,8 +300,8 @@ impl Unbundler { } } - fn deinit(&self) -> Result<()> { - let mut state = self.state.write().map_err(|_| Error::LockWrite)?; + async fn deinit(&self) -> Result<()> { + let mut state = self.state.write().await; state.status = UnbundlerStatus::Idle; state.rundir.cleanup().context(DeinitRunDir)?; diff --git a/src/bundle/rundir.rs b/src/bundle/rundir.rs deleted file mode 100644 index 5574040f2a97711612a94e2b924af08ca5c70857..0000000000000000000000000000000000000000 --- a/src/bundle/rundir.rs +++ /dev/null @@ -1,266 +0,0 @@ -use snafu::{ResultExt, Snafu}; -use std::path::{Path, PathBuf}; - -#[derive(Snafu, Debug)] -pub enum Error { - Initialize { - path: PathBuf, - }, - PathIsNotDir { - path: PathBuf, - }, - DirIsNotEmpty { - path: PathBuf, - child_path: PathBuf, - }, - CreateDir { - path: PathBuf, - source: std::io::Error, - }, - ScanDir { - path: PathBuf, - source: std::io::Error, - }, - RecreateDir { - path: PathBuf, - source: std::io::Error, - }, - RemoveSubDir { - path: PathBuf, - source: std::io::Error, - }, - InvalidSubDirName { - name: String, - inner_error: Option<std::io::Error>, - }, -} - -type Result<T, E = Error> = std::result::Result<T, E>; - -pub struct RunDir { - path: PathBuf, - allow_cleaning: bool, -} - -impl RunDir { - pub fn new<T: Into<PathBuf>>(path: T) -> RunDir { - RunDir { - path: path.into(), - allow_cleaning: false, - } - } - - /// Set whether the directory can perform cleanup operations. - /// - /// Use with caution. This will clear existing directories on initialization - /// and cleanup. - pub fn allow_cleaning(mut self, allow_cleaning: bool) -> RunDir { - self.allow_cleaning = allow_cleaning; - - self - } - - /// Creates the initial RunDir. - /// - /// # Examples - /// - /// ``` - /// use espresso::bundle::rundir::RunDir; - /// - /// let rundir = RunDir::new("tests/rundir").allow_cleaning(true); - /// - /// rundir.initialize().unwrap(); - /// - /// rundir.cleanup().unwrap(); - /// ``` - pub fn initialize(&self) -> Result<()> { - if Path::exists(&self.path) { - info!("RunDir already exists: {}", self.path.display()); - - if !Path::is_dir(&self.path) { - error!("RunDir is not a directory: {}", self.path.display()); - - return Err(Error::PathIsNotDir { - path: self.path.clone(), - }); - } else { - // Scan dir - let mut dir_iterator = std::fs::read_dir(&self.path).context(ScanDir { - path: self.path.clone(), - })?; - - let existing_child_path = dir_iterator - .next() - .map(|entry_result| entry_result.map(|entry| entry.path())); - - if let Some(child_path) = existing_child_path { - let child_path = child_path.context(ScanDir { - path: self.path.clone(), - })?; - - if self.allow_cleaning { - info!("Recreating RunDir."); - - std::fs::remove_dir_all(&self.path).context(RecreateDir { - path: self.path.clone(), - })?; - - std::fs::create_dir_all(&self.path).context(RecreateDir { - path: self.path.clone(), - })?; - } else { - return Err(Error::DirIsNotEmpty { - path: self.path.clone(), - child_path, - }); - } - } - } - } else { - info!("Creating new RunDir: {}", self.path.display()); - - std::fs::create_dir_all(&self.path).context(CreateDir { - path: self.path.clone(), - })? - } - - Ok(()) - } - - pub fn cleanup(&self) -> Result<()> { - if self.allow_cleaning { - std::fs::remove_dir_all(&self.path).context(RecreateDir { - path: self.path.clone(), - })?; - - info!("Cleaned up RunDir: {}", self.path.display()); - } else { - warn!("Leaving RunDir unmodified. Manual cleanup may be needed."); - } - - Ok(()) - } - - /// Creates a subdir within the RunDir. - pub fn create_subdir(&self, name: &str) -> Result<PathBuf> { - let pathbuf = self.validate_subdir_name(name)?; - - std::fs::create_dir(&pathbuf).context(CreateDir { - path: pathbuf.clone(), - })?; - - Ok(pathbuf) - } - - /// Removes a subdir and all its contents from the RunDir. - pub fn remove_subdir_all(&self, name: &str) -> Result<()> { - let pathbuf = self.validate_subdir_name(name)?; - - std::fs::remove_dir_all(&pathbuf).context(RemoveSubDir { path: pathbuf })?; - - Ok(()) - } - - /// Checks if a subdir exists within the RunDir. - pub fn subdir_exists(&self, name: &str) -> Result<bool> { - let pathbuf = self.validate_subdir_name(name)?; - - Ok(pathbuf.exists()) - } - - fn validate_subdir_name(&self, name: &str) -> Result<PathBuf> { - // Check that the name results in a dir exactly one level below the current one. - let mut pathbuf = self.path.clone(); - - pathbuf.push(name); - - if let Some(parent) = pathbuf.parent() { - if PathBuf::from(parent) != PathBuf::from(&self.path) { - return Err(Error::InvalidSubDirName { - name: String::from(name), - inner_error: None, - }); - } - } else { - return Err(Error::InvalidSubDirName { - name: String::from(name), - inner_error: None, - }); - } - - Ok(pathbuf) - } -} - -#[cfg(test)] -mod tests { - use super::{Error, RunDir}; - use std::path::PathBuf; - - #[test] - fn test_initialize() -> () { - // Create dir for the first time. - let result = RunDir::new("tests/rundir").initialize(); - - assert!(result.is_ok()); - - // Use existing empty dir. - let result = RunDir::new("tests/rundir").initialize(); - - assert!(result.is_ok()); - - // Fail when dir is not empty and allow_cleaning is not set. - std::fs::write("tests/rundir/hello.world", "test").unwrap(); - let result = RunDir::new("tests/rundir").initialize(); - - match result { - Err(Error::DirIsNotEmpty { path, child_path }) => { - assert_eq!(path, PathBuf::from("tests/rundir")); - assert_eq!(child_path, PathBuf::from("tests/rundir/hello.world")); - } - _ => panic!("Expected an error."), - } - - // Clean existing dir. - let result = RunDir::new("tests/rundir") - .allow_cleaning(true) - .initialize(); - - assert!(result.is_ok()); - - std::fs::remove_dir("tests/rundir").unwrap(); - - // Fail when dir is not a directory. - std::fs::write("tests/rundir", "hello").unwrap(); - let result = RunDir::new("tests/rundir").initialize(); - - match result { - Err(Error::PathIsNotDir { path }) => { - assert_eq!(path, PathBuf::from("tests/rundir")); - } - _ => panic!("Expected an error."), - } - - std::fs::remove_file("tests/rundir").unwrap(); - } - - #[test] - fn test_subdirs() -> () { - let rundir = RunDir::new("tests/rundir2").allow_cleaning(true); - - rundir.initialize().unwrap(); - - assert_eq!(PathBuf::from("tests/rundir2/subtest").exists(), false); - assert_eq!(rundir.subdir_exists("subtest").unwrap(), false); - - rundir.create_subdir("subtest").unwrap(); - assert_eq!(PathBuf::from("tests/rundir2/subtest").exists(), true); - assert_eq!(rundir.subdir_exists("subtest").unwrap(), true); - - rundir.remove_subdir_all("subtest").unwrap(); - assert_eq!(PathBuf::from("tests/rundir2/subtest").exists(), false); - assert_eq!(rundir.subdir_exists("subtest").unwrap(), false); - - rundir.cleanup().unwrap(); - } -} diff --git a/src/bundle/s3/packager.rs b/src/bundle/s3/packager.rs index 41dbe13f0cce1053dacfb1d56aa8dd5fa6c220d3..248127a7aeb93df3ca70c27111bee0422dcec787 100644 --- a/src/bundle/s3/packager.rs +++ b/src/bundle/s3/packager.rs @@ -1,5 +1,5 @@ use crate::bundle::packager::{BundlePackager, Error, Result}; -use async_compression::tokio_02::write::GzipEncoder; +use async_compression::tokio::write::GzipEncoder; use async_trait::async_trait; use futures_util::TryStreamExt; use rusoto_core::RusotoError; diff --git a/src/bundle/s3/poller.rs b/src/bundle/s3/poller.rs index f9ecc256415a90ff71e040087c4277bb69ee04fd..8a2ef57675f57f63945c17ad6be90c2c19fd5609 100644 --- a/src/bundle/s3/poller.rs +++ b/src/bundle/s3/poller.rs @@ -2,8 +2,7 @@ use crate::bundle::{ poller::{BundlePoller, Error, PollResult, Result}, Bundle, }; -use async_compat::CompatExt; -use async_tar::Archive; + use async_trait::async_trait; use rusoto_core::RusotoError; use rusoto_s3::{ @@ -11,6 +10,7 @@ use rusoto_s3::{ }; use snafu::{ResultExt, Snafu}; use std::path::PathBuf; +use tokio_tar::Archive; #[derive(Snafu, Debug)] pub enum InternalError { @@ -81,7 +81,7 @@ impl BundlePoller for S3BundlePoller { .context(S3HeadObjectError)?; if head_response.e_tag == active_bundle.etag { - info!( + log::info!( "S3BundlePoller: No updates found for object: {}", self.object_name ); @@ -89,13 +89,13 @@ impl BundlePoller for S3BundlePoller { // Skip update download return Ok(PollResult::Skip); } else { - info!( + log::info!( "S3BundlePoller: Object {} has changed. Starting bundle update.", self.object_name ); } } else { - error!("S3BundlePoller: Expected the active bundle to have a valid ETag."); + log::error!("S3BundlePoller: Expected the active bundle to have a valid ETag."); return Err(Error::MissingBundleID); } @@ -120,7 +120,7 @@ impl BundlePoller for S3BundlePoller { } async fn retrieve(&self, bundle_id: &str, path: PathBuf) -> Result<()> { - info!("S3BundlePoller: Starting bundle download..."); + log::info!("S3BundlePoller: Starting bundle download..."); let get_object_request = GetObjectRequest { bucket: self.bucket.clone(), @@ -145,16 +145,15 @@ impl BundlePoller for S3BundlePoller { }); } - info!("S3BundlePoller: Unpacking bundle..."); + log::info!("S3BundlePoller: Unpacking bundle..."); + + let stream = get_object_response + .body + .ok_or(InternalError::S3MissingBody)? + .into_async_read(); // TODO: Write temp file to disk. - let archive = Archive::new( - get_object_response - .body - .ok_or(InternalError::S3MissingBody)? - .into_async_read() - .compat(), - ); + let mut archive = Archive::new(stream); archive .unpack(path) diff --git a/src/cli/args.rs b/src/cli/args.rs new file mode 100644 index 0000000000000000000000000000000000000000..fb477f085a138a171530402b2eb1c97fc5b6de44 --- /dev/null +++ b/src/cli/args.rs @@ -0,0 +1,56 @@ +use std::path::PathBuf; + +use clap::{Parser, Subcommand}; +use collective::{ + cli::{AppOpts, ConfigurableAppOpts}, + config::ConfigFileFormat, +}; +use espresso::config::Config; + +#[derive(Parser)] +#[clap(version, author = "Eduardo T. <ed@trujillo.io>")] +pub struct Opts { + /// Sets a custom config file. + #[clap(short, long)] + config: Option<PathBuf>, + /// A level of verbosity, and can be used multiple times + #[clap(short, long, parse(from_occurrences))] + verbose: i32, + #[clap(subcommand)] + pub subcmd: SubCommand, +} + +#[derive(Subcommand)] +pub enum SubCommand { + /// Start the server + Serve, + Bundle(BundleOpts), +} + +/// Create a bundle using the configured bundler +#[derive(Parser)] +pub struct BundleOpts { + /// The path to use a source for the bundle. + pub source_path: PathBuf, +} + +impl AppOpts for Opts { + fn get_log_level_filter(&self) -> Option<log::LevelFilter> { + match self.verbose { + 3 => Some(log::LevelFilter::Trace), + 2 => Some(log::LevelFilter::Debug), + 1 => Some(log::LevelFilter::Info), + _ => None, + } + } +} + +impl ConfigurableAppOpts<Config> for Opts { + fn get_additional_config_paths(&self) -> Vec<(PathBuf, Option<ConfigFileFormat>)> { + if let Some(config_path) = &self.config { + vec![(config_path.clone(), None)] + } else { + vec![] + } + } +} diff --git a/src/cli/bundle.rs b/src/cli/bundle.rs new file mode 100644 index 0000000000000000000000000000000000000000..0ede3af227d100381e9d51560925c66d8f935091 --- /dev/null +++ b/src/cli/bundle.rs @@ -0,0 +1,16 @@ +use std::sync::Arc; + +use espresso::{ + bundle::{packager, Bundler}, + config::Config, +}; + +use super::args::BundleOpts; + +pub async fn bundle(config: Arc<Config>, opts: BundleOpts) -> Result<(), packager::Error> { + let bundler = Bundler::new(config); + + bundler.package(opts.source_path).await.unwrap(); + + Ok(()) +} diff --git a/src/cli/mod.rs b/src/cli/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..605e7370d8aec7ae7dcbafaeff26a08e482742cc --- /dev/null +++ b/src/cli/mod.rs @@ -0,0 +1,3 @@ +pub mod args; +pub mod bundle; +pub mod serve; diff --git a/src/cli/serve.rs b/src/cli/serve.rs new file mode 100644 index 0000000000000000000000000000000000000000..d494e6fabe9d8a34e24b56575f54aa7083d5685a --- /dev/null +++ b/src/cli/serve.rs @@ -0,0 +1,129 @@ +use actix::System; +use collective::thread::{ + self, + monitor::{self, ThreadMonitor}, +}; +use espresso::{ + bundle::{self, Unbundler}, + config::Config, + server::{self, Server}, + stats::{self, StatsServer}, +}; +use lazy_static::lazy_static; +use snafu::{ResultExt, Snafu}; +use std::{ + collections::HashSet, + sync::{mpsc, Arc}, +}; +use tokio::sync::RwLock; + +lazy_static! { + static ref MONITOR: ThreadMonitor = ThreadMonitor::new(); +} + +#[derive(Snafu, Debug)] +pub enum Error { + Unbundle { source: bundle::Error }, + ServeError { source: Box<server::Error> }, + ServeStats { source: stats::Error }, + MonitorError { source: monitor::Error }, + RecvNotify, +} + +type Result<T, E = Error> = std::result::Result<T, E>; + +pub async fn serve(config: Arc<Config>) -> Result<()> { + MONITOR.init().context(MonitorError)?; + + // Set up a channel for receiving thread notifications. + let (monitor_tx, monitor_rx) = mpsc::channel(); + + // Keep track of what threads have been started. + let mut server_thread_ids = HashSet::new(); + + // Set up unbundler. + let serve_dir = Arc::new(RwLock::new(None)); + let unbundler = Arc::new(Unbundler::new(config.clone(), serve_dir.clone())); + + // Set up main server. + let server = Server::new(config.server.clone(), serve_dir); + + let (server_handle, server_thread_handle) = + server + .spawn(monitor_tx.clone()) + .await + .map_err(|err| Error::ServeError { + source: Box::new(err), + })?; + + server_thread_ids.insert(server_thread_handle.thread().id()); + + // Set up optional stats server. + let mut maybe_stats_server_handle = None; + + match &config.stats { + Some(stats_config) => { + let stats_server = StatsServer::new(stats_config.clone(), unbundler.clone()); + + let (stats_server_handle, stats_thread_handle) = stats_server + .spawn(monitor_tx.clone()) + .await + .context(ServeStats)?; + + maybe_stats_server_handle = Some(stats_server_handle); + server_thread_ids.insert(stats_thread_handle.thread().id()); + } + None => {} + } + + let unbundler_thread_handle = thread::handle::spawn(monitor_tx.clone(), move || { + let sys = System::new(); + + let result = sys + .block_on(async move { unbundler.enter().await }) + .context(Unbundle); + + if let Err(e) = result { + log::error!("Unbundler failed: {:?}", e); + } + }); + let unbundler_thread_id = unbundler_thread_handle.thread().id(); + + let monitor_thread_handle = thread::handle::spawn(monitor_tx.clone(), move || { + let mut watched_thread_ids = HashSet::new(); + + watched_thread_ids.insert(unbundler_thread_id); + + for server_thread_id in server_thread_ids { + watched_thread_ids.insert(server_thread_id); + } + + if MONITOR.watch(Some(&watched_thread_ids)).is_err() { + log::error!("Failed to watch threads for panics."); + } + }); + + // Wait for a thread to finish. + loop { + monitor_rx.recv().map_err(|_| Error::RecvNotify)?; + + if Ok(true) == monitor_thread_handle.get_end_handle().has_ended() { + log::info!("Stopping servers due to a panic."); + + break; + } else if Ok(true) == unbundler_thread_handle.get_end_handle().has_ended() { + log::info!("Stopping servers due to unbundler shutdown."); + + break; + } + } + + // Stop server threads. + server_handle.stop(true).await; + + if let Some(stats_server_handle) = maybe_stats_server_handle { + stats_server_handle.stop(true).await; + } + + Ok(()) +} diff --git a/src/config.rs b/src/config.rs index f11d2711a72d32c7f60252b5ebed5dc1877521a3..ef5f1faa091ca5afb5459fc538a14f493e0ef6ab 100644 --- a/src/config.rs +++ b/src/config.rs @@ -2,17 +2,14 @@ use crate::files::directory::{index::IndexStrategy, listing::default_listing_renderer}; use serde_derive::{Deserialize, Serialize}; -use snafu::{ResultExt, Snafu}; +use snafu::Snafu; use std::{ collections::{HashMap, HashSet}, - env, fs, net::SocketAddr, - path::{Path, PathBuf}, + path::PathBuf, sync::Arc, }; -const PKG_NAME: &str = env!("CARGO_PKG_NAME"); - #[derive(Snafu, Debug)] pub enum Error { /// The configuration file could not be found or read. @@ -251,14 +248,8 @@ pub enum IndexStrategyConfig { pub enum CompressionConfig { /// Automatically select encoding based on encoding negotiation. Auto, - /// Use the Brotli algorithm. - Brotli, - /// Use a Zlib structure with the deflate algorithm. - Deflate, /// Don't use any compression. Disabled, - /// Use the Gzip algorithm. - Gzip, } impl From<IndexStrategyConfig> for IndexStrategy { @@ -279,71 +270,19 @@ impl From<IndexStrategyConfig> for IndexStrategy { } } -/// Attempts to read a Config object from the specified path. -/// -/// The configuration file is expected to be a TOML file. -pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Config> { - let path = path.as_ref(); - - info!("Reading config file from {}", path.display()); - - let contents = fs::read_to_string(path).context(OpenConfig { path })?; - - let config = toml::from_str(&contents); - - config.context(DeserializeConfig { path }) -} - -/// Attempts to read a Config object from the specified paths. -pub fn from_paths<P: AsRef<Path>>(paths: Vec<P>) -> Result<Config> { - for path in paths { - if path.as_ref().exists() { - return from_file(path); - } - } - - Err(Error::NoValidPath) -} - -/// Attempts to read a Config object from the current directory. -/// -/// The configuration file is expected to be a TOML file named `config.toml`. -pub fn from_current_dir() -> Result<Config> { - let mut current_path = env::current_dir().context(GetCurrentDir)?; - - current_path.push("config.toml"); - - from_file(¤t_path) -} - -/// Similar to `from_paths`. Uses a default set of paths: -/// -/// - CURRENT_WORKING_DIRECTORY/config.toml -/// - /etc/CRATE/config.toml -pub fn from_default_paths() -> Result<Config> { - let mut current_path = env::current_dir().context(GetCurrentDir)?; - - current_path.push("config.toml"); - - let mut config_path = PathBuf::from("/etc/"); - - config_path.push(PKG_NAME); - config_path.push("config.toml"); - - let paths = vec![current_path, config_path]; - - from_paths(paths) -} - #[cfg(test)] mod tests { - use super::{from_file, BundleConfig, Config, ServerConfig, StatsConfig, UnbundlerConfig}; + use collective::config::from_file; + + use super::{BundleConfig, Config, ServerConfig, StatsConfig, UnbundlerConfig}; use std::path::{Path, PathBuf}; #[test] fn test_from_file() { + let config: Config = from_file(Path::new("config.sample.toml"), None).unwrap(); + assert_eq!( - from_file(&Path::new("config.sample.toml")).unwrap(), + config, Config { stats: Some(StatsConfig { address: "127.0.0.1:8089".parse().unwrap(), diff --git a/src/files/chunked.rs b/src/files/chunked.rs deleted file mode 100644 index f84fdf5014cc0946b2a2174c7a8713a39b500c95..0000000000000000000000000000000000000000 --- a/src/files/chunked.rs +++ /dev/null @@ -1,98 +0,0 @@ -use actix_web::{ - error::{BlockingError, Error, ErrorInternalServerError}, - web, -}; -use bytes::Bytes; -use futures_core::Stream; -use futures_util::future::{FutureExt, LocalBoxFuture}; -use io::Seek; -use std::{ - cmp, - fs::File, - future::Future, - io, - io::Read, - pin::Pin, - task::{Context, Poll}, -}; - -fn handle_error(err: BlockingError<io::Error>) -> Error { - match err { - BlockingError::Error(err) => err.into(), - BlockingError::Canceled => ErrorInternalServerError("Unexpected error"), - } -} - -#[doc(hidden)] -/// A helper created from a `std::fs::File` which reads the file -/// chunk-by-chunk on a `ThreadPool`. -pub struct ChunkedReadFile { - size: u64, - offset: u64, - file: Option<File>, - fut: Option<LocalBoxFuture<'static, Result<(File, Bytes), BlockingError<io::Error>>>>, - counter: u64, -} - -impl ChunkedReadFile { - pub fn new( - size: u64, - offset: u64, - file: Option<File>, - fut: Option<LocalBoxFuture<'static, Result<(File, Bytes), BlockingError<io::Error>>>>, - counter: u64, - ) -> ChunkedReadFile { - ChunkedReadFile { - size, - offset, - file, - fut, - counter, - } - } -} - -impl Stream for ChunkedReadFile { - type Item = Result<Bytes, Error>; - - fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> { - if let Some(ref mut fut) = self.fut { - return match Pin::new(fut).poll(cx) { - Poll::Ready(Ok((file, bytes))) => { - self.fut.take(); - self.file = Some(file); - self.offset += bytes.len() as u64; - self.counter += bytes.len() as u64; - Poll::Ready(Some(Ok(bytes))) - } - Poll::Ready(Err(e)) => Poll::Ready(Some(Err(handle_error(e)))), - Poll::Pending => Poll::Pending, - }; - } - - let size = self.size; - let offset = self.offset; - let counter = self.counter; - - if size == counter { - Poll::Ready(None) - } else { - let mut file = self.file.take().expect("Use after completion"); - self.fut = Some( - web::block(move || { - let max_bytes: usize; - max_bytes = cmp::min(size.saturating_sub(counter), 65_536) as usize; - let mut buf = Vec::with_capacity(max_bytes); - file.seek(io::SeekFrom::Start(offset))?; - let nbytes = file.by_ref().take(max_bytes as u64).read_to_end(&mut buf)?; - if nbytes == 0 { - return Err(io::ErrorKind::UnexpectedEof.into()); - } - Ok((file, Bytes::from(buf))) - }) - .boxed_local(), - ); - self.poll_next(cx) - } - } -} diff --git a/src/files/directory/listing.rs b/src/files/directory/listing.rs index 19d49a970e5bfc501ee4876e684fd57c3561f7a6..2ad0eb0eb882fdb1bc85daab7b0924beb6ef7a3b 100644 --- a/src/files/directory/listing.rs +++ b/src/files/directory/listing.rs @@ -38,7 +38,7 @@ pub fn default_listing_renderer( if dir.is_visible(&entry) { let entry = entry.unwrap(); let p = match entry.path().strip_prefix(&dir.path) { - Ok(p) if cfg!(windows) => base.join(p).to_string_lossy().replace("\\", "/"), + Ok(p) if cfg!(windows) => base.join(p).to_string_lossy().replace('\\', "/"), Ok(p) => base.join(p).to_string_lossy().into_owned(), Err(_) => continue, }; diff --git a/src/files/mod.rs b/src/files/mod.rs index 24a9269faa389664ce23ae30eb4834af6a19d4e9..e426a3f52c7a39c85cb5c02f51c37a4ccc6daff0 100644 --- a/src/files/mod.rs +++ b/src/files/mod.rs @@ -4,28 +4,29 @@ use std::cell::RefCell; use std::path::PathBuf; use std::rc::Rc; -use std::sync::{Arc, RwLock}; +use std::sync::Arc; use actix_service::boxed::{self, BoxServiceFactory}; -use actix_service::{IntoServiceFactory, ServiceFactory}; +use actix_service::{IntoServiceFactory, ServiceFactory, ServiceFactoryExt}; use actix_web::dev::{ AppService, HttpServiceFactory, ResourceDef, ServiceRequest, ServiceResponse, }; use actix_web::error::Error as ActixError; use actix_web::guard::Guard; -use futures_util::future::{ok, FutureExt, LocalBoxFuture}; +use futures_util::future::LocalBoxFuture; use path_context::PathContext; use service::FilesService; +use tokio::sync::RwLock; + +use self::service::FilesServiceInner; -mod chunked; pub mod directory; -pub mod named; +mod named_ext; mod pages; mod path; pub mod path_context; mod pathbuf; -pub mod range; mod service; type HttpNewService = BoxServiceFactory<(), ServiceRequest, ServiceResponse, ActixError, ()>; @@ -37,13 +38,14 @@ type HttpNewService = BoxServiceFactory<(), ServiceRequest, ServiceResponse, Act /// ```rust /// use std::{ /// convert::TryInto, -/// sync::{Arc, RwLock}, +/// sync::Arc, /// }; /// use actix_web::App; /// use espresso::{ /// files::Files, /// config::ServerConfig, /// }; +/// use tokio::sync::RwLock; /// /// let mut server_config = ServerConfig::default(); /// @@ -67,7 +69,8 @@ pub struct Files { path_contexts: Arc<Vec<PathContext>>, redirect_to_slash: bool, default: Rc<RefCell<Option<Rc<HttpNewService>>>>, - guards: Option<Rc<dyn Guard>>, + use_guards: Option<Rc<dyn Guard>>, + guards: Vec<Rc<dyn Guard>>, } impl Clone for Files { @@ -77,9 +80,10 @@ impl Clone for Files { redirect_to_slash: self.redirect_to_slash, default: self.default.clone(), path: self.path.clone(), - guards: self.guards.clone(), + use_guards: self.use_guards.clone(), root_path_context: self.root_path_context.clone(), path_contexts: self.path_contexts.clone(), + guards: self.guards.clone(), } } } @@ -89,7 +93,7 @@ impl Files { /// /// `File` uses `ThreadPool` for blocking filesystem operations. /// By default pool with 5x threads of available cpus is used. - /// Pool size can be changed by setting ACTIX_THREADPOOL environment variable. + /// Pool size can be changed by setting `ACTIX_THREADPOOL` environment variable. #[allow(clippy::rc_buffer)] pub fn new( path: &str, @@ -107,11 +111,12 @@ impl Files { // }; Files { - path: path.to_string(), + path: path.trim_end_matches('/').to_string(), directory, redirect_to_slash: false, default: Rc::new(RefCell::new(None)), - guards: None, + use_guards: None, + guards: vec![], root_path_context, path_contexts, } @@ -125,25 +130,63 @@ impl Files { self } + /// Adds a routing guard. + /// + /// Use this to allow multiple chained file services that respond to strictly different + /// properties of a request. Due to the way routing works, if a guard check returns true and the + /// request starts being handled by the file service, it will not be able to back-out and try + /// the next service, you will simply get a 404 (or 405) error response. + /// + /// To allow `POST` requests to retrieve files, see [`Files::use_guards`]. + /// + /// # Examples + /// ``` + /// use std::{ + /// convert::TryInto, + /// sync::Arc, + /// }; + /// use actix_web::{guard::Header, App}; + /// use espresso::{ + /// files::Files, + /// config::ServerConfig, + /// }; + /// use tokio::sync::RwLock; + /// + /// let mut server_config = ServerConfig::default(); + /// + /// let serve_dir = Arc::new(RwLock::new(Some(".".into()))); + /// let root_path_context = Arc::new((&server_config).try_into().unwrap()); + /// let path_contexts = Arc::new(vec![]); + /// + /// App::new().service( + /// Files::new("/", serve_dir, root_path_context, path_contexts) + /// .guard(Header("Host", "example.com")) + /// ); + /// ``` + pub fn guard<G: Guard + 'static>(mut self, guard: G) -> Self { + self.guards.push(Rc::new(guard)); + self + } + /// Specifies custom guards to use for directory listings and files. /// /// Default behaviour allows GET and HEAD. #[inline] - pub fn use_guards<G: Guard + 'static>(mut self, guards: G) -> Self { - self.guards = Some(Rc::new(guards)); + pub fn method_guard<G: Guard + 'static>(mut self, guards: G) -> Self { + self.use_guards = Some(Rc::new(guards)); self } /// Sets default handler which is used when no matched file could be found. pub fn default_handler<F, U>(mut self, f: F) -> Self where - F: IntoServiceFactory<U>, + F: IntoServiceFactory<U, ServiceRequest>, U: ServiceFactory< - Config = (), - Request = ServiceRequest, - Response = ServiceResponse, - Error = ActixError, - > + 'static, + ServiceRequest, + Config = (), + Response = ServiceResponse, + Error = actix_web::error::Error, + > + 'static, { // create and configure default resource self.default = Rc::new(RefCell::new(Some(Rc::new(boxed::factory( @@ -155,7 +198,19 @@ impl Files { } impl HttpServiceFactory for Files { - fn register(self, config: &mut AppService) { + fn register(mut self, config: &mut AppService) { + let guards = if self.guards.is_empty() { + None + } else { + let guards = std::mem::take(&mut self.guards); + Some( + guards + .into_iter() + .map(|guard| -> Box<dyn Guard> { Box::new(guard) }) + .collect::<Vec<_>>(), + ) + }; + if self.default.borrow().is_none() { *self.default.borrow_mut() = Some(config.default_service()); } @@ -166,12 +221,11 @@ impl HttpServiceFactory for Files { ResourceDef::prefix(&self.path) }; - config.register_service(rdef, None, self, None) + config.register_service(rdef, guards, self, None) } } -impl ServiceFactory for Files { - type Request = ServiceRequest; +impl ServiceFactory<ServiceRequest> for Files { type Response = ServiceResponse; type Error = ActixError; type Config = (); @@ -180,303 +234,69 @@ impl ServiceFactory for Files { type Future = LocalBoxFuture<'static, Result<Self::Service, Self::InitError>>; fn new_service(&self, _: ()) -> Self::Future { - let mut srv = FilesService::new( + let mut inner = FilesServiceInner::new( self.directory.clone(), self.redirect_to_slash, None, self.root_path_context.clone(), self.path_contexts.clone(), - self.guards.clone(), + self.use_guards.clone(), ); if let Some(ref default) = *self.default.borrow() { - default - .new_service(()) - .map(move |result| match result { + let fut = default.new_service(()); + + Box::pin(async { + match fut.await { Ok(default) => { - srv.set_default(Some(default)); - Ok(srv) + inner.default = Some(default); + Ok(FilesService(Rc::new(inner))) } Err(_) => Err(()), - }) - .boxed_local() + } + }) } else { - ok(srv).boxed_local() + Box::pin(async move { Ok(FilesService(Rc::new(inner))) }) } } } #[cfg(test)] mod tests { + use std::collections::{HashMap, HashSet}; + use std::convert::TryInto; use std::fs; - use std::ops::Add; - use std::{ - convert::TryInto, - time::{Duration, SystemTime}, - }; use super::*; use crate::config::{ContentDispositionConfig, IndexStrategyConfig, ServerConfig}; use actix_web::guard; - use actix_web::http::header::{self, ContentDisposition, DispositionParam, DispositionType}; - use actix_web::http::{Method, StatusCode}; - use actix_web::middleware::Compress; + + use actix_web::http::{header, Method, StatusCode}; use actix_web::test::{self, TestRequest}; - use actix_web::{web, App, HttpResponse, Responder}; + use actix_web::App; use bytes::Bytes; - use fs::File; - use named::NamedFile; fn serve_dir<T: Into<PathBuf>>(path: T) -> Arc<RwLock<Option<PathBuf>>> { Arc::new(RwLock::new(Some(path.into()))) } - #[actix_rt::test] - async fn test_if_modified_since_without_if_none_match() { - let file = NamedFile::open("Cargo.toml").unwrap(); - let since = header::HttpDate::from(SystemTime::now().add(Duration::from_secs(60))); - - let req = TestRequest::default() - .header(header::IF_MODIFIED_SINCE, since) - .to_http_request(); - let resp = file.respond_to(&req).await.unwrap(); - assert_eq!(resp.status(), StatusCode::NOT_MODIFIED); - } - - #[actix_rt::test] - async fn test_if_modified_since_with_if_none_match() { - let file = NamedFile::open("Cargo.toml").unwrap(); - let since = header::HttpDate::from(SystemTime::now().add(Duration::from_secs(60))); - - let req = TestRequest::default() - .header(header::IF_NONE_MATCH, "miss_etag") - .header(header::IF_MODIFIED_SINCE, since) - .to_http_request(); - let resp = file.respond_to(&req).await.unwrap(); - assert_ne!(resp.status(), StatusCode::NOT_MODIFIED); - } - - #[actix_rt::test] - async fn test_named_file_text() { - assert!(NamedFile::open("test--").is_err()); - let mut file = NamedFile::open("Cargo.toml").unwrap(); - { - file.file(); - let _f: &File = &file; - } - { - let _f: &mut File = &mut file; - } - - let req = TestRequest::default().to_http_request(); - let resp = file.respond_to(&req).await.unwrap(); - assert_eq!( - resp.headers().get(header::CONTENT_TYPE).unwrap(), - "text/x-toml" - ); - assert_eq!( - resp.headers().get(header::CONTENT_DISPOSITION).unwrap(), - "inline; filename=\"Cargo.toml\"" - ); - } - - #[actix_rt::test] - async fn test_named_file_content_disposition() { - assert!(NamedFile::open("test--").is_err()); - let mut file = NamedFile::open("Cargo.toml").unwrap(); - { - file.file(); - let _f: &File = &file; - } - { - let _f: &mut File = &mut file; - } - - let req = TestRequest::default().to_http_request(); - let resp = file.respond_to(&req).await.unwrap(); - assert_eq!( - resp.headers().get(header::CONTENT_DISPOSITION).unwrap(), - "inline; filename=\"Cargo.toml\"" - ); - - let file = NamedFile::open("Cargo.toml") - .unwrap() - .disable_content_disposition(); - let req = TestRequest::default().to_http_request(); - let resp = file.respond_to(&req).await.unwrap(); - assert!(resp.headers().get(header::CONTENT_DISPOSITION).is_none()); - } - - #[actix_rt::test] - async fn test_named_file_non_ascii_file_name() { - let mut file = NamedFile::from_file(File::open("Cargo.toml").unwrap(), "貨物.toml").unwrap(); - { - file.file(); - let _f: &File = &file; - } - { - let _f: &mut File = &mut file; - } - - let req = TestRequest::default().to_http_request(); - let resp = file.respond_to(&req).await.unwrap(); - assert_eq!( - resp.headers().get(header::CONTENT_TYPE).unwrap(), - "text/x-toml" - ); - assert_eq!( - resp.headers().get(header::CONTENT_DISPOSITION).unwrap(), - "inline; filename=\"貨物.toml\"; filename*=UTF-8''%E8%B2%A8%E7%89%A9.toml" - ); - } - - #[actix_rt::test] - async fn test_named_file_set_content_type() { - let mut file = NamedFile::open("Cargo.toml") - .unwrap() - .set_content_type(mime::TEXT_XML); - { - file.file(); - let _f: &File = &file; - } - { - let _f: &mut File = &mut file; - } - - let req = TestRequest::default().to_http_request(); - let resp = file.respond_to(&req).await.unwrap(); - assert_eq!( - resp.headers().get(header::CONTENT_TYPE).unwrap(), - "text/xml" - ); - assert_eq!( - resp.headers().get(header::CONTENT_DISPOSITION).unwrap(), - "inline; filename=\"Cargo.toml\"" - ); - } - - #[actix_rt::test] - async fn test_named_file_image() { - let mut file = NamedFile::open("tests/test.png").unwrap(); - { - file.file(); - let _f: &File = &file; - } - { - let _f: &mut File = &mut file; - } - - let req = TestRequest::default().to_http_request(); - let resp = file.respond_to(&req).await.unwrap(); - assert_eq!( - resp.headers().get(header::CONTENT_TYPE).unwrap(), - "image/png" - ); - assert_eq!( - resp.headers().get(header::CONTENT_DISPOSITION).unwrap(), - "inline; filename=\"test.png\"" - ); - } - - #[actix_rt::test] - async fn test_named_file_image_attachment() { - let cd = ContentDisposition { - disposition: DispositionType::Attachment, - parameters: vec![DispositionParam::Filename(String::from("test.png"))], - }; - let mut file = NamedFile::open("tests/test.png") - .unwrap() - .set_content_disposition(cd); - { - file.file(); - let _f: &File = &file; - } - { - let _f: &mut File = &mut file; - } - - let req = TestRequest::default().to_http_request(); - let resp = file.respond_to(&req).await.unwrap(); - assert_eq!( - resp.headers().get(header::CONTENT_TYPE).unwrap(), - "image/png" - ); - assert_eq!( - resp.headers().get(header::CONTENT_DISPOSITION).unwrap(), - "attachment; filename=\"test.png\"" - ); - } - - #[actix_rt::test] - async fn test_named_file_binary() { - let mut file = NamedFile::open("tests/test.binary").unwrap(); - { - file.file(); - let _f: &File = &file; - } - { - let _f: &mut File = &mut file; - } - - let req = TestRequest::default().to_http_request(); - let resp = file.respond_to(&req).await.unwrap(); - assert_eq!( - resp.headers().get(header::CONTENT_TYPE).unwrap(), - "application/octet-stream" - ); - assert_eq!( - resp.headers().get(header::CONTENT_DISPOSITION).unwrap(), - "attachment; filename=\"test.binary\"" - ); - } - - #[actix_rt::test] - async fn test_named_file_status_code_text() { - let mut file = NamedFile::open("Cargo.toml") - .unwrap() - .set_status_code(StatusCode::NOT_FOUND); - { - file.file(); - let _f: &File = &file; - } - { - let _f: &mut File = &mut file; - } - - let req = TestRequest::default().to_http_request(); - let resp = file.respond_to(&req).await.unwrap(); - assert_eq!( - resp.headers().get(header::CONTENT_TYPE).unwrap(), - "text/x-toml" - ); - assert_eq!( - resp.headers().get(header::CONTENT_DISPOSITION).unwrap(), - "inline; filename=\"Cargo.toml\"" - ); - assert_eq!(resp.status(), StatusCode::NOT_FOUND); - } - #[actix_rt::test] async fn test_mime_override() { - let mut server_config = ServerConfig::default(); - - server_config.index_strategy = Some(IndexStrategyConfig::IndexFiles { - filenames: ["Cargo.toml".to_owned()].iter().cloned().collect(), - }); - server_config.mime_disposition = Some( - vec![( + let server_config = ServerConfig { + index_strategy: Some(IndexStrategyConfig::IndexFiles { + filenames: HashSet::from(["Cargo.toml".to_owned()]), + }), + mime_disposition: Some(HashMap::from([( "text/x-toml".to_owned(), ContentDispositionConfig::Attachment, - )] - .iter() - .cloned() - .collect(), - ); + )])), + ..ServerConfig::default() + }; let root_path_context = Arc::new((&server_config).try_into().unwrap()); let path_contexts = Arc::new(vec![]); - let mut srv = test::init_service(App::new().service(Files::new( + let srv = test::init_service(App::new().service(Files::new( "/", serve_dir("."), root_path_context, @@ -485,7 +305,7 @@ mod tests { .await; let request = TestRequest::get().uri("/").to_request(); - let response = test::call_service(&mut srv, request).await; + let response = test::call_service(&srv, request).await; assert_eq!(response.status(), StatusCode::OK); let content_disposition = response @@ -500,16 +320,17 @@ mod tests { #[actix_rt::test] async fn test_named_file_ranges_status_code() { - let mut server_config = ServerConfig::default(); - - server_config.index_strategy = Some(IndexStrategyConfig::IndexFiles { - filenames: ["Cargo.toml".to_owned()].iter().cloned().collect(), - }); + let server_config = ServerConfig { + index_strategy: Some(IndexStrategyConfig::IndexFiles { + filenames: ["Cargo.toml".to_owned()].iter().cloned().collect(), + }), + ..ServerConfig::default() + }; let root_path_context = Arc::new((&server_config).try_into().unwrap()); let path_contexts = Arc::new(vec![]); - let mut srv = test::init_service(App::new().service(Files::new( + let srv = test::init_service(App::new().service(Files::new( "/test", serve_dir("."), root_path_context, @@ -520,24 +341,24 @@ mod tests { // Valid range header let request = TestRequest::get() .uri("/t%65st/Cargo.toml") - .header(header::RANGE, "bytes=10-20") + .append_header((header::RANGE, "bytes=10-20")) .to_request(); - let response = test::call_service(&mut srv, request).await; + let response = test::call_service(&srv, request).await; assert_eq!(response.status(), StatusCode::PARTIAL_CONTENT); // Invalid range header let request = TestRequest::get() .uri("/t%65st/Cargo.toml") - .header(header::RANGE, "bytes=1-0") + .append_header((header::RANGE, "bytes=1-0")) .to_request(); - let response = test::call_service(&mut srv, request).await; + let response = test::call_service(&srv, request).await; assert_eq!(response.status(), StatusCode::RANGE_NOT_SATISFIABLE); } #[actix_rt::test] async fn test_named_file_content_range_headers() { - let srv = test::start(|| { + let srv = actix_test::start(|| { let root_path_context = Arc::new((&ServerConfig::default()).try_into().unwrap()); let path_contexts = Arc::new(vec![]); @@ -552,7 +373,7 @@ mod tests { // Valid range header let response = srv .get("/tests/test.binary") - .header(header::RANGE, "bytes=10-20") + .append_header((header::RANGE, "bytes=10-20")) .send() .await .unwrap(); @@ -562,7 +383,7 @@ mod tests { // Invalid range header let response = srv .get("/tests/test.binary") - .header(header::RANGE, "bytes=10-5") + .append_header((header::RANGE, "bytes=10-5")) .send() .await .unwrap(); @@ -572,7 +393,7 @@ mod tests { #[actix_rt::test] async fn test_named_file_content_length_headers() { - let srv = test::start(|| { + let srv = actix_test::start(|| { let root_path_context = Arc::new((&ServerConfig::default()).try_into().unwrap()); let path_contexts = Arc::new(vec![]); @@ -587,7 +408,7 @@ mod tests { // Valid range header let response = srv .get("/tests/test.binary") - .header(header::RANGE, "bytes=10-20") + .append_header((header::RANGE, "bytes=10-20")) .send() .await .unwrap(); @@ -597,7 +418,7 @@ mod tests { // Valid range header, starting from 0 let response = srv .get("/tests/test.binary") - .header(header::RANGE, "bytes=0-20") + .append_header((header::RANGE, "bytes=0-20")) .send() .await .unwrap(); @@ -616,12 +437,13 @@ mod tests { // Check file contents let bytes = response.body().await.unwrap(); let data = Bytes::from(fs::read("tests/test.binary").unwrap()); + assert_eq!(bytes, data); } #[actix_rt::test] async fn test_head_content_length_headers() { - let srv = test::start(|| { + let srv = actix_test::start(|| { let root_path_context = Arc::new((&ServerConfig::default()).try_into().unwrap()); let path_contexts = Arc::new(vec![]); @@ -647,16 +469,17 @@ mod tests { #[actix_rt::test] async fn test_static_files_with_spaces() { - let mut server_config = ServerConfig::default(); - - server_config.index_strategy = Some(IndexStrategyConfig::IndexFiles { - filenames: ["Cargo.toml".to_owned()].iter().cloned().collect(), - }); + let server_config = ServerConfig { + index_strategy: Some(IndexStrategyConfig::IndexFiles { + filenames: ["Cargo.toml".to_owned()].iter().cloned().collect(), + }), + ..ServerConfig::default() + }; let root_path_context = Arc::new((&server_config).try_into().unwrap()); let path_contexts = Arc::new(vec![]); - let mut srv = test::init_service(App::new().service(Files::new( + let srv = test::init_service(App::new().service(Files::new( "/", serve_dir("."), root_path_context, @@ -666,7 +489,7 @@ mod tests { let request = TestRequest::get() .uri("/tests/test%20space.binary") .to_request(); - let response = test::call_service(&mut srv, request).await; + let response = test::call_service(&srv, request).await; assert_eq!(response.status(), StatusCode::OK); let bytes = test::read_body(response).await; @@ -679,7 +502,7 @@ mod tests { let root_path_context = Arc::new((&ServerConfig::default()).try_into().unwrap()); let path_contexts = Arc::new(vec![]); - let mut srv = test::init_service(App::new().default_service(Files::new( + let srv = test::init_service(App::new().default_service(Files::new( "/", serve_dir("."), root_path_context, @@ -692,13 +515,13 @@ mod tests { .method(Method::POST) .to_request(); - let resp = test::call_service(&mut srv, req).await; + let resp = test::call_service(&srv, req).await; assert_eq!(resp.status(), StatusCode::METHOD_NOT_ALLOWED); let root_path_context = Arc::new((&ServerConfig::default()).try_into().unwrap()); let path_contexts = Arc::new(vec![]); - let mut srv = test::init_service(App::new().default_service(Files::new( + let srv = test::init_service(App::new().default_service(Files::new( "/", serve_dir("."), root_path_context, @@ -709,7 +532,7 @@ mod tests { .method(Method::PUT) .uri("/Cargo.toml") .to_request(); - let resp = test::call_service(&mut srv, req).await; + let resp = test::call_service(&srv, req).await; assert_eq!(resp.status(), StatusCode::METHOD_NOT_ALLOWED); } @@ -718,8 +541,8 @@ mod tests { let root_path_context = Arc::new((&ServerConfig::default()).try_into().unwrap()); let path_contexts = Arc::new(vec![]); - let mut srv = test::init_service(App::new().service( - Files::new("/", serve_dir("."), root_path_context, path_contexts).use_guards(guard::Post()), + let srv = test::init_service(App::new().service( + Files::new("/", serve_dir("."), root_path_context, path_contexts).method_guard(guard::Post()), )) .await; @@ -728,76 +551,72 @@ mod tests { .method(Method::POST) .to_request(); - let resp = test::call_service(&mut srv, req).await; + let resp = test::call_service(&srv, req).await; assert_eq!(resp.status(), StatusCode::OK); } #[actix_rt::test] - async fn test_named_file_content_encoding() { - let mut srv = test::init_service(App::new().wrap(Compress::default()).service( - web::resource("/").to(|| async { - NamedFile::open("Cargo.toml") - .unwrap() - .set_content_encoding(header::ContentEncoding::Identity) - }), - )) - .await; + async fn test_static_files() { + let server_config = ServerConfig { + index_strategy: Some(IndexStrategyConfig::AlwaysShowListing), + ..ServerConfig::default() + }; - let request = TestRequest::get() - .uri("/") - .header(header::ACCEPT_ENCODING, "gzip") - .to_request(); - let res = test::call_service(&mut srv, request).await; - assert_eq!(res.status(), StatusCode::OK); - assert!(!res.headers().contains_key(header::CONTENT_ENCODING)); - } + let root_path_context = Arc::new((&server_config).try_into().unwrap()); + let path_contexts = Arc::new(vec![]); - #[actix_rt::test] - async fn test_named_file_content_encoding_gzip() { - let mut srv = test::init_service(App::new().wrap(Compress::default()).service( - web::resource("/").to(|| async { - NamedFile::open("Cargo.toml") - .unwrap() - .set_content_encoding(header::ContentEncoding::Gzip) - }), - )) + let srv = test::init_service(App::new().service(Files::new( + "/", + serve_dir("."), + root_path_context, + path_contexts, + ))) .await; + let req = TestRequest::with_uri("/tests/test.png").to_request(); - let request = TestRequest::get() - .uri("/") - .header(header::ACCEPT_ENCODING, "gzip") - .to_request(); - let res = test::call_service(&mut srv, request).await; - assert_eq!(res.status(), StatusCode::OK); - assert_eq!( - res - .headers() - .get(header::CONTENT_ENCODING) - .unwrap() - .to_str() - .unwrap(), - "gzip" - ); + let resp = test::call_service(&srv, req).await; + assert_eq!(resp.status(), StatusCode::OK); + + let bytes = test::read_body(resp).await; + + let data = Bytes::from(fs::read("tests/test.png").unwrap()); + assert_eq!(bytes, data); } #[actix_rt::test] - async fn test_named_file_allowed_method() { - let req = TestRequest::default().method(Method::GET).to_http_request(); - let file = NamedFile::open("Cargo.toml").unwrap(); - let resp = file.respond_to(&req).await.unwrap(); + async fn test_static_files_percent_encoded() { + let server_config = ServerConfig { + index_strategy: Some(IndexStrategyConfig::AlwaysShowListing), + ..ServerConfig::default() + }; + + let root_path_context = Arc::new((&server_config).try_into().unwrap()); + let path_contexts = Arc::new(vec![]); + + let srv = test::init_service(App::new().service(Files::new( + "/", + serve_dir("."), + root_path_context, + path_contexts, + ))) + .await; + let req = TestRequest::with_uri("/%43argo.toml").to_request(); + + let resp = test::call_service(&srv, req).await; assert_eq!(resp.status(), StatusCode::OK); } #[actix_rt::test] - async fn test_static_files() { - let mut server_config = ServerConfig::default(); - - server_config.index_strategy = Some(IndexStrategyConfig::AlwaysShowListing); + async fn test_static_files_with_missing_path() { + let server_config = ServerConfig { + index_strategy: Some(IndexStrategyConfig::AlwaysShowListing), + ..ServerConfig::default() + }; let root_path_context = Arc::new((&server_config).try_into().unwrap()); let path_contexts = Arc::new(vec![]); - let mut srv = test::init_service(App::new().service(Files::new( + let srv = test::init_service(App::new().service(Files::new( "/", serve_dir("."), root_path_context, @@ -806,14 +625,16 @@ mod tests { .await; let req = TestRequest::with_uri("/missing").to_request(); - let resp = test::call_service(&mut srv, req).await; + let resp = test::call_service(&srv, req).await; assert_eq!(resp.status(), StatusCode::NOT_FOUND); + } - // Without index strategy. + #[actix_rt::test] + async fn test_static_files_without_index_strategy() { let root_path_context = Arc::new((&ServerConfig::default()).try_into().unwrap()); let path_contexts = Arc::new(vec![]); - let mut srv = test::init_service(App::new().service(Files::new( + let srv = test::init_service(App::new().service(Files::new( "/", serve_dir("."), root_path_context, @@ -822,24 +643,31 @@ mod tests { .await; let req = TestRequest::default().to_request(); - let resp = test::call_service(&mut srv, req).await; + let resp = test::call_service(&srv, req).await; assert_eq!(resp.status(), StatusCode::NOT_FOUND); + } - // With default renderer. - server_config.index_strategy = Some(IndexStrategyConfig::AlwaysShowListing); + #[actix_rt::test] + async fn test_static_files_with_listing_index_strategy() { + let server_config = ServerConfig { + index_strategy: Some(IndexStrategyConfig::AlwaysShowListing), + ..ServerConfig::default() + }; let root_path_context = Arc::new((&server_config).try_into().unwrap()); let path_contexts = Arc::new(vec![]); - let mut srv = test::init_service(App::new().service(Files::new( + let srv = test::init_service(App::new().default_service(Files::new( "/", serve_dir("."), root_path_context, path_contexts, ))) .await; + let req = TestRequest::with_uri("/tests").to_request(); - let resp = test::call_service(&mut srv, req).await; + let resp = test::call_service(&srv, req).await; + assert_eq!(resp.status(), StatusCode::OK); assert_eq!( resp.headers().get(header::CONTENT_TYPE).unwrap(), "text/html; charset=utf-8" @@ -851,26 +679,18 @@ mod tests { #[actix_rt::test] async fn test_redirect_to_slash_directory() { - let mut server_config = ServerConfig::default(); - - server_config.index_strategy = Some(IndexStrategyConfig::IndexFiles { - filenames: ["test.png".to_owned()].iter().cloned().collect(), - }); + let server_config = ServerConfig { + index_strategy: Some(IndexStrategyConfig::IndexFiles { + filenames: ["test.png".to_owned()].iter().cloned().collect(), + }), + ..ServerConfig::default() + }; - let root_path_context = Arc::new((&server_config).try_into().unwrap()); + let root_path_context: Arc<PathContext> = Arc::new((&server_config).try_into().unwrap()); let path_contexts = Arc::new(vec![]); - // should not redirect if no index - // let mut srv = test::init_service( - // App::new().service(Files::new("/", serve_dir(".")).redirect_to_slash_directory()), - // ) - // .await; - // let req = TestRequest::with_uri("/tests").to_request(); - // let resp = test::call_service(&mut srv, req).await; - // assert_eq!(resp.status(), StatusCode::NOT_FOUND); - // should redirect if index present - let mut srv = test::init_service( + let srv = test::init_service( App::new().service( Files::new("/", serve_dir("."), root_path_context, path_contexts) .redirect_to_slash_directory(), @@ -878,12 +698,12 @@ mod tests { ) .await; let req = TestRequest::with_uri("/tests").to_request(); - let resp = test::call_service(&mut srv, req).await; + let resp = test::call_service(&srv, req).await; assert_eq!(resp.status(), StatusCode::FOUND); // should not redirect if the path is wrong let req = TestRequest::with_uri("/not_existing").to_request(); - let resp = test::call_service(&mut srv, req).await; + let resp = test::call_service(&srv, req).await; assert_eq!(resp.status(), StatusCode::NOT_FOUND); } @@ -904,138 +724,4 @@ mod tests { path_contexts, ); } - - #[actix_rt::test] - async fn test_default_handler_file_missing() { - let root_path_context = Arc::new((&ServerConfig::default()).try_into().unwrap()); - let path_contexts = Arc::new(vec![]); - - let mut st = Files::new("/", serve_dir("."), root_path_context, path_contexts) - .default_handler(|req: ServiceRequest| { - ok(req.into_response(HttpResponse::Ok().body("default content"))) - }) - .new_service(()) - .await - .unwrap(); - let req = TestRequest::with_uri("/missing").to_srv_request(); - - let resp = test::call_service(&mut st, req).await; - assert_eq!(resp.status(), StatusCode::OK); - let bytes = test::read_body(resp).await; - assert_eq!(bytes, Bytes::from_static(b"default content")); - } - - // #[actix_rt::test] - // async fn test_serve_index() { - // let st = Files::new(".").index_file("test.binary"); - // let req = TestRequest::default().uri("/tests").finish(); - - // let resp = st.handle(&req).respond_to(&req).unwrap(); - // let resp = resp.as_msg(); - // assert_eq!(resp.status(), StatusCode::OK); - // assert_eq!( - // resp.headers() - // .get(header::CONTENT_TYPE) - // .expect("content type"), - // "application/octet-stream" - // ); - // assert_eq!( - // resp.headers() - // .get(header::CONTENT_DISPOSITION) - // .expect("content disposition"), - // "attachment; filename=\"test.binary\"" - // ); - - // let req = TestRequest::default().uri("/tests/").finish(); - // let resp = st.handle(&req).respond_to(&req).unwrap(); - // let resp = resp.as_msg(); - // assert_eq!(resp.status(), StatusCode::OK); - // assert_eq!( - // resp.headers().get(header::CONTENT_TYPE).unwrap(), - // "application/octet-stream" - // ); - // assert_eq!( - // resp.headers().get(header::CONTENT_DISPOSITION).unwrap(), - // "attachment; filename=\"test.binary\"" - // ); - - // // nonexistent index file - // let req = TestRequest::default().uri("/tests/unknown").finish(); - // let resp = st.handle(&req).respond_to(&req).unwrap(); - // let resp = resp.as_msg(); - // assert_eq!(resp.status(), StatusCode::NOT_FOUND); - - // let req = TestRequest::default().uri("/tests/unknown/").finish(); - // let resp = st.handle(&req).respond_to(&req).unwrap(); - // let resp = resp.as_msg(); - // assert_eq!(resp.status(), StatusCode::NOT_FOUND); - // } - - // #[actix_rt::test] - // async fn test_serve_index_nested() { - // let st = Files::new(".").index_file("mod.rs"); - // let req = TestRequest::default().uri("/src/client").finish(); - // let resp = st.handle(&req).respond_to(&req).unwrap(); - // let resp = resp.as_msg(); - // assert_eq!(resp.status(), StatusCode::OK); - // assert_eq!( - // resp.headers().get(header::CONTENT_TYPE).unwrap(), - // "text/x-rust" - // ); - // assert_eq!( - // resp.headers().get(header::CONTENT_DISPOSITION).unwrap(), - // "inline; filename=\"mod.rs\"" - // ); - // } - - // #[actix_rt::test] - // fn integration_serve_index() { - // let mut srv = test::TestServer::with_factory(|| { - // App::new().handler( - // "test", - // Files::new(".").index_file("Cargo.toml"), - // ) - // }); - - // let request = srv.get().uri(srv.url("/test")).finish().unwrap(); - // let response = srv.execute(request.send()).unwrap(); - // assert_eq!(response.status(), StatusCode::OK); - // let bytes = srv.execute(response.body()).unwrap(); - // let data = Bytes::from(fs::read("Cargo.toml").unwrap()); - // assert_eq!(bytes, data); - - // let request = srv.get().uri(srv.url("/test/")).finish().unwrap(); - // let response = srv.execute(request.send()).unwrap(); - // assert_eq!(response.status(), StatusCode::OK); - // let bytes = srv.execute(response.body()).unwrap(); - // let data = Bytes::from(fs::read("Cargo.toml").unwrap()); - // assert_eq!(bytes, data); - - // // nonexistent index file - // let request = srv.get().uri(srv.url("/test/unknown")).finish().unwrap(); - // let response = srv.execute(request.send()).unwrap(); - // assert_eq!(response.status(), StatusCode::NOT_FOUND); - - // let request = srv.get().uri(srv.url("/test/unknown/")).finish().unwrap(); - // let response = srv.execute(request.send()).unwrap(); - // assert_eq!(response.status(), StatusCode::NOT_FOUND); - // } - - // #[actix_rt::test] - // fn integration_percent_encoded() { - // let mut srv = test::TestServer::with_factory(|| { - // App::new().handler( - // "test", - // Files::new(".").index_file("Cargo.toml"), - // ) - // }); - - // let request = srv - // .get() - // .uri(srv.url("/test/%43argo.toml")) - // .finish() - // .unwrap(); - // let response = srv.execute(request.send()).unwrap(); - // assert_eq!(response.status(), StatusCode::OK); - // } } diff --git a/src/files/named.rs b/src/files/named.rs deleted file mode 100644 index 4f9fa8921f44535fc9631b3eb3f2ed3918c643ac..0000000000000000000000000000000000000000 --- a/src/files/named.rs +++ /dev/null @@ -1,451 +0,0 @@ -use std::fs::{File, Metadata}; -use std::io; -use std::ops::{Deref, DerefMut}; -use std::path::{Path, PathBuf}; -use std::time::{SystemTime, UNIX_EPOCH}; - -#[cfg(unix)] -use std::os::unix::fs::MetadataExt; - -use bitflags::bitflags; -use mime_guess::from_path; - -use actix_http::body::SizedStream; -use actix_web::dev::BodyEncoding; -use actix_web::http::header::{ - self, Charset, ContentDisposition, DispositionParam, DispositionType, ExtendedValue, -}; -use actix_web::http::{ContentEncoding, StatusCode}; -use actix_web::{Error, HttpMessage, HttpRequest, HttpResponse, Responder}; -use futures_util::future::{ready, Ready}; - -use super::{chunked::ChunkedReadFile, path_context::PathContext, range::HttpRange}; - -bitflags! { - pub(crate) struct Flags: u8 { - const ETAG = 0b0000_0001; - const LAST_MD = 0b0000_0010; - const CONTENT_DISPOSITION = 0b0000_0100; - } -} - -impl Default for Flags { - fn default() -> Self { - Flags::all() - } -} - -/// A file with an associated name. -#[derive(Debug)] -pub struct NamedFile { - path: PathBuf, - file: File, - modified: Option<SystemTime>, - pub(crate) md: Metadata, - pub(crate) flags: Flags, - pub(crate) status_code: StatusCode, - pub(crate) content_type: mime::Mime, - pub(crate) content_disposition: header::ContentDisposition, - pub(crate) encoding: Option<ContentEncoding>, -} - -impl NamedFile { - /// Creates an instance from a previously opened file. - /// - /// The given `path` need not exist and is only used to determine the `ContentType` and - /// `ContentDisposition` headers. - /// - /// # Examples - /// - /// ```rust - /// use espresso::files::named::NamedFile; - /// use std::io::{self, Write}; - /// use std::env; - /// use std::fs::File; - /// - /// fn main() -> io::Result<()> { - /// let mut file = File::create("foo.txt")?; - /// file.write_all(b"Hello, world!")?; - /// let named_file = NamedFile::from_file(file, "bar.txt")?; - /// # std::fs::remove_file("foo.txt"); - /// Ok(()) - /// } - /// ``` - pub fn from_file<P: AsRef<Path>>(file: File, path: P) -> io::Result<NamedFile> { - let path = path.as_ref().to_path_buf(); - - // Get the name of the file and use it to construct default Content-Type - // and Content-Disposition values - let (content_type, content_disposition) = { - let filename = match path.file_name() { - Some(name) => name.to_string_lossy(), - None => { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "Provided path has no filename", - )); - } - }; - - let ct = from_path(&path).first_or_octet_stream(); - let disposition = match ct.type_() { - mime::IMAGE | mime::TEXT | mime::VIDEO => DispositionType::Inline, - _ => DispositionType::Attachment, - }; - let mut parameters = vec![DispositionParam::Filename(String::from(filename.as_ref()))]; - if !filename.is_ascii() { - parameters.push(DispositionParam::FilenameExt(ExtendedValue { - charset: Charset::Ext(String::from("UTF-8")), - language_tag: None, - value: filename.into_owned().into_bytes(), - })) - } - let cd = ContentDisposition { - disposition, - parameters, - }; - (ct, cd) - }; - - let md = file.metadata()?; - let modified = md.modified().ok(); - let encoding = None; - Ok(NamedFile { - path, - file, - content_type, - content_disposition, - md, - modified, - encoding, - status_code: StatusCode::OK, - flags: Flags::default(), - }) - } - - /// Attempts to open a file in read-only mode. - /// - /// # Examples - /// - /// ```rust - /// use espresso::files::named::NamedFile; - /// - /// let file = NamedFile::open("foo.txt"); - /// ``` - pub fn open<P: AsRef<Path>>(path: P) -> io::Result<NamedFile> { - Self::from_file(File::open(&path)?, path) - } - - /// Returns reference to the underlying `File` object. - #[inline] - pub fn file(&self) -> &File { - &self.file - } - - /// Retrieve the path of this file. - /// - /// # Examples - /// - /// ```rust - /// # use std::io; - /// use espresso::files::named::NamedFile; - /// - /// # fn path() -> io::Result<()> { - /// let file = NamedFile::open("test.txt")?; - /// assert_eq!(file.path().as_os_str(), "foo.txt"); - /// # Ok(()) - /// # } - /// ``` - #[inline] - pub fn path(&self) -> &Path { - self.path.as_path() - } - - /// Set response **Status Code** - pub fn set_status_code(mut self, status: StatusCode) -> Self { - self.status_code = status; - self - } - - /// Set the MIME Content-Type for serving this file. By default - /// the Content-Type is inferred from the filename extension. - #[inline] - pub fn set_content_type(mut self, mime_type: mime::Mime) -> Self { - self.content_type = mime_type; - self - } - - /// Set the Content-Disposition for serving this file. This allows - /// changing the inline/attachment disposition as well as the filename - /// sent to the peer. By default the disposition is `inline` for text, - /// image, and video content types, and `attachment` otherwise, and - /// the filename is taken from the path provided in the `open` method - /// after converting it to UTF-8 using. - /// [to_string_lossy](https://doc.rust-lang.org/std/ffi/struct.OsStr.html#method.to_string_lossy). - #[inline] - pub fn set_content_disposition(mut self, cd: header::ContentDisposition) -> Self { - self.content_disposition = cd; - self.flags.insert(Flags::CONTENT_DISPOSITION); - self - } - - /// Disable `Content-Disposition` header. - /// - /// By default Content-Disposition` header is enabled. - #[inline] - pub fn disable_content_disposition(mut self) -> Self { - self.flags.remove(Flags::CONTENT_DISPOSITION); - self - } - - /// Set content encoding for serving this file - #[inline] - pub fn set_content_encoding(mut self, enc: ContentEncoding) -> Self { - self.encoding = Some(enc); - self - } - - #[inline] - ///Specifies whether to use ETag or not. - /// - ///Default is true. - pub fn use_etag(mut self, value: bool) -> Self { - self.flags.set(Flags::ETAG, value); - self - } - - #[inline] - ///Specifies whether to use Last-Modified or not. - /// - ///Default is true. - pub fn use_last_modified(mut self, value: bool) -> Self { - self.flags.set(Flags::LAST_MD, value); - self - } - - pub fn with_path_context(mut self, path_context: &PathContext) -> Self { - if let Some(mime_disposition) = path_context.get_mime_disposition() { - if let Some(new_disposition) = mime_disposition.get(&self.content_type) { - self.content_disposition.disposition = new_disposition.clone(); - } - } - - self - .use_etag(path_context.get_use_etag_or_default()) - .use_last_modified(path_context.get_use_last_modifiedor_default()) - } - - pub(crate) fn etag(&self) -> Option<header::EntityTag> { - // This etag format is similar to Apache's. - self.modified.as_ref().map(|mtime| { - let ino = { - #[cfg(unix)] - { - self.md.ino() - } - #[cfg(not(unix))] - { - 0 - } - }; - - let dur = mtime - .duration_since(UNIX_EPOCH) - .expect("modification time must be after epoch"); - header::EntityTag::strong(format!( - "{:x}:{:x}:{:x}:{:x}", - ino, - self.md.len(), - dur.as_secs(), - dur.subsec_nanos() - )) - }) - } - - pub(crate) fn last_modified(&self) -> Option<header::HttpDate> { - self.modified.map(|mtime| mtime.into()) - } - - pub fn into_response(self, req: &HttpRequest) -> Result<HttpResponse, Error> { - if self.status_code != StatusCode::OK { - let mut resp = HttpResponse::build(self.status_code); - resp - .set(header::ContentType(self.content_type.clone())) - .if_true(self.flags.contains(Flags::CONTENT_DISPOSITION), |res| { - res.header( - header::CONTENT_DISPOSITION, - self.content_disposition.to_string(), - ); - }); - if let Some(current_encoding) = self.encoding { - resp.encoding(current_encoding); - } - let reader = ChunkedReadFile::new(self.md.len(), 0, Some(self.file), None, 0); - return Ok(resp.streaming(reader)); - } - - let etag = if self.flags.contains(Flags::ETAG) { - self.etag() - } else { - None - }; - let last_modified = if self.flags.contains(Flags::LAST_MD) { - self.last_modified() - } else { - None - }; - - // check preconditions - let precondition_failed = if !any_match(etag.as_ref(), req) { - true - } else if let (Some(ref m), Some(header::IfUnmodifiedSince(ref since))) = - (last_modified, req.get_header()) - { - let t1: SystemTime = m.clone().into(); - let t2: SystemTime = since.clone().into(); - match (t1.duration_since(UNIX_EPOCH), t2.duration_since(UNIX_EPOCH)) { - (Ok(t1), Ok(t2)) => t1 > t2, - _ => false, - } - } else { - false - }; - - // check last modified - let not_modified = if !none_match(etag.as_ref(), req) { - true - } else if req.headers().contains_key(&header::IF_NONE_MATCH) { - false - } else if let (Some(ref m), Some(header::IfModifiedSince(ref since))) = - (last_modified, req.get_header()) - { - let t1: SystemTime = m.clone().into(); - let t2: SystemTime = since.clone().into(); - match (t1.duration_since(UNIX_EPOCH), t2.duration_since(UNIX_EPOCH)) { - (Ok(t1), Ok(t2)) => t1 <= t2, - _ => false, - } - } else { - false - }; - - let mut resp = HttpResponse::build(self.status_code); - resp - .set(header::ContentType(self.content_type.clone())) - .if_true(self.flags.contains(Flags::CONTENT_DISPOSITION), |res| { - res.header( - header::CONTENT_DISPOSITION, - self.content_disposition.to_string(), - ); - }); - // default compressing - if let Some(current_encoding) = self.encoding { - resp.encoding(current_encoding); - } - - resp - .if_some(last_modified, |lm, resp| { - resp.set(header::LastModified(lm)); - }) - .if_some(etag, |etag, resp| { - resp.set(header::ETag(etag)); - }); - - resp.header(header::ACCEPT_RANGES, "bytes"); - - let mut length = self.md.len(); - let mut offset = 0; - - // check for range header - if let Some(ranges) = req.headers().get(&header::RANGE) { - if let Ok(rangesheader) = ranges.to_str() { - if let Ok(rangesvec) = HttpRange::parse(rangesheader, length) { - length = rangesvec[0].length; - offset = rangesvec[0].start; - resp.encoding(ContentEncoding::Identity); - resp.header( - header::CONTENT_RANGE, - format!("bytes {}-{}/{}", offset, offset + length - 1, self.md.len()), - ); - } else { - resp.header(header::CONTENT_RANGE, format!("bytes */{}", length)); - return Ok(resp.status(StatusCode::RANGE_NOT_SATISFIABLE).finish()); - }; - } else { - return Ok(resp.status(StatusCode::BAD_REQUEST).finish()); - }; - }; - - if precondition_failed { - return Ok(resp.status(StatusCode::PRECONDITION_FAILED).finish()); - } else if not_modified { - return Ok(resp.status(StatusCode::NOT_MODIFIED).finish()); - } - - let reader = ChunkedReadFile::new(length, offset, Some(self.file), None, 0); - - if offset != 0 || length != self.md.len() { - resp.status(StatusCode::PARTIAL_CONTENT); - } - - Ok(resp.body(SizedStream::new(length, reader))) - } -} - -impl Deref for NamedFile { - type Target = File; - - fn deref(&self) -> &File { - &self.file - } -} - -impl DerefMut for NamedFile { - fn deref_mut(&mut self) -> &mut File { - &mut self.file - } -} - -impl Responder for NamedFile { - type Error = Error; - type Future = Ready<Result<HttpResponse, Error>>; - - fn respond_to(self, req: &HttpRequest) -> Self::Future { - ready(self.into_response(req)) - } -} - -/// Returns true if `req` has no `If-Match` header or one which matches `etag`. -fn any_match(etag: Option<&header::EntityTag>, req: &HttpRequest) -> bool { - match req.get_header::<header::IfMatch>() { - None | Some(header::IfMatch::Any) => true, - Some(header::IfMatch::Items(ref items)) => { - if let Some(some_etag) = etag { - for item in items { - if item.strong_eq(some_etag) { - return true; - } - } - } - false - } - } -} - -/// Returns true if `req` doesn't have an `If-None-Match` header matching `req`. -fn none_match(etag: Option<&header::EntityTag>, req: &HttpRequest) -> bool { - match req.get_header::<header::IfNoneMatch>() { - Some(header::IfNoneMatch::Any) => false, - Some(header::IfNoneMatch::Items(ref items)) => { - if let Some(some_etag) = etag { - for item in items { - if item.weak_eq(some_etag) { - return false; - } - } - } - true - } - None => true, - } -} diff --git a/src/files/named_ext.rs b/src/files/named_ext.rs new file mode 100644 index 0000000000000000000000000000000000000000..7492ab133970f475eeeee42139bce0d6bed794ed --- /dev/null +++ b/src/files/named_ext.rs @@ -0,0 +1,29 @@ +use actix_files::NamedFile; +use actix_web::http::header::ContentDisposition; + +use super::path_context::PathContext; + +pub trait NamedFileExt { + fn with_path_context(self, path_context: &PathContext) -> Self; +} + +impl NamedFileExt for NamedFile { + fn with_path_context(self, path_context: &PathContext) -> Self { + let mut this = self; + + if let Some(mime_disposition) = path_context.get_mime_disposition() { + if let Some(new_disposition_type) = mime_disposition.get(this.content_type()) { + let original_parameters = this.content_disposition().parameters.clone(); + + this = this.set_content_disposition(ContentDisposition { + disposition: new_disposition_type.clone(), + parameters: original_parameters, + }); + } + } + + this + .use_etag(path_context.get_use_etag_or_default()) + .use_last_modified(path_context.get_use_last_modifiedor_default()) + } +} diff --git a/src/files/pages.rs b/src/files/pages.rs index 34027e544b47af170a0763707abc1a0eb8238e61..d1b46065822a296a0c571ad7f44dd502d9c3a529 100644 --- a/src/files/pages.rs +++ b/src/files/pages.rs @@ -62,17 +62,19 @@ pub fn render_server_page( title: &str, subtitle: &str, content: &str, -) -> Result<String, handlebars::TemplateRenderError> { +) -> Result<String, Box<handlebars::TemplateRenderError>> { let reg = Handlebars::new(); - reg.render_template( - PAGE_TEMPLATE, - &json!({ - "title": title, - "subtitle": subtitle, - "content": content, - "pkg_name": PKG_NAME, - "pkg_version": PKG_VERSION, - }), - ) + reg + .render_template( + PAGE_TEMPLATE, + &json!({ + "title": title, + "subtitle": subtitle, + "content": content, + "pkg_name": PKG_NAME, + "pkg_version": PKG_VERSION, + }), + ) + .map_err(Box::new) } diff --git a/src/files/path.rs b/src/files/path.rs index e0fb0b734ee49cad88f9a26226e0a099da0221e7..c5a8d20a68e163287d830af235180731186036b7 100644 --- a/src/files/path.rs +++ b/src/files/path.rs @@ -36,7 +36,7 @@ pub fn resolve_path_within_tree( .ok_or(Error::NoParent)? }; - Ok(new_path.canonicalize().context(Canonicalize { + new_path.canonicalize().context(Canonicalize { path: new_path.clone(), - })?) + }) } diff --git a/src/files/path_context.rs b/src/files/path_context.rs index 00744bd3f8a2bb3d4014bbf0bb8f6aba6b223955..05c3c64b69f14596a600238236e04196ce4b49d6 100644 --- a/src/files/path_context.rs +++ b/src/files/path_context.rs @@ -1,9 +1,6 @@ use super::directory::index::IndexStrategy; use crate::config::{ContentDispositionConfig, PathConfig, PathMatcherConfig, ServerConfig}; -use actix_http::http::{ - header::{self, DispositionType}, - HeaderMap, -}; +use actix_web::http::header::{self, DispositionType, HeaderMap}; use regex::Regex; use snafu::{ResultExt, Snafu}; use std::{ @@ -146,7 +143,7 @@ impl PathContext { if let Some(headers) = &self.headers { for (header_name, header_value) in headers.iter() { if header_map.contains_key(header_name) { - warn!( + log::warn!( "Unable to replace header '{}' since it was already set.", header_name ); @@ -258,62 +255,41 @@ mod tests { #[test] fn test_static_path_matcher() { - assert_eq!( - PathMatcher::Static { - path: "hello/world.png".into(), - } - .matches_path(&"hello/world.png"), - true - ); + assert!(PathMatcher::Static { + path: "hello/world.png".into(), + } + .matches_path("hello/world.png"),); - assert_eq!( - PathMatcher::Static { - path: "hello/world.tar.gz".into(), - } - .matches_path(&"hello/world.png"), - false - ); + assert!(!PathMatcher::Static { + path: "hello/world.tar.gz".into(), + } + .matches_path("hello/world.png"),); } #[test] fn test_prefix_path_matcher() { - assert_eq!( - PathMatcher::Prefix { - prefix: "hello/".into(), - } - .matches_path(&"hello/world.png"), - true - ); + assert!(PathMatcher::Prefix { + prefix: "hello/".into(), + } + .matches_path("hello/world.png"),); - assert_eq!( - PathMatcher::Prefix { - prefix: "hello/bye".into(), - } - .matches_path(&"hello/world.png"), - false - ); + assert!(!PathMatcher::Prefix { + prefix: "hello/bye".into(), + } + .matches_path("hello/world.png"),); } #[test] fn test_regex_path_matcher() { - assert_eq!( - Regex::new(r"\.png$").unwrap().is_match("hello/world.png"), - true, - ); - - assert_eq!( - Regex::new(r"\.(js|css|png|jpg|jpeg|gif|ico)$") - .unwrap() - .is_match("hello/world.png"), - true, - ); - - assert_eq!( - PathMatcher::Regex { - regex: Regex::new(r"\.png$").unwrap(), - } - .matches_path(&"hello/world.tar.gz"), - false - ); + assert!(Regex::new(r"\.png$").unwrap().is_match("hello/world.png"),); + + assert!(Regex::new(r"\.(js|css|png|jpg|jpeg|gif|ico)$") + .unwrap() + .is_match("hello/world.png"),); + + assert!(!PathMatcher::Regex { + regex: Regex::new(r"\.png$").unwrap(), + } + .matches_path("hello/world.tar.gz"),); } } diff --git a/src/files/pathbuf.rs b/src/files/pathbuf.rs index f2b119b57ac2b738d6134f7220fc098e2ed8ea75..429834e829da701d1a816cb1bb250313a2144fc7 100644 --- a/src/files/pathbuf.rs +++ b/src/files/pathbuf.rs @@ -4,11 +4,13 @@ use actix_web::{ FromRequest, HttpRequest, ResponseError, }; use futures_util::future::{ready, Ready}; +use percent_encoding::percent_decode_str; use snafu::Snafu; use std::{ convert::{TryFrom, TryInto}, ops::Deref, - path::{Path, PathBuf}, + path::{Component, Path, PathBuf}, + str::FromStr, }; #[derive(Snafu, Debug, PartialEq)] @@ -22,6 +24,12 @@ pub enum Error { /// The segment ended with the wrapped invalid character. #[snafu(display("The segment ended with the wrapped invalid character."))] BadEnd { char: char }, + /// The path is not a valid UTF-8 string after percent-decoding + #[snafu(display("The path is not a valid UTF-8 string after percent-decoding."))] + NotValidUtf8, + /// The path has invalid or unexpected components. + #[snafu(display("The path has invalid or unexpected components."))] + InvalidComponents, } /// Return `BadRequest` for `Error`. @@ -37,12 +45,23 @@ type Result<T, E = Error> = std::result::Result<T, E>; pub struct UriPathBuf(PathBuf); impl UriPathBuf { - pub fn new(path: &str) -> Result<Self> { - let mut buf = PathBuf::new(); + pub fn new(raw_path: &str) -> Result<Self> { + let mut path = PathBuf::new(); - for segment in path.split('/') { + let mut segment_count = raw_path.matches('/').count() + 1; + + let decoded_path = percent_decode_str(raw_path) + .decode_utf8() + .map_err(|_| Error::NotValidUtf8)?; + + if segment_count != decoded_path.matches('/').count() + 1 { + return Err(Error::BadChar { char: '/' }); + } + + for segment in decoded_path.split('/') { if segment == ".." { - buf.pop(); + segment_count -= 1; + path.pop(); } else if segment.starts_with('.') { return Err(Error::BadStart { char: '.' }); } else if segment.starts_with('*') { @@ -54,25 +73,41 @@ impl UriPathBuf { } else if segment.ends_with('<') { return Err(Error::BadEnd { char: '<' }); } else if segment.is_empty() { + segment_count -= 1; continue; } else if cfg!(windows) && segment.contains('\\') { return Err(Error::BadChar { char: '\\' }); + } else if cfg!(windows) && segment.contains(':') { + return Err(Error::BadChar { char: ':' }); } else { - buf.push(segment) + path.push(segment) + } + } + + for (i, component) in path.components().enumerate() { + if !matches!(component, Component::Normal(_)) || i >= segment_count { + return Err(Error::InvalidComponents); } } - Ok(UriPathBuf(buf)) + Ok(UriPathBuf(path)) + } +} + +impl FromStr for UriPathBuf { + type Err = Error; + + fn from_str(raw_path: &str) -> Result<Self, Self::Err> { + Self::new(raw_path) } } impl FromRequest for UriPathBuf { type Error = Error; type Future = Ready<Result<Self, Self::Error>>; - type Config = (); - fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future { - ready(req.try_into()) + fn from_request(request: &HttpRequest, _: &mut Payload) -> Self::Future { + ready(request.try_into()) } } @@ -80,7 +115,7 @@ impl TryFrom<&HttpRequest> for UriPathBuf { type Error = Error; fn try_from(request: &HttpRequest) -> Result<Self, Error> { - UriPathBuf::new(request.match_info().path()) + request.match_info().unprocessed().parse() } } @@ -88,13 +123,13 @@ impl TryFrom<&ServiceRequest> for UriPathBuf { type Error = Error; fn try_from(request: &ServiceRequest) -> Result<Self, Error> { - UriPathBuf::new(request.match_info().path()) + request.match_info().unprocessed().parse() } } impl From<UriPathBuf> for PathBuf { - fn from(buf: UriPathBuf) -> PathBuf { - buf.0 + fn from(path: UriPathBuf) -> PathBuf { + path.0 } } @@ -111,33 +146,31 @@ mod tests { #[actix_rt::test] async fn test_path_buf() { - assert_eq!( - UriPathBuf::new("/test/.tt").map(|t| t.0), - Err(Error::BadStart { char: '.' }) - ); - assert_eq!( - UriPathBuf::new("/test/*tt").map(|t| t.0), - Err(Error::BadStart { char: '*' }) - ); - assert_eq!( - UriPathBuf::new("/test/tt:").map(|t| t.0), - Err(Error::BadEnd { char: ':' }) - ); - assert_eq!( - UriPathBuf::new("/test/tt<").map(|t| t.0), - Err(Error::BadEnd { char: '<' }) - ); - assert_eq!( - UriPathBuf::new("/test/tt>").map(|t| t.0), - Err(Error::BadEnd { char: '>' }) - ); - assert_eq!( - UriPathBuf::new("/seg1/seg2/").unwrap().0, - PathBuf::from_iter(vec!["seg1", "seg2"]) - ); - assert_eq!( - UriPathBuf::new("/seg1/../seg2/").unwrap().0, - PathBuf::from_iter(vec!["seg2"]) - ); + let cases: &[(&str, Result<PathBuf, Error>)] = &[ + ("/test/.tt", Err(Error::BadStart { char: '.' })), + ("/test/*tt", Err(Error::BadStart { char: '*' })), + ("/test/tt:", Err(Error::BadEnd { char: ':' })), + ("/test/tt<", Err(Error::BadEnd { char: '<' })), + ("/test/tt>", Err(Error::BadEnd { char: '>' })), + ("hello%20world", Ok(PathBuf::from_iter(vec!["hello world"]))), + ( + "/testing%21/hello%20world", + Ok(PathBuf::from_iter(vec!["testing!", "hello world"])), + ), + ("/seg1/seg2/", Ok(PathBuf::from_iter(vec!["seg1", "seg2"]))), + ("/seg1/../seg2/", Ok(PathBuf::from_iter(vec!["seg2"]))), + ( + "/../../../../../dev/null", + Ok(PathBuf::from_iter(vec!["dev/null"])), + ), + ( + "/../../../..%2F../dev/null", + Err(Error::BadChar { char: '/' }), + ), + ]; + + for (input, expected) in cases { + assert_eq!(&UriPathBuf::new(input).map(|t| t.0), expected) + } } } diff --git a/src/files/range.rs b/src/files/range.rs deleted file mode 100644 index b4cd265f55249f9b32403de45e1b676372d1322c..0000000000000000000000000000000000000000 --- a/src/files/range.rs +++ /dev/null @@ -1,406 +0,0 @@ -use snafu::Snafu; - -#[derive(Snafu, Debug, PartialEq)] -pub enum Error { - /// The segment started with the wrapped invalid character. - #[snafu(display("The range has an invalid prefix"))] - InvalidPrefix { - header: String, - }, - InvalidRangeComponent, - InvalidRange { - start: i64, - end: i64, - }, - InvalidRanges, -} - -/// HTTP Range header representation. -#[derive(Debug, Clone, Copy)] -pub struct HttpRange { - /// Start of range. - pub start: u64, - - /// Length of range. - pub length: u64, -} - -type Result<T, E = Error> = std::result::Result<T, E>; - -const PREFIX: &str = "bytes="; -const PREFIX_LEN: usize = 6; - -impl HttpRange { - /// Parses Range HTTP header string as per RFC 2616. - /// - /// `header` is HTTP Range header (e.g. `bytes=bytes=0-9`). - /// `size` is full size of response (file). - pub fn parse(header: &str, size: u64) -> Result<Vec<HttpRange>> { - if header.is_empty() { - return Ok(Vec::new()); - } else if !header.starts_with(PREFIX) { - return Err(Error::InvalidPrefix { - header: header.to_owned(), - }); - } - - let size_sig = size as i64; - let mut no_overlap = false; - - let all_ranges: Vec<Option<HttpRange>> = header[PREFIX_LEN..] - .split(',') - .map(|x| x.trim()) - .filter(|x| !x.is_empty()) - .map(|ra| { - let mut start_end_iter = ra.split('-'); - - let start_str = start_end_iter - .next() - .ok_or(Error::InvalidRangeComponent)? - .trim(); - let end_str = start_end_iter - .next() - .ok_or(Error::InvalidRangeComponent)? - .trim(); - - if start_str.is_empty() { - // If no start is specified, end specifies the - // range start relative to the end of the file. - let mut length: i64 = end_str.parse().map_err(|_| Error::InvalidRangeComponent)?; - - if length > size_sig { - length = size_sig; - } - - Ok(Some(HttpRange { - start: (size_sig - length) as u64, - length: length as u64, - })) - } else { - let start: i64 = start_str - .parse() - .map_err(|_| Error::InvalidRangeComponent)?; - - if start < 0 { - return Err(Error::InvalidRangeComponent); - } - if start >= size_sig { - no_overlap = true; - return Ok(None); - } - - let length = if end_str.is_empty() { - // If no end is specified, range extends to end of the file. - size_sig - start - } else { - let mut end: i64 = end_str.parse().map_err(|_| Error::InvalidRangeComponent)?; - - if start > end { - return Err(Error::InvalidRange { start, end }); - } - - if end >= size_sig { - end = size_sig - 1; - } - - end - start + 1 - }; - - Ok(Some(HttpRange { - start: start as u64, - length: length as u64, - })) - } - }) - .collect::<Result<Vec<Option<HttpRange>>, Error>>()?; - - let ranges: Vec<HttpRange> = all_ranges.into_iter().filter_map(|x| x).collect(); - - if no_overlap && ranges.is_empty() { - return Err(Error::InvalidRanges); - } - - Ok(ranges) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - struct T(&'static str, u64, Vec<HttpRange>); - - #[test] - fn test_parse() { - let tests = vec![ - T("", 0, vec![]), - T("", 1000, vec![]), - T("foo", 0, vec![]), - T("bytes=", 0, vec![]), - T("bytes=7", 10, vec![]), - T("bytes= 7 ", 10, vec![]), - T("bytes=1-", 0, vec![]), - T("bytes=5-4", 10, vec![]), - T("bytes=0-2,5-4", 10, vec![]), - T("bytes=2-5,4-3", 10, vec![]), - T("bytes=--5,4--3", 10, vec![]), - T("bytes=A-", 10, vec![]), - T("bytes=A- ", 10, vec![]), - T("bytes=A-Z", 10, vec![]), - T("bytes= -Z", 10, vec![]), - T("bytes=5-Z", 10, vec![]), - T("bytes=Ran-dom, garbage", 10, vec![]), - T("bytes=0x01-0x02", 10, vec![]), - T("bytes= ", 10, vec![]), - T("bytes= , , , ", 10, vec![]), - T( - "bytes=0-9", - 10, - vec![HttpRange { - start: 0, - length: 10, - }], - ), - T( - "bytes=0-", - 10, - vec![HttpRange { - start: 0, - length: 10, - }], - ), - T( - "bytes=5-", - 10, - vec![HttpRange { - start: 5, - length: 5, - }], - ), - T( - "bytes=0-20", - 10, - vec![HttpRange { - start: 0, - length: 10, - }], - ), - T( - "bytes=15-,0-5", - 10, - vec![HttpRange { - start: 0, - length: 6, - }], - ), - T( - "bytes=1-2,5-", - 10, - vec![ - HttpRange { - start: 1, - length: 2, - }, - HttpRange { - start: 5, - length: 5, - }, - ], - ), - T( - "bytes=-2 , 7-", - 11, - vec![ - HttpRange { - start: 9, - length: 2, - }, - HttpRange { - start: 7, - length: 4, - }, - ], - ), - T( - "bytes=0-0 ,2-2, 7-", - 11, - vec![ - HttpRange { - start: 0, - length: 1, - }, - HttpRange { - start: 2, - length: 1, - }, - HttpRange { - start: 7, - length: 4, - }, - ], - ), - T( - "bytes=-5", - 10, - vec![HttpRange { - start: 5, - length: 5, - }], - ), - T( - "bytes=-15", - 10, - vec![HttpRange { - start: 0, - length: 10, - }], - ), - T( - "bytes=0-499", - 10000, - vec![HttpRange { - start: 0, - length: 500, - }], - ), - T( - "bytes=500-999", - 10000, - vec![HttpRange { - start: 500, - length: 500, - }], - ), - T( - "bytes=-500", - 10000, - vec![HttpRange { - start: 9500, - length: 500, - }], - ), - T( - "bytes=9500-", - 10000, - vec![HttpRange { - start: 9500, - length: 500, - }], - ), - T( - "bytes=0-0,-1", - 10000, - vec![ - HttpRange { - start: 0, - length: 1, - }, - HttpRange { - start: 9999, - length: 1, - }, - ], - ), - T( - "bytes=500-600,601-999", - 10000, - vec![ - HttpRange { - start: 500, - length: 101, - }, - HttpRange { - start: 601, - length: 399, - }, - ], - ), - T( - "bytes=500-700,601-999", - 10000, - vec![ - HttpRange { - start: 500, - length: 201, - }, - HttpRange { - start: 601, - length: 399, - }, - ], - ), - // Match Apache laxity: - T( - "bytes= 1 -2 , 4- 5, 7 - 8 , ,,", - 11, - vec![ - HttpRange { - start: 1, - length: 2, - }, - HttpRange { - start: 4, - length: 2, - }, - HttpRange { - start: 7, - length: 2, - }, - ], - ), - ]; - - for t in tests { - let header = t.0; - let size = t.1; - let expected = t.2; - - let res = HttpRange::parse(header, size); - - if res.is_err() { - if expected.is_empty() { - continue; - } else { - assert!( - false, - "parse({}, {}) returned error {:?}", - header, - size, - res.unwrap_err() - ); - } - } - - let got = res.unwrap(); - - if got.len() != expected.len() { - assert!( - false, - "len(parseRange({}, {})) = {}, want {}", - header, - size, - got.len(), - expected.len() - ); - continue; - } - - for i in 0..expected.len() { - if got[i].start != expected[i].start { - assert!( - false, - "parseRange({}, {})[{}].start = {}, want {}", - header, size, i, got[i].start, expected[i].start - ) - } - if got[i].length != expected[i].length { - assert!( - false, - "parseRange({}, {})[{}].length = {}, want {}", - header, size, i, got[i].length, expected[i].length - ) - } - } - } - } -} diff --git a/src/files/service.rs b/src/files/service.rs index 263e8497d0c24ef2091b7a2b4066a17699384035..33ae2d0406a7982ef51bed99f66ab24641fc3646 100644 --- a/src/files/service.rs +++ b/src/files/service.rs @@ -1,30 +1,35 @@ use super::{ directory::{index::IndexStrategy, Directory}, - named::NamedFile, + named_ext::NamedFileExt, pages::render_server_page, path::resolve_path_within_tree, path_context::PathContext, pathbuf::UriPathBuf, }; -use actix_service::{boxed::BoxService, Service}; +use actix_files::NamedFile; +use actix_service::boxed::BoxService; use actix_web::{ - dev::{ServiceRequest, ServiceResponse}, + body::BoxBody, + dev::{Service, ServiceRequest, ServiceResponse}, error::Error as ActixError, guard::Guard, http::{header, Method, StatusCode}, HttpResponse, ResponseError, }; -use futures_util::future::{err, ok, Either, LocalBoxFuture, Ready}; +use async_recursion::async_recursion; +use futures_util::future::LocalBoxFuture; use snafu::ResultExt; use snafu::Snafu; use std::{ convert::TryInto, io, + ops::Deref, path::{Path, PathBuf}, rc::Rc, - sync::{Arc, RwLock}, + sync::Arc, task::{Context, Poll}, }; +use tokio::sync::RwLock; /// Errors which can occur when serving static files. #[derive(Snafu, Debug)] @@ -44,7 +49,7 @@ pub enum Error { ServerDirReadLockFail, #[snafu(display("Unable to find or open the specified file."))] - OpenFileError { + OpenFile { source: io::Error, }, @@ -78,7 +83,7 @@ impl ResponseError for Error { fn error_response(&self) -> HttpResponse { match self { Error::MethodNotAllowed { .. } => HttpResponse::MethodNotAllowed() - .header(header::CONTENT_TYPE, "text/plain") + .append_header((header::CONTENT_TYPE, "text/plain")) .body("Request did not meet this resource's requirements."), _ => HttpResponse::new(StatusCode::NOT_FOUND), } @@ -93,20 +98,27 @@ struct RequestContext { path_context: PathContext, } -pub struct FilesService { +#[derive(Clone)] +pub struct FilesService(pub(crate) Rc<FilesServiceInner>); + +impl Deref for FilesService { + type Target = FilesServiceInner; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +pub struct FilesServiceInner { directory: Arc<RwLock<Option<PathBuf>>>, redirect_to_slash: bool, - default: Option<HttpService>, + pub(crate) default: Option<HttpService>, root_path_context: Arc<PathContext>, - #[allow(clippy::rc_buffer)] path_contexts: Arc<Vec<PathContext>>, - // FIXME: Should re-visit later. - #[allow(clippy::redundant_allocation)] guards: Option<Rc<dyn Guard>>, } -impl FilesService { - #[allow(clippy::rc_buffer)] +impl FilesServiceInner { pub(crate) fn new( directory: Arc<RwLock<Option<PathBuf>>>, redirect_to_slash: bool, @@ -114,8 +126,8 @@ impl FilesService { root_path_context: Arc<PathContext>, path_contexts: Arc<Vec<PathContext>>, guards: Option<Rc<dyn Guard>>, - ) -> FilesService { - FilesService { + ) -> FilesServiceInner { + FilesServiceInner { directory, redirect_to_slash, default, @@ -129,63 +141,60 @@ impl FilesService { self.default = default } - fn handle_err( - &mut self, + #[async_recursion(?Send)] + async fn handle_err( + &self, e: Error, req: ServiceRequest, request_context: Option<RequestContext>, - ) -> Either< - Ready<Result<ServiceResponse, ActixError>>, - LocalBoxFuture<'static, Result<ServiceResponse, ActixError>>, - > { + ) -> Result<ServiceResponse, ActixError> { log::debug!("Files: Failed to handle {}: {}", req.path(), e); - if let Some(ref mut default) = self.default { - info!("Using default handler"); + if let Some(ref default) = self.default { + log::info!("Using default handler"); - Either::Right(default.call(req)) + default.call(req).await } else { let error_response = e.error_response(); match error_response.status() { - StatusCode::NOT_FOUND => self.handle_not_found_err(req, request_context), - _ => Either::Left(ok(req.into_response(error_response))), + StatusCode::NOT_FOUND => self.handle_not_found_err(req, request_context).await, + _ => Ok(req.into_response(error_response)), } } } - fn handle_early_err( - &mut self, + async fn get_request_context_for_request( + &self, + req: &ServiceRequest, + ) -> Result<RequestContext, Error> { + let serve_dir = self.get_serve_dir().await?; + let path_from_request: UriPathBuf = req.try_into().context(BuildUriPath)?; + + Ok(RequestContext { + path: serve_dir.join(&path_from_request), + serve_dir, + path_context: self.get_path_context(&path_from_request), + }) + } + + async fn handle_early_err( + &self, e: Error, req: ServiceRequest, - ) -> Either< - Ready<Result<ServiceResponse, ActixError>>, - LocalBoxFuture<'static, Result<ServiceResponse, ActixError>>, - > { - let request_context: Result<RequestContext, Error> = try { - let serve_dir = self.get_serve_dir()?; - let path_from_request: UriPathBuf = (&req).try_into().context(BuildUriPath)?; - - RequestContext { - path: serve_dir.join(&path_from_request), - serve_dir, - path_context: self.get_path_context(&path_from_request), - } - }; + ) -> Result<ServiceResponse, ActixError> { + let request_context = self.get_request_context_for_request(&req).await; - self.handle_err(e, req, request_context.ok()) + self.handle_err(e, req, request_context.ok()).await } - fn handle_not_found_err( - &mut self, + async fn handle_not_found_err( + &self, req: ServiceRequest, request_context: Option<RequestContext>, - ) -> Either< - Ready<Result<ServiceResponse, ActixError>>, - LocalBoxFuture<'static, Result<ServiceResponse, ActixError>>, - > { + ) -> Result<ServiceResponse, ActixError> { if let Some(request_context) = request_context { - debug!( + log::debug!( "Using custom error path: {:?}", request_context.path_context.get_not_found_path() ); @@ -198,55 +207,57 @@ impl FilesService { not_found_path, ) { Ok(path) => { - debug!("Custom error page: {:?}", path); - - return self.handle_file( - req, - RequestContext { - path, - ..request_context - }, - false, - ); + log::debug!("Custom error page: {:?}", path); + + return self + .handle_file( + req, + RequestContext { + path, + ..request_context + }, + false, + ) + .await; } - Err(err) => error!("Error resolving custom error page: {}", err), + Err(err) => log::error!("Error resolving custom error page: {}", err), } } } match render_server_page("404", "Not Found", "") { - Ok(body) => Either::Left(ok( + Ok(body) => Ok( req.into_response( HttpResponse::NotFound() .content_type("text/html; charset=utf-8") - .body(&body), + .body(body), ), - )), - Err(_) => self.handle_err(Error::ServeCustomNotFoundPath, req, None), + ), + Err(_) => { + self + .handle_err(Error::ServeCustomNotFoundPath, req, None) + .await + } } } - fn handle_dir( - &mut self, + async fn handle_dir( + &self, req: ServiceRequest, request_context: RequestContext, - ) -> Either< - Ready<Result<ServiceResponse, ActixError>>, - LocalBoxFuture<'static, Result<ServiceResponse, ActixError>>, - > { + ) -> Result<ServiceResponse, ActixError> { // Check if we should redirect the client to a normalized path ending in a // slash. if self.redirect_to_slash && !req.path().ends_with('/') { let redirect_to = format!("{}/", req.path()); - return Either::Left(ok( + return Ok( req.into_response( HttpResponse::Found() - .header(header::LOCATION, redirect_to) - .body("") - .into_body(), + .append_header((header::LOCATION, redirect_to)) + .body(""), ), - )); + ); } let RequestContext { @@ -261,11 +272,14 @@ impl FilesService { let (http_req, payload) = req.into_parts(); match renderer(&dir, &http_req) { - Ok(resp) => Either::Left(ok(resp)), - Err(source) => match ServiceRequest::from_parts(http_req, payload) { - Ok(req) => self.handle_err(Error::RenderListing { source }, req, Some(request_context)), - Err(_) => Either::Left(err(Error::ReconstructRequest.into())), - }, + Ok(resp) => Ok(resp), + Err(source) => { + let req = ServiceRequest::from_parts(http_req, payload); + + self + .handle_err(Error::RenderListing { source }, req, Some(request_context)) + .await + } } } IndexStrategy::ShowListingWhenAbsent { @@ -276,15 +290,17 @@ impl FilesService { let path = path.join(filename); if path.exists() { - return self.handle_file( - req, - RequestContext { - serve_dir: request_context.serve_dir, - path, - path_context: request_context.path_context, - }, - true, - ); + return self + .handle_file( + req, + RequestContext { + serve_dir: request_context.serve_dir, + path, + path_context: request_context.path_context, + }, + true, + ) + .await; } } @@ -292,11 +308,14 @@ impl FilesService { let (http_req, payload) = req.into_parts(); match renderer(&dir, &http_req) { - Ok(resp) => Either::Left(ok(resp)), - Err(source) => match ServiceRequest::from_parts(http_req, payload) { - Ok(req) => self.handle_err(Error::RenderListing { source }, req, Some(request_context)), - Err(_) => Either::Left(err(Error::ReconstructRequest.into())), - }, + Ok(resp) => Ok(resp), + Err(source) => { + let req = ServiceRequest::from_parts(http_req, payload); + + self + .handle_err(Error::RenderListing { source }, req, Some(request_context)) + .await + } } } IndexStrategy::IndexFiles { filenames } => { @@ -304,80 +323,71 @@ impl FilesService { let path = path.join(filename); if path.exists() { - return self.handle_file( - req, - RequestContext { - path, - ..request_context - }, - true, - ); + return self + .handle_file( + req, + RequestContext { + path, + ..request_context + }, + true, + ) + .await; } } - self.handle_err(Error::IsDirectory, req, Some(request_context)) + self + .handle_err(Error::IsDirectory, req, Some(request_context)) + .await + } + IndexStrategy::NoIndex => { + self + .handle_err(Error::IsDirectory, req, Some(request_context)) + .await } - IndexStrategy::NoIndex => self.handle_err(Error::IsDirectory, req, Some(request_context)), }; } - fn handle_file( - &mut self, + async fn handle_file( + &self, req: ServiceRequest, request_context: RequestContext, preserve_request_context: bool, - ) -> Either< - Ready<Result<ServiceResponse, ActixError>>, - LocalBoxFuture<'static, Result<ServiceResponse, ActixError>>, - > { + ) -> Result<ServiceResponse, ActixError> { let RequestContext { path, path_context, .. } = &request_context; - match NamedFile::open(path).context(OpenFileError) { + match NamedFile::open(path).context(OpenFile) { Ok(named_file) => { - let (http_req, payload) = req.into_parts(); + let (http_req, _payload) = req.into_parts(); - match named_file - .with_path_context(&path_context) - .into_response(&http_req) - { - Ok(mut response) => { - path_context.append_headers_to_map(response.headers_mut()); + let mut response = named_file + .with_path_context(path_context) + .into_response(&http_req); - Either::Left(ok(ServiceResponse::new(http_req, response))) - } - Err(source) => match ServiceRequest::from_parts(http_req, payload) { - Ok(req) => self.handle_err( - Error::BuildFileResponse { source }, - req, - if preserve_request_context { - Some(request_context) - } else { - None - }, - ), - Err(_) => Either::Left(err(Error::ReconstructRequest.into())), - }, - } + path_context.append_headers_to_map(response.headers_mut()); + + Ok(ServiceResponse::new(http_req, response)) + } + Err(e) => { + self + .handle_err( + e, + req, + if preserve_request_context { + Some(request_context) + } else { + None + }, + ) + .await } - Err(e) => self.handle_err( - e, - req, - if preserve_request_context { - Some(request_context) - } else { - None - }, - ), } } - fn get_serve_dir(&self) -> Result<PathBuf, Error> { - let maybe_dir = match self.directory.read().map(|dir| dir.clone()) { - Ok(maybe_dir) => maybe_dir, - Err(_) => return Err(Error::ServerDirReadLockFail), - }; + async fn get_serve_dir(&self) -> Result<PathBuf, Error> { + let maybe_dir = self.directory.read().await.clone(); match maybe_dir { Some(dir) => Ok(dir), @@ -385,11 +395,11 @@ impl FilesService { } } - fn get_canonical_path_from_request( + async fn get_canonical_path_from_request( &self, req: &ServiceRequest, ) -> Result<(PathBuf, PathBuf, UriPathBuf), Error> { - let serve_dir = self.get_serve_dir()?; + let serve_dir = self.get_serve_dir().await?; let path_from_request: UriPathBuf = req.try_into().context(BuildUriPath)?; @@ -407,7 +417,7 @@ impl FilesService { for path_context in self.path_contexts.as_ref() { if path_context.matches_path(path_from_request) { - debug!( + log::debug!( "Using matched PathContext. Matcher: {:?}, Path: {}", path_context, path_from_request.display() @@ -416,7 +426,7 @@ impl FilesService { } } - debug!( + log::debug!( "Using root PathContext. Path: {}", path_from_request.display() ); @@ -424,54 +434,55 @@ impl FilesService { } } -impl Service for FilesService { - type Request = ServiceRequest; - type Response = ServiceResponse; +impl Service<ServiceRequest> for FilesService { + type Response = ServiceResponse<BoxBody>; type Error = ActixError; - type Future = Either< - Ready<Result<Self::Response, Self::Error>>, - LocalBoxFuture<'static, Result<Self::Response, Self::Error>>, - >; + type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>; - fn poll_ready(&mut self, _: &mut Context) -> Poll<Result<(), Self::Error>> { + fn poll_ready(&self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { Poll::Ready(Ok(())) } - fn call(&mut self, req: ServiceRequest) -> Self::Future { - // Check user-defined guards or fallback to default method check. + fn call(&self, req: ServiceRequest) -> Self::Future { let is_method_valid = if let Some(guard) = &self.guards { - (**guard).check(req.head()) + (**guard).check(&req.guard_ctx()) } else { matches!(*req.method(), Method::HEAD | Method::GET) }; - if !is_method_valid { - return self.handle_early_err( - Error::MethodNotAllowed { - method: req.method().clone(), - }, - req, - ); - } + let this = self.clone(); + + Box::pin(async move { + if !is_method_valid { + return this + .handle_early_err( + Error::MethodNotAllowed { + method: req.method().clone(), + }, + req, + ) + .await; + } - let maybe_path = self.get_canonical_path_from_request(&req); - let (path, serve_dir, path_from_request) = match maybe_path { - Ok(path) => path, - Err(e) => return self.handle_early_err(e, req), - }; + let maybe_path = this.get_canonical_path_from_request(&req).await; + let (path, serve_dir, path_from_request) = match maybe_path { + Ok(path) => path, + Err(e) => return this.handle_early_err(e, req).await, + }; - let path_context = self.get_path_context(&path_from_request); + let path_context = this.get_path_context(&path_from_request); - let request_context = RequestContext { - path, - serve_dir, - path_context, - }; + let request_context = RequestContext { + path, + serve_dir, + path_context, + }; - if request_context.path.is_dir() { - self.handle_dir(req, request_context) - } else { - self.handle_file(req, request_context, true) - } + if request_context.path.is_dir() { + this.handle_dir(req, request_context).await + } else { + this.handle_file(req, request_context, true).await + } + }) } } diff --git a/src/lib.rs b/src/lib.rs index f42fe19a42acc31fac6f972cf5c43edd119e124a..467ae835a0c931604ec287e85bdc786b84b873fc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,12 +1,10 @@ #![feature(try_blocks, proc_macro_hygiene)] - -#[macro_use] -extern crate log; +#![deny(rust_2018_idioms, nonstandard_style)] +#![deny(clippy::doc_markdown, clippy::match_bool, clippy::match_same_arms)] +#![warn(future_incompatible)] pub mod bundle; pub mod config; pub mod files; -pub mod monitor; pub mod server; pub mod stats; -pub mod thread; diff --git a/src/main.rs b/src/main.rs index 4c00275f3e60e2fe75685a3a6d47e7d74881c1c0..6cb2c7f87f1fba76377cf291007ddc00262108ed 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,114 +1,33 @@ #![feature(try_blocks, proc_macro_hygiene)] +#![deny(rust_2018_idioms, nonstandard_style)] +#![deny(clippy::doc_markdown, clippy::match_bool, clippy::match_same_arms)] +#![warn(future_incompatible)] -#[macro_use] -extern crate log; - -use actix::prelude::*; -use clap::Clap; -use collective::cli::{AppOpts, ConfigurableAppOpts}; -use lazy_static::lazy_static; -use monitor::Monitor; -use server::Server; -use snafu::{ResultExt, Snafu}; -use stats::StatsServer; -use std::{ - collections::HashSet, - net::SocketAddr, - path::PathBuf, - sync::{mpsc, Arc, RwLock}, +use cli::{ + args::{Opts, SubCommand}, + bundle, serve, }; +use collective::cli::ConfigurableAppOpts; +use espresso::bundle::packager; +use snafu::{ResultExt, Snafu}; +use std::sync::Arc; -pub mod bundle; -pub mod config; -pub mod files; -pub mod monitor; -pub mod server; -pub mod stats; -pub mod thread; - -lazy_static! { - static ref MONITOR: Monitor = Monitor::new(); -} +pub mod cli; #[derive(Snafu, Debug)] pub enum Error { - OpenConfig { - source: config::Error, - }, - Bind { - address: SocketAddr, - source: std::io::Error, - }, - Unbundle { - source: bundle::Error, - }, - ServeError { - source: Box<server::Error>, - }, - ServeStats { - source: stats::Error, - }, - MonitorError { - source: monitor::Error, - }, - RecvNotify, - CliError { - source: collective::cli::CliError, - }, + ServeError { source: serve::Error }, + BundleError { source: packager::Error }, + CliError { source: collective::cli::CliError }, } type Result<T, E = Error> = std::result::Result<T, E>; -#[derive(Clap)] -#[clap(version = "1.0", author = "Eduardo T. <ed@trujillo.io>")] -struct Opts { - /// Sets a custom config file. - #[clap(short, long)] - config: Option<PathBuf>, - /// A level of verbosity, and can be used multiple times - #[clap(short, long, parse(from_occurrences))] - verbose: i32, - #[clap(subcommand)] - subcmd: SubCommand, -} - -#[derive(Clap)] -enum SubCommand { - /// Start the server - Serve, - Bundle(BundleOpts), -} - -/// Create a bundle using the configured bundler -#[derive(Clap)] -struct BundleOpts { - /// The path to use a source for the bundle. - source_path: PathBuf, -} - -impl AppOpts for Opts { - fn get_log_level_filter(&self) -> Option<log::LevelFilter> { - match self.verbose { - 3 => Some(log::LevelFilter::Trace), - 2 => Some(log::LevelFilter::Debug), - 1 => Some(log::LevelFilter::Info), - _ => None, - } - } -} - -impl ConfigurableAppOpts<config::Config> for Opts { - fn get_additional_config_paths(&self) -> Vec<PathBuf> { - if let Some(config_path) = &self.config { - vec![config_path.clone()] - } else { - vec![] - } - } -} - #[actix_rt::main] async fn main() -> Result<()> { + #[cfg(feature = "console-subscriber")] + console_subscriber::init(); + let result = inner_main().await; if let Err(Error::CliError { @@ -122,118 +41,12 @@ async fn main() -> Result<()> { } async fn inner_main() -> Result<()> { - MONITOR.init().context(MonitorError)?; - let (opts, config) = Opts::try_init_with_config().context(CliError)?; let config = Arc::new(config); match opts.subcmd { - SubCommand::Serve => serve(config).await, - SubCommand::Bundle(opts) => bundle(config, opts).await, + SubCommand::Serve => serve::serve(config).await.context(ServeError), + SubCommand::Bundle(opts) => bundle::bundle(config, opts).await.context(BundleError), } } - -async fn bundle(config: Arc<config::Config>, opts: BundleOpts) -> Result<()> { - let bundler = bundle::Bundler::new(config); - - bundler.package(opts.source_path).await.unwrap(); - - Ok(()) -} - -async fn serve(config: Arc<config::Config>) -> Result<()> { - // Set up a channel for receiving thread notifications. - let (monitor_tx, monitor_rx) = mpsc::channel(); - - // Keep track of what threads have been started. - let mut server_thread_ids = HashSet::new(); - let mut server_thread_handles = vec![]; - - // Set up unbundler. - let serve_dir = Arc::new(RwLock::new(None)); - let unbundler = Arc::new(bundle::Unbundler::new(config.clone(), serve_dir.clone())); - - // Set up main server. - let server = Server::new(config.server.clone(), serve_dir); - - let (server_handle, server_join_handle, server_thread_handle) = server - .spawn(monitor_tx.clone()) - .await - .map_err(|err| Error::ServeError { - source: Box::new(err), - })?; - - server_thread_ids.insert(server_join_handle.thread().id()); - server_thread_handles.push(server_thread_handle); - - // Set up optional stats server. - let mut maybe_stats_server_handle = None; - - match &config.stats { - Some(stats_config) => { - let stats_server = StatsServer::new(stats_config.clone(), unbundler.clone()); - - let (stats_server_handle, stats_join_handle, stats_thread_handle) = stats_server - .spawn(monitor_tx.clone()) - .await - .context(ServeStats)?; - - maybe_stats_server_handle = Some(stats_server_handle); - server_thread_ids.insert(stats_join_handle.thread().id()); - server_thread_handles.push(stats_thread_handle); - } - None => {} - } - - let (unbundler_join_handle, unbundler_thread_handle) = - thread::spawn(monitor_tx.clone(), move || { - let mut sys = System::new("unbundler"); - - let result = sys - .block_on(async move { unbundler.enter().await }) - .context(Unbundle); - - if let Err(e) = result { - error!("Unbundler failed: {:?}", e); - } - }); - - let (_, monitor_thread_handle) = thread::spawn(monitor_tx.clone(), move || { - let mut watched_thread_ids = HashSet::new(); - - watched_thread_ids.insert(unbundler_join_handle.thread().id()); - - for server_thread_id in server_thread_ids { - watched_thread_ids.insert(server_thread_id); - } - - if MONITOR.watch(Some(&watched_thread_ids)).is_err() { - error!("Failed to watch threads for panics."); - } - }); - - // Wait for a thread to finish. - loop { - monitor_rx.recv().map_err(|_| Error::RecvNotify)?; - - if Ok(true) == monitor_thread_handle.has_ended() { - info!("Stopping servers due to a panic."); - - break; - } else if Ok(true) == unbundler_thread_handle.has_ended() { - info!("Stopping servers due to unbundler shutdown."); - - break; - } - } - - // Stop server threads. - server_handle.stop(true).await; - - if let Some(stats_server_handle) = maybe_stats_server_handle { - stats_server_handle.stop(true).await; - } - - Ok(()) -} diff --git a/src/monitor.rs b/src/monitor.rs deleted file mode 100644 index c61da8a475655fee24edeadbd5c501719987c984..0000000000000000000000000000000000000000 --- a/src/monitor.rs +++ /dev/null @@ -1,227 +0,0 @@ -//! Thread Monitoring -//! -//! Utilities for monitoring when a thread has panicked. - -use snafu::Snafu; -use std::{ - collections::{HashMap, HashSet}, - panic, - sync::{Condvar, Mutex}, - thread::{self, Thread, ThreadId}, -}; - -#[derive(Debug, Snafu)] -pub enum Error { - WatchStateLock, - #[snafu(display("There should only be one active call to watch()."))] - MultipleWatches, - NoWatches, - Uninitialized, -} - -pub type Result<T, E = Error> = std::result::Result<T, E>; - -struct State { - panicked: HashMap<ThreadId, Thread>, - watched: Option<HashSet<ThreadId>>, - initialized: bool, -} - -/// A thread panic monitor. -pub struct Monitor { - condvar: Condvar, - state: Mutex<State>, -} - -impl Monitor { - /// Instantiates a new thread monitor. - pub fn new() -> Self { - Monitor { - condvar: Condvar::new(), - state: Mutex::new(State { - panicked: HashMap::new(), - watched: None, - initialized: false, - }), - } - } - - /// Initializes the thread monitor. - /// - /// This should be done before watching any threads. - /// - /// Internally, the monitor will set up a new panic hook, which will be used - /// for detecting panics on the threads being watched. - /// - /// The monitor will initially ignore all panics. Use [`set_watched`] or - /// [`watch`] to specify which threads to monitor. - /// - /// [`set_watched`]: #method.set_watched - /// [`watch`]: #method.watch - pub fn init(&'static self) -> Result<()> { - let hook = panic::take_hook(); - - panic::set_hook(Box::new(move |panic_info| { - match self.state.lock() { - Ok(mut state) => { - match &state.watched { - Some(watched) => { - let current_thread = thread::current(); - - // Only notify if the thread ID is being watched. - if watched.contains(¤t_thread.id()) { - state.panicked.insert(current_thread.id(), current_thread); - - self.condvar.notify_all(); - } - } - None => {} - } - } - Err(_) => error!("Unable to update map of panicked threads."), - } - - hook(panic_info) - })); - - let mut state = self.state.lock().map_err(|_| Error::WatchStateLock)?; - - state.initialized = true; - - Ok(()) - } - - /// Set the threads to be watched by this monitor. - /// - /// If [init] has been called, the monitor will begin recording panics for - /// the specified threads. - /// - /// [`init`]: #method.init - pub fn set_watched(&self, thread_ids: HashSet<ThreadId>) -> Result<()> { - let mut state = self.state.lock().map_err(|_| Error::WatchStateLock)?; - - state.watched = Some(thread_ids); - - Ok(()) - } - - /// Watches the provided thread IDs. - /// - /// [`init`] has to be called before this method. An [`Uninitialized`] error - /// will be returned if it's not. - /// - /// - If an empty set is passed, this function returns immediately. - /// - If a thread set is not passed and one hasn't been set with - /// [`set_watched`], a [`NoWatches`] error will be returned. - /// - If [`set_watched`] was previously called and one of the watched threads - /// already panicked, this function will return immediately. - /// - Otherwise, the monitor will block the current thread until one of the - /// watched threads has a panic. - /// - /// [`set_watched`]: #method.set_watched - /// [`NoWatches`]: ./enum.Error.html#variant.NoWatches - /// [`Uninitialized`]: ./enum.Error.html#variant.Uninitialized - pub fn watch(&self, thread_ids: Option<&HashSet<ThreadId>>) -> Result<Vec<Thread>> { - let mut state = self.state.lock().map_err(|_| Error::WatchStateLock)?; - - if !state.initialized { - return Err(Error::Uninitialized); - } - - let thread_ids = match thread_ids { - Some(thread_ids) => Ok(thread_ids.clone()), - None => match &(state.watched) { - Some(thread_ids) => Ok(thread_ids.clone()), - None => Err(Error::NoWatches), - }, - }?; - - if thread_ids.is_empty() { - return Ok(vec![]); - } - - state.panicked = HashMap::new(); - state.watched = Some(thread_ids); - - let mut watched_panicked = vec![]; - - loop { - // Since `state` may have changed, we need to reload the list of thread - // ids, otherwise we would be stuck checking for thread ids that may not - // be watched anymore. - let thread_ids = match &state.watched { - Some(thread_ids) => thread_ids, - None => return Err(Error::NoWatches), - }; - - if thread_ids.is_empty() { - return Ok(vec![]); - } - - for thread_id in thread_ids { - if let Some(thread) = state.panicked.get(&thread_id) { - watched_panicked.push(thread.clone().clone()); - } - } - - if !watched_panicked.is_empty() { - return Ok(watched_panicked); - } - - state = self - .condvar - .wait(state) - .map_err(|_| Error::WatchStateLock)?; - } - } -} - -impl Default for Monitor { - fn default() -> Self { - Self::new() - } -} - -#[cfg(test)] -mod tests { - use super::Monitor; - use lazy_static::lazy_static; - use std::{collections::HashSet, sync::mpsc, thread, time::Duration}; - - lazy_static! { - static ref MONITOR: Monitor = Monitor::new(); - } - - #[test] - pub fn test_watch() { - MONITOR.init().unwrap(); - - MONITOR.watch(Some(&HashSet::new())).unwrap(); - - let (tx, rx) = mpsc::channel(); - - let handle = thread::spawn(move || { - rx.recv().unwrap(); - - panic!("Oh no"); - }); - - let mut thread_ids = HashSet::new(); - thread_ids.insert(handle.thread().id()); - - thread::sleep(Duration::from_millis(10)); - - let test_handle = thread::spawn(move || { - let watch_result = MONITOR.watch(Some(&thread_ids)).unwrap(); - - assert_eq!(watch_result.is_empty(), false); - assert_eq!(watch_result[0].id(), handle.thread().id()); - }); - - thread::sleep(Duration::from_millis(10)); - - tx.send(true).unwrap(); - - test_handle.join().unwrap(); - } -} diff --git a/src/server.rs b/src/server.rs index 880940c0180d332ecddca3ae5e5298d9083095d4..3ae0be182ffa5242c738ade94767f26a1a6159cc 100644 --- a/src/server.rs +++ b/src/server.rs @@ -1,32 +1,29 @@ use crate::{ config::{CompressionConfig, ServerConfig}, files::{path_context::PathContext, Files}, - thread, - thread::ThreadHandle, }; -use actix::System; -use actix_http::http::{uri::InvalidUri, ContentEncoding}; +use actix_http::http::uri::InvalidUri; +use actix_rt::Runtime; use actix_web::{ - dev::Server as ActixServer, - middleware::{self, Logger}, + dev::ServerHandle, + middleware::{self, Condition, Logger}, App, HttpServer, }; +use collective::thread::{self, handle::ThreadHandle}; use snafu::{ResultExt, Snafu}; use std::{ convert::{TryFrom, TryInto}, path::PathBuf, sync::{ - mpsc::{self, RecvError, SendError, Sender}, - Arc, RwLock, + mpsc::{self, RecvError, Sender}, + Arc, }, - thread::{JoinHandle, Thread}, + thread::Thread, }; +use tokio::sync::RwLock; #[derive(Debug, Snafu)] pub enum Error { - ChannelSend { - source: SendError<Server>, - }, ChannelReceive { source: RecvError, }, @@ -59,13 +56,19 @@ impl Server { pub async fn spawn( self, notify_sender: Sender<Thread>, - ) -> Result<(ActixServer, JoinHandle<Result<()>>, ThreadHandle)> { + ) -> Result<(ServerHandle, ThreadHandle<Result<()>>)> { + log::debug!("Starting server thread"); + let (tx, rx) = mpsc::channel(); let server_address = self.config.address; let serve_dir = Arc::clone(&self.serve_dir); let redirect_to_slash = self.config.redirect_to_slash; - let compression = self.config.compression.clone(); + + let enable_auto_compression = matches!( + self.config.compression, + Some(CompressionConfig::Auto) | None + ); let root_path_context = Arc::new(PathContext::try_from(&self.config).context(CreatePathContext)?); @@ -79,8 +82,8 @@ impl Server { let path_contexts = Arc::new(path_contexts); - let (join_handle, thread_handle) = thread::spawn(notify_sender, move || { - let sys = System::new("http-server"); + let thread_handle = thread::handle::spawn(notify_sender, move || { + let rt = Runtime::new().unwrap(); let srv = HttpServer::new(move || { let mut files_service = Files::new( @@ -96,17 +99,10 @@ impl Server { App::new() .wrap(Logger::default()) - .wrap(middleware::Compress::new(match &compression { - Some(compression) => match compression { - CompressionConfig::Auto => ContentEncoding::Auto, - CompressionConfig::Brotli => ContentEncoding::Br, - CompressionConfig::Disabled => ContentEncoding::Identity, - CompressionConfig::Deflate => ContentEncoding::Deflate, - CompressionConfig::Gzip => ContentEncoding::Gzip, - }, - // Default to auto if not specified in the config. - _ => ContentEncoding::Auto, - })) + .wrap(Condition::new( + enable_auto_compression, + middleware::Compress::default(), + )) .default_service(files_service) }) .bind(server_address) @@ -114,15 +110,13 @@ impl Server { .shutdown_timeout(60) .run(); - let _ = tx.send(srv); + let _ = tx.send(srv.handle()); + + rt.block_on(async { srv.await }).context(SystemRun)?; - sys.run().context(SystemRun) + Ok(()) }); - Ok(( - rx.recv().context(ChannelReceive)?, - join_handle, - thread_handle, - )) + Ok((rx.recv().context(ChannelReceive)?, thread_handle)) } } diff --git a/src/stats.rs b/src/stats.rs index d3c736f51c7c53cb0f75a381a4c85838a2e6a76b..0c513f27cb1a6936b54434fa4f62d87a9484c711 100644 --- a/src/stats.rs +++ b/src/stats.rs @@ -1,22 +1,24 @@ -use crate::thread::{self, ThreadHandle}; use crate::{ bundle::{Unbundler, UnbundlerStatus}, config::StatsConfig, }; -use actix::System; -use actix_web::{dev::Server, middleware::Logger, App, HttpResponse, HttpServer, Responder}; +use actix_rt::Runtime; +use actix_web::dev::ServerHandle; +use actix_web::web::Data; +use actix_web::{middleware::Logger, App, HttpResponse, HttpServer, Responder}; +use collective::thread::{self, handle::ThreadHandle}; use mpsc::{RecvError, SendError, Sender}; use serde::Serialize; use snafu::{ResultExt, Snafu}; use std::{ path::PathBuf, sync::{mpsc, Arc}, - thread::{JoinHandle, Thread}, + thread::Thread, }; #[derive(Debug, Snafu)] pub enum Error { - ChannelSend { source: SendError<Server> }, + ChannelSend { source: SendError<ServerHandle> }, ChannelReceive { source: RecvError }, Bind { source: std::io::Error }, SystemRun { source: std::io::Error }, @@ -41,11 +43,11 @@ impl StatsServer { pub async fn spawn( self, notify_sender: Sender<Thread>, - ) -> Result<(Server, JoinHandle<Result<()>>, ThreadHandle)> { + ) -> Result<(ServerHandle, ThreadHandle<Result<()>>)> { let (tx, rx) = mpsc::channel(); - let (join_handle, thread_handle) = thread::spawn(notify_sender, move || { - let sys = System::new("stats-http-server"); + let thread_handle = thread::handle::spawn(notify_sender, move || { + let rt = Runtime::new().unwrap(); let unbundler = self.unbundler.clone(); let server_address = self.config.address; @@ -55,25 +57,23 @@ impl StatsServer { .wrap(Logger::default()) .route("/", actix_web::web::get().to(get_status)) .route("/health", actix_web::web::get().to(get_health)) - .data(State { + .app_data(Data::new(State { unbundler: Arc::clone(&unbundler), - }) + })) }) .bind(server_address) .context(Bind)? .shutdown_timeout(60) .run(); - tx.send(srv).context(ChannelSend)?; + tx.send(srv.handle()).context(ChannelSend)?; - sys.run().context(SystemRun) + rt.block_on(async { srv.await }).context(SystemRun)?; + + Ok(()) }); - Ok(( - rx.recv().context(ChannelReceive)?, - join_handle, - thread_handle, - )) + Ok((rx.recv().context(ChannelReceive)?, thread_handle)) } } @@ -83,13 +83,18 @@ struct GetStatusResponse { serve_dir: Option<PathBuf>, } -async fn get_status(data: actix_web::web::Data<State>) -> impl Responder { - let result: anyhow::Result<String> = try { - let status = data.unbundler.get_status()?; - let serve_dir = data.unbundler.get_serve_dir()?; +async fn try_get_status(data: actix_web::web::Data<State>) -> anyhow::Result<String> { + let status = data.unbundler.get_status().await?; + let serve_dir = data.unbundler.get_serve_dir().await?; - serde_json::to_string(&GetStatusResponse { status, serve_dir })? - }; + Ok(serde_json::to_string(&GetStatusResponse { + status, + serve_dir, + })?) +} + +async fn get_status(data: actix_web::web::Data<State>) -> impl Responder { + let result = try_get_status(data).await; match result { Ok(response) => HttpResponse::Ok().body(response), @@ -98,10 +103,9 @@ async fn get_status(data: actix_web::web::Data<State>) -> impl Responder { } async fn get_health(data: actix_web::web::Data<State>) -> impl Responder { - match data.unbundler.get_status() { + match data.unbundler.get_status().await { Ok(status) => match status { - UnbundlerStatus::Ready => HttpResponse::Ok().body("Ready"), - UnbundlerStatus::Polling => HttpResponse::Ok().body("Ready"), + UnbundlerStatus::Ready | UnbundlerStatus::Polling => HttpResponse::Ok().body("Ready"), _ => HttpResponse::ServiceUnavailable().body("Not Ready"), }, Err(_) => HttpResponse::InternalServerError().body("Internal Server Error"), diff --git a/src/thread.rs b/src/thread.rs deleted file mode 100644 index 8d48c37d63d5857a80a505a441fa0a81cc759a5b..0000000000000000000000000000000000000000 --- a/src/thread.rs +++ /dev/null @@ -1,167 +0,0 @@ -//! Multithreading Utilities. - -use mpsc::Sender; -use snafu::Snafu; -use std::{ - sync::{mpsc, Arc, RwLock}, - thread::JoinHandle, -}; - -#[derive(Snafu, Debug, PartialEq)] -pub enum Error { - // Unable to obtain a read lock to check the status of a thread. - LockRead, -} - -pub type Result<T, E = Error> = std::result::Result<T, E>; - -/// A lightweight abstration over a regular thread that provides an API for -/// determining if a thread has terminated. -pub struct ThreadHandle { - ended: Arc<RwLock<bool>>, -} - -impl ThreadHandle { - /// Attempts to check if the thread has ended. - /// - /// An error may be returned if the underlying channel is disconnected. - pub fn has_ended(&self) -> Result<bool> { - let result = self.ended.read().map_err(|_| Error::LockRead)?; - - Ok(*result) - } -} - -/// Like `std::thread::spawn`, but returns a `ThreadHandle` instead. -/// -/// # Examples -/// -/// Create ten threads and wait for all threads to finish. -/// -/// ``` -/// use espresso::thread::spawn; -/// use std::{ -/// collections::HashMap, -/// sync::{mpsc, Arc, Barrier}, -/// }; -/// -/// let (monitor_tx, monitor_rx) = mpsc::channel(); -/// let barrier = Arc::new(Barrier::new(10)); -/// -/// let mut handles = HashMap::new(); -/// -/// for _ in 0..10 { -/// let bc = barrier.clone(); -/// -/// let (join_handle, thread_handle) = spawn(monitor_tx.clone(), move || { -/// /// Sync all threads. -/// bc.wait(); -/// }); -/// -/// handles.insert(join_handle.thread().id(), thread_handle); -/// } -/// -/// // Loop until we have been notified of every thread ending. -/// loop { -/// let thread = monitor_rx.recv().unwrap(); -/// -/// handles.remove(&thread.id()); -/// -/// if handles.is_empty() { -/// break; -/// } -/// } -/// ``` -pub fn spawn<F, T>( - notify_sender: Sender<std::thread::Thread>, - f: F, -) -> (JoinHandle<T>, ThreadHandle) -where - F: FnOnce() -> T, - F: Send + 'static, - T: Send + 'static, -{ - let ended = Arc::new(RwLock::new(false)); - let ended_for_spawn = ended.clone(); - - let join_handle = std::thread::spawn(move || { - let ended = ended_for_spawn.clone(); - - let result = f(); - - let mut ended = ended.write().unwrap(); - *ended = true; - notify_sender.send(std::thread::current()).unwrap(); - - result - }); - - (join_handle, ThreadHandle { ended }) -} - -#[cfg(test)] -mod tests { - use super::spawn; - use std::{ - collections::HashMap, - sync::{mpsc, Arc, Barrier}, - }; - - #[test] - fn test_spawn() { - let (monitor_tx, monitor_rx) = mpsc::channel(); - let (ready_tx, ready_rx) = mpsc::channel(); - let (end_tx, end_rx) = mpsc::channel(); - - let (join_handle, handle) = spawn(monitor_tx, move || { - ready_tx.send(()).unwrap(); - - end_rx.recv().unwrap(); - }); - - ready_rx.recv().unwrap(); - - assert_eq!((&handle).has_ended(), Ok(false)); - - end_tx.send(()).unwrap(); - - monitor_rx.recv().unwrap(); - join_handle.join().unwrap(); - - assert_eq!(handle.has_ended(), Ok(true)); - } - - #[test] - fn test_multiple() { - let (monitor_tx, monitor_rx) = mpsc::channel(); - let barrier = Arc::new(Barrier::new(11)); - - let mut handles = HashMap::new(); - - for _ in 0..10 { - let bc = barrier.clone(); - - let (join_handle, thread_handle) = spawn(monitor_tx.clone(), move || { - bc.wait(); - }); - - handles.insert(join_handle.thread().id(), thread_handle); - } - - for (_, handle) in &handles { - assert_eq!(handle.has_ended(), Ok(false)); - } - - barrier.wait(); - - loop { - let thread = monitor_rx.recv().unwrap(); - - handles.remove(&thread.id()); - - if handles.is_empty() { - break; - } - } - } -}