diff options
-rw-r--r-- | .github/dependabot.yml | 8 | ||||
-rw-r--r-- | .github/workflows/publish.yml | 14 | ||||
-rw-r--r-- | CHANGELOG.md | 10 | ||||
-rw-r--r-- | Cargo.lock | 1496 | ||||
-rw-r--r-- | Cargo.toml | 32 | ||||
-rw-r--r-- | README.md | 26 | ||||
-rw-r--r-- | data/style.scss | 1 | ||||
-rw-r--r-- | src/args.rs | 10 | ||||
-rw-r--r-- | src/auth.rs | 74 | ||||
-rw-r--r-- | src/config.rs | 192 | ||||
-rw-r--r-- | src/file_upload.rs | 233 | ||||
-rw-r--r-- | src/listing.rs | 68 | ||||
-rw-r--r-- | src/main.rs | 218 | ||||
-rw-r--r-- | src/pipe.rs | 10 | ||||
-rw-r--r-- | src/renderer.rs | 4 | ||||
-rw-r--r-- | tests/archive.rs | 58 | ||||
-rw-r--r-- | tests/auth.rs | 140 | ||||
-rw-r--r-- | tests/data/cert.pem | 29 | ||||
-rwxr-xr-x | tests/data/generate_tls_certs.sh | 2 | ||||
-rw-r--r-- | tests/data/key.pem | 52 | ||||
-rw-r--r-- | tests/fixtures/mod.rs | 116 | ||||
-rw-r--r-- | tests/header.rs | 24 | ||||
-rw-r--r-- | tests/navigation.rs | 103 | ||||
-rw-r--r-- | tests/qrcode.rs | 59 | ||||
-rw-r--r-- | tests/serve_request.rs | 114 | ||||
-rw-r--r-- | tests/tls.rs | 53 | ||||
-rw-r--r-- | tests/upload_files.rs | 48 |
27 files changed, 1430 insertions, 1764 deletions
diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..c11601f --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,8 @@ +version: 2 +updates: +- package-ecosystem: cargo + directory: "/" + schedule: + interval: daily + time: "04:00" + open-pull-requests-limit: 10 diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 53480cd..064a0a0 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -32,6 +32,7 @@ jobs: cross: true strip: true compress: true + cargo_flags: "" - os: ubuntu-latest target: aarch64-unknown-linux-musl artifact_name: target/aarch64-unknown-linux-musl/release/miniserve @@ -39,6 +40,7 @@ jobs: cross: true strip: false compress: true + cargo_flags: "" - os: ubuntu-latest target: armv7-unknown-linux-musleabihf artifact_name: target/armv7-unknown-linux-musleabihf/release/miniserve @@ -46,6 +48,7 @@ jobs: cross: true strip: false compress: true + cargo_flags: "" - os: ubuntu-latest target: arm-unknown-linux-musleabihf artifact_name: target/arm-unknown-linux-musleabihf/release/miniserve @@ -53,6 +56,7 @@ jobs: cross: true strip: false compress: true + cargo_flags: "" - os: ubuntu-latest target: mips-unknown-linux-musl artifact_name: target/mips-unknown-linux-musl/release/miniserve @@ -60,6 +64,7 @@ jobs: cross: true strip: false compress: true + cargo_flags: "--no-default-features" - os: ubuntu-latest target: mipsel-unknown-linux-musl artifact_name: target/mipsel-unknown-linux-musl/release/miniserve @@ -67,6 +72,7 @@ jobs: cross: true strip: false compress: true + cargo_flags: "--no-default-features" - os: ubuntu-latest target: mips64-unknown-linux-gnuabi64 artifact_name: target/mips64-unknown-linux-gnuabi64/release/miniserve @@ -74,6 +80,7 @@ jobs: cross: true strip: false compress: false + cargo_flags: "--no-default-features" - os: ubuntu-latest target: mips64el-unknown-linux-gnuabi64 artifact_name: target/mips64el-unknown-linux-gnuabi64/release/miniserve @@ -81,6 +88,7 @@ jobs: cross: true strip: false compress: false + cargo_flags: "--no-default-features" - os: ubuntu-latest target: riscv64gc-unknown-linux-gnu artifact_name: target/riscv64gc-unknown-linux-gnu/release/miniserve @@ -88,6 +96,7 @@ jobs: cross: true strip: false compress: false + cargo_flags: "--no-default-features" - os: windows-latest target: x86_64-pc-windows-msvc artifact_name: target/x86_64-pc-windows-msvc/release/miniserve.exe @@ -95,6 +104,7 @@ jobs: cross: false strip: true compress: true + cargo_flags: "" - os: macos-latest target: x86_64-apple-darwin artifact_name: target/x86_64-apple-darwin/release/miniserve @@ -102,6 +112,7 @@ jobs: cross: false strip: true compress: true + cargo_flags: "" - os: ubuntu-latest target: x86_64-unknown-freebsd artifact_name: target/x86_64-unknown-freebsd/release/miniserve @@ -109,6 +120,7 @@ jobs: cross: true strip: false compress: false + cargo_flags: "" steps: - name: Checkout code @@ -124,7 +136,7 @@ jobs: uses: actions-rs/cargo@v1 with: command: build - args: --release --locked --target=${{ matrix.target }} + args: --release --locked --target=${{ matrix.target }} ${{ matrix.cargo_flags }} use-cross: ${{ matrix.cross }} - name: Compress binaries diff --git a/CHANGELOG.md b/CHANGELOG.md index d542b4f..d897915 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/). <!-- next-header --> ## [Unreleased] - ReleaseDate +- Fix serving files with backslashes in their names [#578](https://github.com/svenstaro/miniserve/pull/578) (thanks @Jikstra) +- Fix behavior of downloading symlinks by upgrading to actix-web 4 [#582](https://github.com/svenstaro/miniserve/pull/582)[#462](https://github.com/svenstaro/miniserve/issues/462) (thanks @aliemjay) + +## [0.15.0] - 2021-08-27 - Add hardened systemd template unit file to `packaging/miniserve@.service` +- Fix qrcodegen dependency problem [#568](https://github.com/svenstaro/miniserve/issues/568) +- Remove animation on QR code hover (it was kind of annoying as it makes things less snappy) +- Add TLS support [#576](https://github.com/svenstaro/miniserve/pull/576) ## [0.14.0] - 2021-04-18 - Fix breadcrumbs for right-to-left languages [#489](https://github.com/svenstaro/miniserve/pull/489) (thanks @aliemjay) @@ -94,7 +101,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Some theme related bug fixes (thanks @boastful-squirrel) <!-- next-url --> -[Unreleased]: https://github.com/svenstaro/miniserve/compare/v0.14.0...HEAD +[Unreleased]: https://github.com/svenstaro/miniserve/compare/v0.15.0...HEAD +[0.15.0]: https://github.com/svenstaro/miniserve/compare/v0.14.0...v0.15.0 [0.14.0]: https://github.com/svenstaro/miniserve/compare/v0.13.0...v0.14.0 [0.13.0]: https://github.com/svenstaro/miniserve/compare/v0.12.1...v0.13.0 [0.12.1]: https://github.com/svenstaro/miniserve/compare/v0.12.0...v0.12.1 @@ -4,111 +4,91 @@ version = 3 [[package]] name = "actix-codec" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78d1833b3838dbe990df0f1f87baf640cf6146e898166afe401839d1b001e570" +checksum = "1d5dbeb2d9e51344cb83ca7cc170f1217f9fe25bfc50160e6e200b5c31c1019a" dependencies = [ "bitflags", - "bytes 0.5.6", + "bytes", "futures-core", "futures-sink", "log", - "pin-project 0.4.28", - "tokio 0.2.25", - "tokio-util 0.3.1", -] - -[[package]] -name = "actix-connect" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "177837a10863f15ba8d3ae3ec12fac1099099529ed20083a27fdfe247381d0dc" -dependencies = [ - "actix-codec", - "actix-rt", - "actix-service", - "actix-utils", - "derive_more", - "either", - "futures-util", - "http", - "log", - "trust-dns-proto", - "trust-dns-resolver", + "pin-project-lite", + "tokio", + "tokio-util", ] [[package]] name = "actix-files" -version = "0.5.0" +version = "0.6.0-beta.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c51e8a9146c12fce92a6e4c24b8c4d9b05268130bfd8d61bc587e822c32ce689" +checksum = "89b864740ed79d26e6e3c33fd2a1e03a071daaa43c88e6900ff1f9378fca88ce" dependencies = [ + "actix-http", "actix-service", + "actix-utils", "actix-web", + "askama_escape", "bitflags", - "bytes 0.5.6", + "bytes", "derive_more", "futures-core", - "futures-util", + "http-range", "log", "mime", "mime_guess", "percent-encoding", - "v_htmlescape", ] [[package]] name = "actix-http" -version = "2.2.0" +version = "3.0.0-beta.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "452299e87817ae5673910e53c243484ca38be3828db819b6011736fc6982e874" +checksum = "01260589f1aafad11224002741eb37bc603b4ce55b4e3556d2b2122f9aac7c51" dependencies = [ "actix-codec", - "actix-connect", "actix-rt", "actix-service", - "actix-threadpool", + "actix-tls", "actix-utils", + "ahash", "base64", "bitflags", "brotli2", - "bytes 0.5.6", - "cookie", - "copyless", + "bytes", + "bytestring", "derive_more", - "either", "encoding_rs", "flate2", - "futures-channel", "futures-core", "futures-util", - "fxhash", - "h2 0.2.7", + "h2", "http", "httparse", - "indexmap", "itoa", "language-tags", - "lazy_static", + "local-channel", "log", "mime", + "once_cell", "percent-encoding", - "pin-project 1.0.7", - "rand 0.7.3", + "pin-project", + "pin-project-lite", + "rand 0.8.4", "regex", "serde", - "serde_json", - "serde_urlencoded", "sha-1", - "slab", - "time 0.2.26", + "smallvec", + "time 0.2.27", + "tokio", + "zstd", ] [[package]] name = "actix-macros" -version = "0.1.3" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ca8ce00b267af8ccebbd647de0d61e0674b6e61185cc7a592ff88772bed655" +checksum = "c2f86cd6857c135e6e9fe57b1619a88d1f94a7df34c00e11fe13e64fd3438837" dependencies = [ "quote", "syn", @@ -116,17 +96,18 @@ dependencies = [ [[package]] name = "actix-multipart" -version = "0.3.0" +version = "0.4.0-beta.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "774bfeb11b54bf9c857a005b8ab893293da4eaff79261a66a9200dab7f5ab6e3" +checksum = "a32d8964e147f1e411b38cd08a28eb37915be6797191a394fe0ad73f36441a99" dependencies = [ - "actix-service", "actix-utils", "actix-web", - "bytes 0.5.6", + "bytes", "derive_more", + "futures-core", "futures-util", "httparse", + "local-waker", "log", "mime", "twoway", @@ -147,115 +128,77 @@ dependencies = [ [[package]] name = "actix-rt" -version = "1.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "143fcc2912e0d1de2bcf4e2f720d2a60c28652ab4179685a1ee159e0fb3db227" +checksum = "bc7d7cd957c9ed92288a7c3c96af81fa5291f65247a76a34dac7b6af74e52ba0" dependencies = [ "actix-macros", - "actix-threadpool", - "copyless", - "futures-channel", - "futures-util", - "smallvec", - "tokio 0.2.25", + "futures-core", + "tokio", ] [[package]] name = "actix-server" -version = "1.0.4" +version = "2.0.0-beta.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45407e6e672ca24784baa667c5d32ef109ccdd8d5e0b5ebb9ef8a67f4dfb708e" +checksum = "26369215fcc3b0176018b3b68756a8bcc275bb000e6212e454944913a1f9bf87" dependencies = [ - "actix-codec", "actix-rt", "actix-service", "actix-utils", - "futures-channel", - "futures-util", + "futures-core", "log", - "mio 0.6.23", - "mio-uds", + "mio", "num_cpus", "slab", - "socket2 0.3.19", + "tokio", ] [[package]] name = "actix-service" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0052435d581b5be835d11f4eb3bce417c8af18d87ddf8ace99f8e67e595882bb" -dependencies = [ - "futures-util", - "pin-project 0.4.28", -] - -[[package]] -name = "actix-testing" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47239ca38799ab74ee6a8a94d1ce857014b2ac36f242f70f3f75a66f691e791c" -dependencies = [ - "actix-macros", - "actix-rt", - "actix-server", - "actix-service", - "log", - "socket2 0.3.19", -] - -[[package]] -name = "actix-threadpool" -version = "0.3.3" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d209f04d002854b9afd3743032a27b066158817965bf5d036824d19ac2cc0e30" +checksum = "77f5f9d66a8730d0fae62c26f3424f5751e5518086628a40b7ab6fca4a705034" dependencies = [ - "derive_more", - "futures-channel", - "lazy_static", - "log", - "num_cpus", - "parking_lot", - "threadpool", + "futures-core", + "paste", + "pin-project-lite", ] [[package]] name = "actix-tls" -version = "2.0.0" +version = "3.0.0-beta.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24789b7d7361cf5503a504ebe1c10806896f61e96eca9a7350e23001aca715fb" +checksum = "65b7bb60840962ef0332f7ea01a57d73a24d2cb663708511ff800250bbfef569" dependencies = [ "actix-codec", + "actix-rt", "actix-service", "actix-utils", - "futures-util", + "derive_more", + "futures-core", + "http", + "log", + "tokio-rustls", + "tokio-util", + "webpki-roots", ] [[package]] name = "actix-utils" -version = "2.0.0" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e9022dec56632d1d7979e59af14f0597a28a830a9c1c7fec8b2327eb9f16b5a" +checksum = "e491cbaac2e7fc788dfff99ff48ef317e23b3cf63dbaf7aaab6418f40f92aa94" dependencies = [ - "actix-codec", - "actix-rt", - "actix-service", - "bitflags", - "bytes 0.5.6", - "either", - "futures-channel", - "futures-sink", - "futures-util", - "log", - "pin-project 0.4.28", - "slab", + "local-waker", + "pin-project-lite", ] [[package]] name = "actix-web" -version = "3.3.2" +version = "4.0.0-beta.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e641d4a172e7faa0862241a20ff4f1f5ab0ab7c279f00c2d4587b77483477b86" +checksum = "c503f726f895e55dac39adeafd14b5ee00cc956796314e9227fc7ae2e176f443" dependencies = [ "actix-codec", "actix-http", @@ -264,37 +207,40 @@ dependencies = [ "actix-rt", "actix-server", "actix-service", - "actix-testing", - "actix-threadpool", "actix-tls", "actix-utils", "actix-web-codegen", - "awc", - "bytes 0.5.6", + "ahash", + "bytes", + "cfg-if", + "cookie", "derive_more", + "either", "encoding_rs", - "futures-channel", "futures-core", "futures-util", - "fxhash", + "itoa", + "language-tags", "log", "mime", - "pin-project 1.0.7", + "once_cell", + "paste", + "pin-project", "regex", "serde", "serde_json", "serde_urlencoded", - "socket2 0.3.19", - "time 0.2.26", - "tinyvec", + "smallvec", + "socket2", + "time 0.2.27", "url", ] [[package]] name = "actix-web-codegen" -version = "0.4.0" +version = "0.5.0-beta.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad26f77093333e0e7c6ffe54ebe3582d908a104e448723eec6d43d08b07143fb" +checksum = "0d048c6986743105c1e8e9729fbc8d5d1667f2f62393a58be8d85a7d9a5a6c8d" dependencies = [ "proc-macro2", "quote", @@ -303,10 +249,11 @@ dependencies = [ [[package]] name = "actix-web-httpauth" -version = "0.5.1" +version = "0.6.0-beta.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c3b11a07a3df3f7970fd8bd38cc66998b5549f507c54cc64c6e843bc82d6358" +checksum = "264d0eb4698d59493cafc96554c3919837115f8c4e9040a3790c2b55400ff758" dependencies = [ + "actix-service", "actix-web", "base64", "futures-util", @@ -326,9 +273,14 @@ checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" [[package]] name = "ahash" -version = "0.3.8" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8fd72866655d1904d6b0997d0b07ba561047d070fbe29de039031c641b61217" +checksum = "43bb833f0bf979d8475d38fbf09ed3b8a55e1885fe93ad3f93239fc6a4f17b98" +dependencies = [ + "getrandom 0.2.3", + "once_cell", + "version_check", +] [[package]] name = "aho-corasick" @@ -351,7 +303,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" dependencies = [ - "winapi 0.3.9", + "winapi", ] [[package]] @@ -360,14 +312,26 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" dependencies = [ - "winapi 0.3.9", + "winapi", ] [[package]] +name = "anyhow" +version = "1.0.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28ae2b3dec75a406790005a200b1bd89785afc02517a00ca99ecfe093ee9e6cf" + +[[package]] +name = "askama_escape" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90c108c1a94380c89d2215d0ac54ce09796823cca0fd91b299cfff3b33e346fb" + +[[package]] name = "assert_cmd" -version = "1.0.3" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2475b58cd94eb4f70159f4fd8844ba3b807532fe3131b3373fae060bbe30396" +checksum = "54f002ce7d0c5e809ebb02be78fd503aeed4a511fd0fcaff6e6914cbdabbfa33" dependencies = [ "bstr", "doc-comment", @@ -379,9 +343,9 @@ dependencies = [ [[package]] name = "assert_fs" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73c485ca248200dfb850a64468a926321865cae0c450eaa7cdbe9ccf4ec49028" +checksum = "b0ca6aa3066e6c6f0357e056a25fa95e8737f15a04f9aead0b22d0d082a39465" dependencies = [ "doc-comment", "globwalk", @@ -392,17 +356,6 @@ dependencies = [ ] [[package]] -name = "async-trait" -version = "0.1.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b98e84bbb4cbcdd97da190ba0c58a1bb0de2c1fdf67d159e192ed766aeca722" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -410,7 +363,7 @@ checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ "hermit-abi", "libc", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -420,30 +373,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] -name = "awc" -version = "2.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b381e490e7b0cfc37ebc54079b0413d8093ef43d14a4e4747083f7fa47a9e691" -dependencies = [ - "actix-codec", - "actix-http", - "actix-rt", - "actix-service", - "base64", - "bytes 0.5.6", - "cfg-if 1.0.0", - "derive_more", - "futures-core", - "log", - "mime", - "percent-encoding", - "rand 0.7.3", - "serde", - "serde_json", - "serde_urlencoded", -] - -[[package]] name = "base-x" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -457,9 +386,9 @@ checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" [[package]] name = "beef" -version = "0.4.4" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "474a626a67200bd107d44179bb3d4fc61891172d11696609264589be6a0e6a43" +checksum = "bed554bd50246729a1ec158d08aa3235d1b69d94ad120ebe187e28894787e736" [[package]] name = "bit-set" @@ -478,9 +407,9 @@ checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" [[package]] name = "bitflags" -version = "1.2.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "block-buffer" @@ -513,9 +442,9 @@ dependencies = [ [[package]] name = "bstr" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a40b47ad93e1a5404e6c18dec46b628214fee441c70f4ab5d6942142cc268a3d" +checksum = "90682c8d613ad3373e66de8c6411e0ae2ab2571e879d2efbf73558cc66f21279" dependencies = [ "lazy_static", "memchr", @@ -523,19 +452,10 @@ dependencies = [ ] [[package]] -name = "buf-min" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa17aa1cf56bdd6bb30518767d00e58019d326f3f05d8c3e0730b549d332ea83" -dependencies = [ - "bytes 0.5.6", -] - -[[package]] name = "bumpalo" -version = "3.6.1" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63396b8a4b9de3f4fdfb320ab6080762242f66a8ef174c49d8e19b674db4cdbe" +checksum = "9c59e7af012c713f529e7a3ee57ce9b31ddd858d4b512923602f74608b009631" [[package]] name = "byteorder" @@ -545,21 +465,15 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" - -[[package]] -name = "bytes" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040" +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" [[package]] name = "bytesize" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81a18687293a1546b67c246452202bbbf143d239cb43494cc163da14979082da" +checksum = "6c58ec36aac5066d5ca17df51b3e70279f5670a72102f5752cb7e7c856adfc70" [[package]] name = "bytestring" @@ -567,14 +481,14 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90706ba19e97b90786e19dc0d5e2abd80008d99d4c0c5d1ad0b5e72cec7c494d" dependencies = [ - "bytes 1.0.1", + "bytes", ] [[package]] name = "bzip2" -version = "0.3.3" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42b7c3cbf0fa9c1b82308d57191728ca0256cb821220f4e2fd410a72ade26e3b" +checksum = "6afcd980b5f3a45017c57e57a2fcccbb351cc43a356ce117ef760ef8052b89b0" dependencies = [ "bzip2-sys", "libc", @@ -582,9 +496,9 @@ dependencies = [ [[package]] name = "bzip2-sys" -version = "0.1.10+1.0.8" +version = "0.1.11+1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17fa3d1ac1ca21c5c4e36a97f3c3eb25084576f6fc47bf0139c1123434216c6c" +checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" dependencies = [ "cc", "libc", @@ -593,15 +507,12 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.67" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd" - -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2" +dependencies = [ + "jobserver", +] [[package]] name = "cfg-if" @@ -619,7 +530,7 @@ dependencies = [ "num-integer", "num-traits", "time 0.1.43", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -654,9 +565,9 @@ checksum = "b9e769b5c8c8283982a987c6e948e540254f1058d5a74b8794914d4ef5fc2a24" [[package]] name = "const_fn" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "402da840495de3f976eaefc3485b7f5eb5b0bf9761f9a47be27fe975b3b8c2ec" +checksum = "f92cfa0fd5690b3cf8c1ef2cabbd9b7ef22fa53cf5e1f92b05103f6d5d1cf6e7" [[package]] name = "convert_case" @@ -666,32 +577,23 @@ checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" [[package]] name = "cookie" -version = "0.14.4" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03a5d7b21829bc7b4bf4754a978a241ae54ea55a40f92bb20216e54096f4b951" +checksum = "d5f1c7727e460397e56abc4bddc1d49e07a1ad78fc98eb2e1c8f032a58a2f80d" dependencies = [ "percent-encoding", - "time 0.2.26", - "version_check 0.9.3", + "time 0.2.27", + "version_check", ] [[package]] -name = "copyless" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2df960f5d869b2dd8532793fde43eb5427cceb126c929747a26823ab0eeb536" - -[[package]] name = "cpufeatures" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cd5a7748210e7ec1a9696610b1015e6e31fbf58f77a160801f124bd1c36592a" - -[[package]] -name = "cpuid-bool" -version = "0.1.2" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634" +checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" +dependencies = [ + "libc", +] [[package]] name = "crc32fast" @@ -699,17 +601,16 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] name = "crossbeam-utils" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7e9d99fa91428effe99c5c6d4634cdeba32b8cf784fc428a2a687f61a952c49" +checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" dependencies = [ - "autocfg", - "cfg-if 1.0.0", + "cfg-if", "lazy_static", ] @@ -725,13 +626,14 @@ dependencies = [ [[package]] name = "derive_more" -version = "0.99.13" +version = "0.99.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f82b1b72f1263f214c0f823371768776c4f5841b942c9883aa8e5ec584fd0ba6" +checksum = "40eebddd2156ce1bb37b20bbe5151340a31828b1f2d22ba4141f3531710e38df" dependencies = [ "convert_case", "proc-macro2", "quote", + "rustc_version 0.3.3", "syn", ] @@ -742,10 +644,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499" [[package]] -name = "difference" -version = "2.0.0" +name = "difflib" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" +checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" [[package]] name = "digest" @@ -780,31 +682,19 @@ version = "0.8.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80df024fbc5ac80f87dfef0d9f5209a252f2a497f7f42944cff24d8253cac065" dependencies = [ - "cfg-if 1.0.0", -] - -[[package]] -name = "enum-as-inner" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c5f0096a91d210159eceb2ff5e1c4da18388a170e1e3ce948aac9c8fdbbf595" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", + "cfg-if", ] [[package]] name = "filetime" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d34cfa13a63ae058bfa601fe9e313bbdb3746427c1459185464ce0fcf62e1e8" +checksum = "975ccf83d8d9d0d84682850a38c8169027be83368805971cc4f238c2b245bc98" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "redox_syscall", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -813,7 +703,7 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd3aec53de10fe96d7d8c565eb17f2c687bb5518a2ec453b5b1252964526abe0" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crc32fast", "libc", "miniz_oxide", @@ -821,9 +711,9 @@ dependencies = [ [[package]] name = "float-cmp" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1267f4ac4f343772758f7b1bdcbe767c218bbab93bb432acbf5162bbf85a6c4" +checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" dependencies = [ "num-traits", ] @@ -845,22 +735,6 @@ dependencies = [ ] [[package]] -name = "fuchsia-zircon" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" -dependencies = [ - "bitflags", - "fuchsia-zircon-sys", -] - -[[package]] -name = "fuchsia-zircon-sys" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" - -[[package]] name = "futf" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -872,9 +746,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.14" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9d5813545e459ad3ca1bff9915e9ad7f1a47dc6a91b627ce321d5863b7dd253" +checksum = "1adc00f486adfc9ce99f77d717836f0c5aa84965eb0b4f051f4e83f7cab53f8b" dependencies = [ "futures-channel", "futures-core", @@ -887,9 +761,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.14" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce79c6a52a299137a6013061e0cf0e688fce5d7f1bc60125f520912fdb29ec25" +checksum = "74ed2411805f6e4e3d9bc904c95d5d423b89b3b25dc0250aa74729de20629ff9" dependencies = [ "futures-core", "futures-sink", @@ -897,15 +771,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.14" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "098cd1c6dda6ca01650f1a37a794245eb73181d0d4d4e955e2f3c37db7af1815" +checksum = "af51b1b4a7fdff033703db39de8802c673eb91855f2e0d47dcf3bf2c0ef01f99" [[package]] name = "futures-executor" -version = "0.3.14" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f6cb7042eda00f0049b1d2080aa4b93442997ee507eb3828e8bd7577f94c9d" +checksum = "4d0d535a57b87e1ae31437b892713aee90cd2d7b0ee48727cd11fc72ef54761c" dependencies = [ "futures-core", "futures-task", @@ -914,16 +788,17 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.14" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "365a1a1fb30ea1c03a830fdb2158f5236833ac81fa0ad12fe35b29cddc35cb04" +checksum = "0b0e06c393068f3a6ef246c75cdca793d6a46347e75286933e5e75fd2fd11582" [[package]] name = "futures-macro" -version = "0.3.14" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "668c6733a182cd7deb4f1de7ba3bf2120823835b3bcfbeacf7d2c4a773c1bb8b" +checksum = "c54913bae956fb8df7f4dc6fc90362aa72e69148e3f39041fbe8742d21e0ac57" dependencies = [ + "autocfg", "proc-macro-hack", "proc-macro2", "quote", @@ -932,22 +807,23 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.14" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5629433c555de3d82861a7a4e3794a4c40040390907cfbfd7143a92a426c23" +checksum = "c0f30aaa67363d119812743aa5f33c201a7a66329f97d1a887022971feea4b53" [[package]] name = "futures-task" -version = "0.3.14" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba7aa51095076f3ba6d9a1f702f74bd05ec65f555d70d2033d55ba8d69f581bc" +checksum = "bbe54a98670017f3be909561f6ad13e810d9a51f3f061b902062ca3da80799f2" [[package]] name = "futures-util" -version = "0.3.14" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c144ad54d60f23927f0a6b6d816e4271278b64f005ad65e4e35291d2de9c025" +checksum = "67eb846bfd58e44a8481a00049e82c43e0ccb5d61f8dc071057cb19249dd4d78" dependencies = [ + "autocfg", "futures-channel", "futures-core", "futures-io", @@ -955,7 +831,7 @@ dependencies = [ "futures-sink", "futures-task", "memchr", - "pin-project-lite 0.2.6", + "pin-project-lite", "pin-utils", "proc-macro-hack", "proc-macro-nested", @@ -963,22 +839,13 @@ dependencies = [ ] [[package]] -name = "fxhash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] - -[[package]] name = "generic-array" version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" dependencies = [ "typenum", - "version_check 0.9.3", + "version_check", ] [[package]] @@ -987,27 +854,27 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "wasi 0.9.0+wasi-snapshot-preview1", ] [[package]] name = "getrandom" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" +checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "wasi 0.10.2+wasi-snapshot-preview1", ] [[package]] name = "globset" -version = "0.4.6" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c152169ef1e421390738366d2f796655fec62621dabbd0fd476f905934061e4a" +checksum = "10463d9ff00a2a068db14231982f5132edebad0d7660cd956a1c30292dbcbfbd" dependencies = [ "aho-corasick", "bstr", @@ -1029,9 +896,9 @@ dependencies = [ [[package]] name = "grass" -version = "0.10.4" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8209e6832a1f93e15adca845b43af12ead0cb8221fb2ef615ca84c75e54af1a" +checksum = "82317908bc4204532d098390f8e041693aaeab95cf7351f774bdacf253b1c8ed" dependencies = [ "beef", "clap", @@ -1042,38 +909,17 @@ dependencies = [ "num-rational", "num-traits", "once_cell", - "peekmore", - "phf", - "rand 0.7.3", -] - -[[package]] -name = "h2" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e4728fd124914ad25e99e3d15a9361a879f6620f63cb56bbb08f95abb97a535" -dependencies = [ - "bytes 0.5.6", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http", - "indexmap", - "slab", - "tokio 0.2.25", - "tokio-util 0.3.1", - "tracing", - "tracing-futures", + "phf 0.9.0", + "rand 0.8.4", ] [[package]] name = "h2" -version = "0.3.2" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc018e188373e2777d0ef2467ebff62a08e66c3f5857b23c8fbec3018210dc00" +checksum = "d7f3675cfef6a30c8031cf9e6493ebdc3bb3272a3fea3923c4210d1830e6a472" dependencies = [ - "bytes 1.0.1", + "bytes", "fnv", "futures-core", "futures-sink", @@ -1081,41 +927,34 @@ dependencies = [ "http", "indexmap", "slab", - "tokio 1.5.0", - "tokio-util 0.6.6", + "tokio", + "tokio-util", "tracing", ] [[package]] name = "hashbrown" -version = "0.8.2" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b62f79061a0bc2e046024cb7ba44b08419ed238ecbd9adbd787434b9e8c25" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" dependencies = [ "ahash", - "autocfg", ] [[package]] -name = "hashbrown" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" - -[[package]] name = "heck" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cbf45460356b7deeb5e3415b5563308c0a9b057c85e12b06ad551f98d0a6ac" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" dependencies = [ "unicode-segmentation", ] [[package]] name = "hermit-abi" -version = "0.1.18" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" dependencies = [ "libc", ] @@ -1127,17 +966,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] -name = "hostname" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" -dependencies = [ - "libc", - "match_cfg", - "winapi 0.3.9", -] - -[[package]] name = "html5ever" version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1157,53 +985,59 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "527e8c9ac747e28542699a951517aa9a6945af506cd1f2e1b53a576c17b6cc11" dependencies = [ - "bytes 1.0.1", + "bytes", "fnv", "itoa", ] [[package]] name = "http-body" -version = "0.4.1" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfb77c123b4e2f72a2069aeae0b4b4949cc7e966df277813fc16347e7549737" +checksum = "399c583b2979440c60be0821a6199eca73bc3c8dcd9d070d75ac726e2c6186e5" dependencies = [ - "bytes 1.0.1", + "bytes", "http", - "pin-project-lite 0.2.6", + "pin-project-lite", ] [[package]] +name = "http-range" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eee9694f83d9b7c09682fdb32213682939507884e5bcf227be9aff5d644b90dc" + +[[package]] name = "httparse" -version = "1.4.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a1ce40d6fc9764887c2fdc7305c3dcc429ba11ff981c1509416afd5697e4437" +checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503" [[package]] name = "httpdate" -version = "0.3.2" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "494b4d60369511e7dea41cf646832512a94e542f68bb9c49e54518e0f468eb47" +checksum = "6456b8a6c8f33fee7d958fcd1b60d55b11940a79e63ae87013e6d22e26034440" [[package]] name = "hyper" -version = "0.14.5" +version = "0.14.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bf09f61b52cfcf4c00de50df88ae423d6c02354e385a86341133b5338630ad1" +checksum = "13f67199e765030fa08fe0bd581af683f0d5bc04ea09c2b1102012c5fb90e7fd" dependencies = [ - "bytes 1.0.1", + "bytes", "futures-channel", "futures-core", "futures-util", - "h2 0.3.2", + "h2", "http", "http-body", "httparse", "httpdate", "itoa", - "pin-project 1.0.7", - "socket2 0.4.0", - "tokio 1.5.0", + "pin-project-lite", + "socket2", + "tokio", "tower-service", "tracing", "want", @@ -1219,7 +1053,7 @@ dependencies = [ "hyper", "log", "rustls", - "tokio 1.5.0", + "tokio", "tokio-rustls", "webpki", ] @@ -1237,9 +1071,9 @@ dependencies = [ [[package]] name = "ignore" -version = "0.4.17" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b287fb45c60bb826a0dc68ff08742b9d88a2fea13d6e0c286b3172065aaf878c" +checksum = "713f1b139373f96a2e0ce3ac931cd01ee973c3c5dd7c40c0c2efe96ad2b6751d" dependencies = [ "crossbeam-utils", "globset", @@ -1255,88 +1089,75 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.6.2" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3" +checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" dependencies = [ "autocfg", - "hashbrown 0.9.1", + "hashbrown", ] [[package]] name = "instant" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" +checksum = "bee0328b1209d157ef001c94dd85b4f8f64139adb0eac2659f4b08382b2f474d" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] -name = "iovec" -version = "0.1.4" +name = "ipnet" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" -dependencies = [ - "libc", -] +checksum = "68f2d64f2edebec4ce84ad108148e67e1064789bee435edc5b60ad398714a3a9" [[package]] -name = "ipconfig" -version = "0.2.2" +name = "itertools" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7e2f18aece9709094573a9f24f483c4f65caa4298e2f7ae1b71cc65d853fad7" +checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf" dependencies = [ - "socket2 0.3.19", - "widestring", - "winapi 0.3.9", - "winreg 0.6.2", + "either", ] [[package]] -name = "ipnet" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47be2f14c678be2fdcab04ab1171db51b2762ce6f0a8ee87c8dd4a04ed216135" - -[[package]] name = "itoa" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" [[package]] -name = "js-sys" -version = "0.3.50" +name = "jobserver" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d99f9e3e84b8f67f846ef5b4cbbc3b1c29f6c759fcbce6f01aa0e73d932a24c" +checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa" dependencies = [ - "wasm-bindgen", + "libc", ] [[package]] -name = "kernel32-sys" -version = "0.2.2" +name = "js-sys" +version = "0.3.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +checksum = "e4bf49d50e2961077d9c99f4b7997d770a1114f087c3c2e0069b36c13fc2979d" dependencies = [ - "winapi 0.2.8", - "winapi-build", + "wasm-bindgen", ] [[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 = "lasso" -version = "0.3.1" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf1a626ea51398f5acf36666c8046ff4bfd048aab88e92db676d2a6eac8805d0" +checksum = "e8647c8a01e5f7878eacb2c323c4c949fdb63773110f0686c7810769874b7e0a" dependencies = [ - "hashbrown 0.8.2", + "hashbrown", ] [[package]] @@ -1347,9 +1168,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.93" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9385f66bf6105b241aa65a61cb923ef20efc665cb9f9bb50ac2f0c4b7f378d41" +checksum = "3cb00336871be5ed2c8ed44b60ae9959dc5b9f08539422ed43f09e34ecaeba21" [[package]] name = "libflate" @@ -1372,16 +1193,28 @@ dependencies = [ ] [[package]] -name = "linked-hash-map" -version = "0.5.4" +name = "local-channel" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6246c68cf195087205a0512559c97e15eaf95198bf0e206d662092cdcb03fe9f" +dependencies = [ + "futures-core", + "futures-sink", + "futures-util", + "local-waker", +] + +[[package]] +name = "local-waker" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" +checksum = "84f9a2d3e27ce99ce2c3aad0b09b1a7b916293ea9b2bf624c13fe646fadd8da4" [[package]] name = "lock_api" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3c91c24eae6777794bb1997ad98bbb87daf92890acab859f7eaa4320333176" +checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" dependencies = [ "scopeguard", ] @@ -1392,16 +1225,7 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" dependencies = [ - "cfg-if 1.0.0", -] - -[[package]] -name = "lru-cache" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" -dependencies = [ - "linked-hash-map", + "cfg-if", ] [[package]] @@ -1412,16 +1236,13 @@ checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" [[package]] name = "markup5ever" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aae38d669396ca9b707bfc3db254bc382ddb94f57cc5c235f34623a669a01dab" +checksum = "a24f40fb03852d1cdd84330cddcaf98e9ec08a7b7768e952fad3b4cf048ec8fd" dependencies = [ "log", - "phf", + "phf 0.8.0", "phf_codegen", - "serde", - "serde_derive", - "serde_json", "string_cache", "string_cache_codegen", "tendril", @@ -1440,16 +1261,10 @@ dependencies = [ ] [[package]] -name = "match_cfg" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" - -[[package]] name = "matches" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" [[package]] name = "maud" @@ -1457,8 +1272,6 @@ version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da0784808b0c06f80365c1071048df9b6414a83fc56b8d4b305859e39f5162fa" dependencies = [ - "actix-web", - "futures-util", "maud_htmlescape", "maud_macros", ] @@ -1484,9 +1297,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" [[package]] name = "mime" @@ -1505,17 +1318,18 @@ dependencies = [ [[package]] name = "miniserve" -version = "0.14.1-alpha.0" +version = "0.15.1-alpha.0" dependencies = [ "actix-files", "actix-multipart", "actix-web", "actix-web-httpauth", "alphanumeric-sort", + "anyhow", "assert_cmd", "assert_fs", "atty", - "bytes 1.0.1", + "bytes", "bytesize", "chrono", "chrono-humanize", @@ -1531,11 +1345,13 @@ dependencies = [ "nanoid", "percent-encoding", "port_check", + "predicates", "pretty_assertions", "qrcodegen", "regex", "reqwest", "rstest", + "rustls", "select", "serde", "sha2", @@ -1562,57 +1378,15 @@ dependencies = [ [[package]] name = "mio" -version = "0.6.23" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" +checksum = "8c2bdb6314ec10835cd3293dd268473a835c02b7b352e788be788b3c6ca6bb16" dependencies = [ - "cfg-if 0.1.10", - "fuchsia-zircon", - "fuchsia-zircon-sys", - "iovec", - "kernel32-sys", "libc", "log", - "miow 0.2.2", - "net2", - "slab", - "winapi 0.2.8", -] - -[[package]] -name = "mio" -version = "0.7.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf80d3e903b34e0bd7282b218398aec54e082c840d9baf8339e0080a0c542956" -dependencies = [ - "libc", - "log", - "miow 0.3.7", + "miow", "ntapi", - "winapi 0.3.9", -] - -[[package]] -name = "mio-uds" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0" -dependencies = [ - "iovec", - "libc", - "mio 0.6.23", -] - -[[package]] -name = "miow" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" -dependencies = [ - "kernel32-sys", - "net2", - "winapi 0.2.8", - "ws2_32-sys", + "winapi", ] [[package]] @@ -1621,7 +1395,7 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" dependencies = [ - "winapi 0.3.9", + "winapi", ] [[package]] @@ -1630,18 +1404,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ffa00dec017b5b1a8b7cf5e2c008bfda1aa7e0697ac1508b491fdf2622fb4d8" dependencies = [ - "rand 0.8.3", -] - -[[package]] -name = "net2" -version = "0.2.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae" -dependencies = [ - "cfg-if 0.1.10", - "libc", - "winapi 0.3.9", + "rand 0.8.4", ] [[package]] @@ -1651,16 +1414,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" [[package]] -name = "nom" -version = "4.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6" -dependencies = [ - "memchr", - "version_check 0.1.5", -] - -[[package]] name = "normalize-line-endings" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1672,14 +1425,14 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" dependencies = [ - "winapi 0.3.9", + "winapi", ] [[package]] name = "num-bigint" -version = "0.3.2" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d0a3d5e207573f948a9e5376662aa743a2ea13f7c50a554d7af443a73fbfeba" +checksum = "76e97c412795abf6c24ba30055a8f20642ea57ca12875220b854cfa501bf1e48" dependencies = [ "autocfg", "num-integer", @@ -1698,9 +1451,9 @@ dependencies = [ [[package]] name = "num-rational" -version = "0.3.2" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" +checksum = "d41702bd167c2df5520b384281bc111a4b5efcf7fbc4c9c222c815b07e0a6a6a" dependencies = [ "autocfg", "num-bigint", @@ -1729,9 +1482,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.7.2" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3" +checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" [[package]] name = "opaque-debug" @@ -1745,14 +1498,14 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9" dependencies = [ - "winapi 0.3.9", + "winapi", ] [[package]] name = "parking_lot" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" dependencies = [ "instant", "lock_api", @@ -1761,26 +1514,23 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018" +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "instant", "libc", "redox_syscall", "smallvec", - "winapi 0.3.9", + "winapi", ] [[package]] -name = "peekmore" -version = "0.5.6" +name = "paste" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4089f831c514cbf080bd19bfce702f7a2de250492730d419204af6710ba19316" -dependencies = [ - "smallvec", -] +checksum = "acbf547ad0c65e31259204bd90935776d1c693cec2f4ff7abb7a1bbbd40dfe58" [[package]] name = "percent-encoding" @@ -1803,8 +1553,17 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" dependencies = [ + "phf_shared 0.8.0", +] + +[[package]] +name = "phf" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ac8b67553a7ca9457ce0e526948cad581819238f4a9d1ea74545851fa24f37" +dependencies = [ "phf_macros", - "phf_shared", + "phf_shared 0.9.0", "proc-macro-hack", ] @@ -1814,8 +1573,8 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815" dependencies = [ - "phf_generator", - "phf_shared", + "phf_generator 0.8.0", + "phf_shared 0.8.0", ] [[package]] @@ -1824,18 +1583,28 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" dependencies = [ - "phf_shared", + "phf_shared 0.8.0", "rand 0.7.3", ] [[package]] +name = "phf_generator" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d43f3220d96e0080cc9ea234978ccd80d904eafb17be31bb0f76daaea6493082" +dependencies = [ + "phf_shared 0.9.0", + "rand 0.8.4", +] + +[[package]] name = "phf_macros" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6fde18ff429ffc8fe78e2bf7f8b7a5a5a6e2a8b58bc5a9ac69198bbda9189c" +checksum = "b706f5936eb50ed880ae3009395b43ed19db5bff2ebd459c95e7bf013a89ab86" dependencies = [ - "phf_generator", - "phf_shared", + "phf_generator 0.9.1", + "phf_shared 0.9.0", "proc-macro-hack", "proc-macro2", "quote", @@ -1852,39 +1621,28 @@ dependencies = [ ] [[package]] -name = "pin-project" -version = "0.4.28" +name = "phf_shared" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "918192b5c59119d51e0cd221f4d49dde9112824ba717369e903c97d076083d0f" +checksum = "a68318426de33640f02be62b4ae8eb1261be2efbc337b60c54d845bf4484e0d9" dependencies = [ - "pin-project-internal 0.4.28", + "siphasher", ] [[package]] name = "pin-project" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7509cc106041c40a4518d2af7a61530e1eed0e6285296a3d8c5472806ccc4a4" -dependencies = [ - "pin-project-internal 1.0.7", -] - -[[package]] -name = "pin-project-internal" -version = "0.4.28" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be26700300be6d9d23264c73211d8190e755b6b5ca7a1b28230025511b52a5e" +checksum = "576bc800220cc65dac09e99e97b08b358cfab6e17078de8dc5fee223bd2d0c08" dependencies = [ - "proc-macro2", - "quote", - "syn", + "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c950132583b500556b1efd71d45b319029f2b71518d979fcc208e16b42426f" +checksum = "6e8fe8163d14ce7f0cdac2e040116f22eac817edabff0be91e8aff7e9accf389" dependencies = [ "proc-macro2", "quote", @@ -1893,15 +1651,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777" - -[[package]] -name = "pin-project-lite" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc0e1f259c92177c30a4c9d177246edd0a3568b25756a977d0632cf8fa37e905" +checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" [[package]] name = "pin-utils" @@ -1935,12 +1687,13 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] name = "predicates" -version = "1.0.7" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eeb433456c1a57cc93554dea3ce40b4c19c4057e41c55d4a0f3d84ea71c325aa" +checksum = "c143348f141cc87aab5b950021bac6145d0e5ae754b0591de23244cee42c9308" dependencies = [ - "difference", + "difflib", "float-cmp", + "itertools", "normalize-line-endings", "predicates-core", "regex", @@ -1954,9 +1707,9 @@ checksum = "57e35a3326b75e49aa85f5dc6ec15b41108cf5aee58eabb1f274dd18b73c2451" [[package]] name = "predicates-tree" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15f553275e5721409451eb85e15fd9a860a6e5ab4496eb215987502b5f5391f2" +checksum = "d7dd0fd014130206c9352efbdc92be592751b2b9274dff685348341082c6ea3d" dependencies = [ "predicates-core", "treeline", @@ -1984,7 +1737,7 @@ dependencies = [ "proc-macro2", "quote", "syn", - "version_check 0.9.3", + "version_check", ] [[package]] @@ -1995,7 +1748,7 @@ checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ "proc-macro2", "quote", - "version_check 0.9.3", + "version_check", ] [[package]] @@ -2012,24 +1765,18 @@ checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" [[package]] name = "proc-macro2" -version = "1.0.26" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" +checksum = "5c7ed8b8c7b886ea3ed7dde405212185f423ab44682667c8c6dd14aa1d9f6612" dependencies = [ "unicode-xid", ] [[package]] name = "qrcodegen" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d24ea38b2345f15533e6668104bec0136883404287e095f15f9ea2522e2b4b6c" - -[[package]] -name = "quick-error" -version = "1.2.3" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" +checksum = "135e6754eed8ca897dd70584d895e72e36860b3e163b6bcedce48571cbaef343" [[package]] name = "quote" @@ -2056,14 +1803,14 @@ dependencies = [ [[package]] name = "rand" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" +checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" dependencies = [ "libc", - "rand_chacha 0.3.0", - "rand_core 0.6.2", - "rand_hc 0.3.0", + "rand_chacha 0.3.1", + "rand_core 0.6.3", + "rand_hc 0.3.1", ] [[package]] @@ -2078,12 +1825,12 @@ dependencies = [ [[package]] name = "rand_chacha" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core 0.6.2", + "rand_core 0.6.3", ] [[package]] @@ -2097,11 +1844,11 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" dependencies = [ - "getrandom 0.2.2", + "getrandom 0.2.3", ] [[package]] @@ -2115,11 +1862,11 @@ dependencies = [ [[package]] name = "rand_hc" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" +checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" dependencies = [ - "rand_core 0.6.2", + "rand_core 0.6.3", ] [[package]] @@ -2133,18 +1880,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.6" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8270314b5ccceb518e7e578952f0b72b88222d02e8f77f5ecf7abbb673539041" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" dependencies = [ "bitflags", ] [[package]] name = "regex" -version = "1.5.3" +version = "1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce5f1ceb7f74abbce32601642fcf8e8508a8a8991e0621c7d750295b9095702b" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" dependencies = [ "aho-corasick", "memchr", @@ -2153,12 +1900,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae1ded71d66a4a97f5e961fd0cb25a5f366a42a41570d16a763a69c092c26ae4" -dependencies = [ - "byteorder", -] +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" [[package]] name = "regex-syntax" @@ -2172,17 +1916,17 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" dependencies = [ - "winapi 0.3.9", + "winapi", ] [[package]] name = "reqwest" -version = "0.11.3" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2296f2fac53979e8ccbc4a1136b25dcefd37be9ed7e4a1f6b05a6029c84ff124" +checksum = "246e9f61b9bb77df069a947682be06e31ac43ea37862e244a69f177694ea6d22" dependencies = [ "base64", - "bytes 1.0.1", + "bytes", "encoding_rs", "futures-core", "futures-util", @@ -2197,28 +1941,18 @@ dependencies = [ "mime", "mime_guess", "percent-encoding", - "pin-project-lite 0.2.6", + "pin-project-lite", "rustls", "serde", "serde_urlencoded", - "tokio 1.5.0", + "tokio", "tokio-rustls", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", "webpki-roots", - "winreg 0.7.0", -] - -[[package]] -name = "resolv-conf" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00" -dependencies = [ - "hostname", - "quick-error", + "winreg", ] [[package]] @@ -2233,7 +1967,7 @@ dependencies = [ "spin", "untrusted", "web-sys", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -2244,14 +1978,14 @@ checksum = "cabe4fa914dec5870285fa7f71f602645da47c486e68486d2b4ceb4a343e90ac" [[package]] name = "rstest" -version = "0.9.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c77c86a545c460cffcb2e5f558392e2e6a1edcc9d463cf092bf4ec3c7990641d" +checksum = "2288c66aeafe3b2ed227c981f364f9968fa952ef0b30e84ada4486e7ee24d00a" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "proc-macro2", "quote", - "rustc_version 0.3.3", + "rustc_version 0.4.0", "syn", ] @@ -2274,6 +2008,15 @@ dependencies = [ ] [[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver 1.0.4", +] + +[[package]] name = "rustls" version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2347,6 +2090,12 @@ dependencies = [ ] [[package]] +name = "semver" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012" + +[[package]] name = "semver-parser" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2363,18 +2112,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.125" +version = "1.0.130" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171" +checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.125" +version = "1.0.130" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d" +checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" dependencies = [ "proc-macro2", "quote", @@ -2383,9 +2132,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.64" +version = "1.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" +checksum = "a7f9e390c27c3c0ce8bc5d725f6e4d30a29d26659494aa4b17535f7522c5c950" dependencies = [ "itoa", "ryu", @@ -2406,13 +2155,13 @@ dependencies = [ [[package]] name = "sha-1" -version = "0.9.4" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfebf75d25bd900fd1e7d11501efab59bc846dbc76196839663e6637bba9f25f" +checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" dependencies = [ "block-buffer", - "cfg-if 1.0.0", - "cpuid-bool", + "cfg-if", + "cpufeatures", "digest", "opaque-debug", ] @@ -2425,12 +2174,12 @@ checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" [[package]] name = "sha2" -version = "0.9.4" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8f6b75b17576b792bef0db1bcc4b8b8bcdf9506744cf34b974195487af6cff2" +checksum = "9204c41a1597a8c5af23c82d1c921cb01ec0a4c59e07a9c7306062829a3903f3" dependencies = [ "block-buffer", - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", "digest", "opaque-debug", @@ -2438,9 +2187,9 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16f1d0fef1604ba8f7a073c7e701f213e056707210e9020af4528e0101ce11a6" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" dependencies = [ "libc", ] @@ -2458,15 +2207,15 @@ dependencies = [ [[package]] name = "siphasher" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbce6d4507c7e4a3962091436e56e95290cb71fa302d0d270e32130b75fbff27" +checksum = "729a25c17d72b06c68cb47955d44fda88ad2d3e7d77e025663fdd69b93dd71a1" [[package]] name = "slab" -version = "0.4.2" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" +checksum = "c307a32c1c5c437f38c7fd45d753050587732ba8628319fbdf12a7e289ccc590" [[package]] name = "smallvec" @@ -2476,23 +2225,12 @@ checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" [[package]] name = "socket2" -version = "0.3.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "winapi 0.3.9", -] - -[[package]] -name = "socket2" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e3dfc207c526015c632472a77be09cf1b6e46866581aecae5cc38fb4235dea2" +checksum = "765f090f0e423d2b55843402a07915add955e7d60657db13707a159727326cad" dependencies = [ "libc", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -2507,7 +2245,7 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff" dependencies = [ - "version_check 0.9.3", + "version_check", ] [[package]] @@ -2567,7 +2305,7 @@ checksum = "8ddb1139b5353f96e429e1a5e19fbaf663bddedaa06d1dbd49f82e352601209a" dependencies = [ "lazy_static", "new_debug_unreachable", - "phf_shared", + "phf_shared 0.8.0", "precomputed-hash", "serde", ] @@ -2578,8 +2316,8 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f24c8e5e19d22a726626f1a5e16fe15b132dcf21d10177fa5a45ce7962996b97" dependencies = [ - "phf_generator", - "phf_shared", + "phf_generator 0.8.0", + "phf_shared 0.8.0", "proc-macro2", "quote", ] @@ -2592,9 +2330,9 @@ checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" [[package]] name = "structopt" -version = "0.3.21" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5277acd7ee46e63e5168a80734c9f6ee81b1367a7d8772a2d765df2a3705d28c" +checksum = "69b041cdcb67226aca307e6e7be44c8806423d83e018bd662360a93dabce4d71" dependencies = [ "clap", "lazy_static", @@ -2603,9 +2341,9 @@ dependencies = [ [[package]] name = "structopt-derive" -version = "0.4.14" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ba9cdfda491b814720b6b06e0cac513d922fc407582032e8706e9f137976f90" +checksum = "7813934aecf5f51a54775e00068c237de98489463968231a51746bbbc03f9c10" dependencies = [ "heck", "proc-macro-error", @@ -2616,15 +2354,15 @@ dependencies = [ [[package]] name = "strum" -version = "0.20.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7318c509b5ba57f18533982607f24070a55d353e90d4cae30c467cdb2ad5ac5c" +checksum = "aaf86bbcfd1fa9670b7a129f64fc0c9fcbbfe4f1bc4210e9e98fe71ffc12cde2" [[package]] name = "strum_macros" -version = "0.20.1" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee8bc6b87a5112aeeab1f4a9f7ab634fe6cbefc4850006df31267f4cfb9e3149" +checksum = "d06aaeeee809dbc59eb4556183dd927df67db1540de5be8d3ec0b6636358a5ec" dependencies = [ "heck", "proc-macro2", @@ -2634,9 +2372,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.71" +version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad184cc9470f9117b2ac6817bfe297307418819ba40552f9b3846f05c33d5373" +checksum = "b7f58f7e8eaa0009c5fec437aabf511bd9933e4b2d7407bd05273c01a8906ea7" dependencies = [ "proc-macro2", "quote", @@ -2645,9 +2383,9 @@ dependencies = [ [[package]] name = "tar" -version = "0.4.33" +version = "0.4.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0bcfbd6a598361fda270d82469fff3d65089dc33e175c9a131f7b4cd395f228" +checksum = "d6f5515d3add52e0bbdcad7b83c388bb36ba7b754dda3b5f5bc2d38640cdba5c" dependencies = [ "filetime", "libc", @@ -2660,12 +2398,12 @@ version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", - "rand 0.8.3", + "rand 0.8.4", "redox_syscall", "remove_dir_all", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -2699,18 +2437,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.24" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e" +checksum = "e1c319f97498ee34e17e1d7813fcd28a0ec1aaf350a4c44883d2fe741edb1c70" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.24" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0" +checksum = "8bf955fbafde33573fd32e90312488fa2ea68f7a220a5faab1809fa90690224f" dependencies = [ "proc-macro2", "quote", @@ -2727,37 +2465,28 @@ dependencies = [ ] [[package]] -name = "threadpool" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" -dependencies = [ - "num_cpus", -] - -[[package]] name = "time" version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" dependencies = [ "libc", - "winapi 0.3.9", + "winapi", ] [[package]] name = "time" -version = "0.2.26" +version = "0.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08a8cbfbf47955132d0202d1662f49b2423ae35862aee471f3ba4b133358f372" +checksum = "4752a97f8eebd6854ff91f1c1824cd6160626ac4bd44287f7f4ea2035a02a242" dependencies = [ "const_fn", "libc", "standback", "stdweb", "time-macros", - "version_check 0.9.3", - "winapi 0.3.9", + "version_check", + "winapi", ] [[package]] @@ -2772,9 +2501,9 @@ dependencies = [ [[package]] name = "time-macros-impl" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5c3be1edfad6027c69f5491cf4cb310d1a71ecd6af742788c6ff8bced86b8fa" +checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f" dependencies = [ "proc-macro-hack", "proc-macro2", @@ -2785,9 +2514,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.2.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b5220f05bb7de7f3f53c7c065e1199b3172696fe2db9f9c4d8ad9b4ee74c342" +checksum = "848a1e1181b9f6753b5e96a092749e29b11d19ede67dfbbd6c7dc7e0f49b5338" dependencies = [ "tinyvec_macros", ] @@ -2800,37 +2529,21 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "0.2.25" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6703a273949a90131b290be1fe7b039d0fc884aa1935860dfcbe056f28cd8092" -dependencies = [ - "bytes 0.5.6", - "futures-core", - "iovec", - "lazy_static", - "libc", - "memchr", - "mio 0.6.23", - "mio-uds", - "pin-project-lite 0.1.12", - "signal-hook-registry", - "slab", - "winapi 0.3.9", -] - -[[package]] -name = "tokio" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83f0c8e7c0addab50b663055baf787d0af7f413a46e6e7fb9559a4e4db7137a5" +checksum = "92036be488bb6594459f2e03b60e42df6f937fe6ca5c5ffdcb539c6b84dc40f5" dependencies = [ "autocfg", - "bytes 1.0.1", + "bytes", "libc", "memchr", - "mio 0.7.11", + "mio", "num_cpus", - "pin-project-lite 0.2.6", + "once_cell", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "winapi", ] [[package]] @@ -2840,36 +2553,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6" dependencies = [ "rustls", - "tokio 1.5.0", + "tokio", "webpki", ] [[package]] name = "tokio-util" -version = "0.3.1" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be8242891f2b6cbef26a2d7e8605133c2c554cd35b3e4948ea892d6d68436499" +checksum = "1caa0b0c8d94a049db56b5acf8cba99dc0623aab1b26d5b5f5e2d945846b3592" dependencies = [ - "bytes 0.5.6", + "bytes", "futures-core", "futures-sink", "log", - "pin-project-lite 0.1.12", - "tokio 0.2.25", -] - -[[package]] -name = "tokio-util" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "940a12c99365c31ea8dd9ba04ec1be183ffe4920102bb7122c2f515437601e8e" -dependencies = [ - "bytes 1.0.1", - "futures-core", - "futures-sink", - "log", - "pin-project-lite 0.2.6", - "tokio 1.5.0", + "pin-project-lite", + "tokio", ] [[package]] @@ -2880,81 +2579,31 @@ checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" [[package]] name = "tracing" -version = "0.1.25" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01ebdc2bb4498ab1ab5f5b73c5803825e60199229ccba0698170e3be0e7f959f" +checksum = "09adeb8c97449311ccd28a427f96fb563e7fd31aabf994189879d9da2394b89d" dependencies = [ - "cfg-if 1.0.0", - "log", - "pin-project-lite 0.2.6", + "cfg-if", + "pin-project-lite", "tracing-core", ] [[package]] name = "tracing-core" -version = "0.1.17" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f50de3927f93d202783f4513cda820ab47ef17f624b03c096e86ef00c67e6b5f" +checksum = "2ca517f43f0fb96e0c3072ed5c275fe5eece87e8cb52f4a77b69226d3b1c9df8" dependencies = [ "lazy_static", ] [[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.7", - "tracing", -] - -[[package]] name = "treeline" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7f741b240f1a48843f9b8e0444fb55fb2a4ff67293b50a9179dfd5ea67f8d41" [[package]] -name = "trust-dns-proto" -version = "0.19.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cad71a0c0d68ab9941d2fb6e82f8fb2e86d9945b94e1661dd0aaea2b88215a9" -dependencies = [ - "async-trait", - "cfg-if 1.0.0", - "enum-as-inner", - "futures", - "idna", - "lazy_static", - "log", - "rand 0.7.3", - "smallvec", - "thiserror", - "tokio 0.2.25", - "url", -] - -[[package]] -name = "trust-dns-resolver" -version = "0.19.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "710f593b371175db53a26d0b38ed2978fafb9e9e8d3868b1acd753ea18df0ceb" -dependencies = [ - "cfg-if 0.1.10", - "futures", - "ipconfig", - "lazy_static", - "log", - "lru-cache", - "resolv-conf", - "smallvec", - "thiserror", - "tokio 0.2.25", - "trust-dns-proto", -] - -[[package]] name = "try-lock" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2962,9 +2611,9 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" [[package]] name = "twoway" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b40075910de3a912adbd80b5d8bad6ad10a23eeb1f5bf9d4006839e899ba5bc" +checksum = "c57ffb460d7c24cd6eda43694110189030a3d1dfe418416d9468fd1c1d290b47" dependencies = [ "memchr", "unchecked-index", @@ -2994,32 +2643,29 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" dependencies = [ - "version_check 0.9.3", + "version_check", ] [[package]] name = "unicode-bidi" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eeb8be209bb1c96b7c177c7420d26e04eccacb0eeae6b980e35fcb74678107e0" -dependencies = [ - "matches", -] +checksum = "246f4c42e67e7a4e3c6106ff716a5d067d4132a642840b242e357e468a2a0085" [[package]] name = "unicode-normalization" -version = "0.1.17" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07fbfce1c8a97d547e8b5334978438d9d6ec8c20e38f56d4a4374d181493eaef" +checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" dependencies = [ "tinyvec", ] [[package]] name = "unicode-segmentation" -version = "1.7.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" +checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" [[package]] name = "unicode-width" @@ -3029,9 +2675,9 @@ checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" [[package]] name = "unicode-xid" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" [[package]] name = "untrusted" @@ -3041,9 +2687,9 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] name = "url" -version = "2.2.1" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ccd964113622c8e9322cfac19eb1004a07e636c545f325da085d5cdde6f1f8b" +checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" dependencies = [ "form_urlencoded", "idna", @@ -3058,38 +2704,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" [[package]] -name = "v_escape" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3e0ab5fab1db278a9413d2ea794cb66f471f898c5b020c3c394f6447625d9d4" -dependencies = [ - "buf-min", - "v_escape_derive", -] - -[[package]] -name = "v_escape_derive" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c860ad1273f4eee7006cee05db20c9e60e5d24cba024a32e1094aa8e574f3668" -dependencies = [ - "nom", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "v_htmlescape" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f9a8af610ad6f7fc9989c9d2590d9764bc61f294884e9ee93baa58795174572" -dependencies = [ - "cfg-if 1.0.0", - "v_escape", -] - -[[package]] name = "vec_map" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3097,12 +2711,6 @@ checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" [[package]] name = "version_check" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" - -[[package]] -name = "version_check" version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" @@ -3123,7 +2731,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" dependencies = [ "same-file", - "winapi 0.3.9", + "winapi", "winapi-util", ] @@ -3151,11 +2759,11 @@ checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" [[package]] name = "wasm-bindgen" -version = "0.2.73" +version = "0.2.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83240549659d187488f91f33c0f8547cbfef0b2088bc470c116d1d260ef623d9" +checksum = "8ce9b1b516211d33767048e5d47fa2a381ed8b76fc48d2ce4aa39877f9f183e0" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "serde", "serde_json", "wasm-bindgen-macro", @@ -3163,9 +2771,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.73" +version = "0.2.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae70622411ca953215ca6d06d3ebeb1e915f0f6613e3b495122878d7ebec7dae" +checksum = "cfe8dc78e2326ba5f845f4b5bf548401604fa20b1dd1d365fb73b6c1d6364041" dependencies = [ "bumpalo", "lazy_static", @@ -3178,11 +2786,11 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.23" +version = "0.4.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81b8b767af23de6ac18bf2168b690bed2902743ddf0fb39252e36f9e2bfc63ea" +checksum = "95fded345a6559c2cfee778d562300c581f7d4ff3edb9b0d230d69800d213972" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "js-sys", "wasm-bindgen", "web-sys", @@ -3190,9 +2798,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.73" +version = "0.2.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e734d91443f177bfdb41969de821e15c516931c3c3db3d318fa1b68975d0f6f" +checksum = "44468aa53335841d9d6b6c023eaab07c0cd4bddbcfdee3e2bb1e8d2cb8069fef" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3200,9 +2808,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.73" +version = "0.2.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53739ff08c8a68b0fdbcd54c372b8ab800b1449ab3c9d706503bc7dd1621b2c" +checksum = "0195807922713af1e67dc66132c7328206ed9766af3858164fb583eedc25fbad" dependencies = [ "proc-macro2", "quote", @@ -3213,15 +2821,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.73" +version = "0.2.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9a543ae66aa233d14bb765ed9af4a33e81b8b58d1584cf1b47ff8cd0b9e4489" +checksum = "acdb075a845574a1fa5f09fd77e43f7747599301ea3417a9fbffdeedfc1f4a29" [[package]] name = "web-sys" -version = "0.3.50" +version = "0.3.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a905d57e488fec8861446d3393670fb50d27a262344013181c2cdf9fff5481be" +checksum = "224b2f6b67919060055ef1a67807367c2066ed520c3862cc013d26cf893a783c" dependencies = [ "js-sys", "wasm-bindgen", @@ -3247,18 +2855,6 @@ dependencies = [ ] [[package]] -name = "widestring" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c168940144dd21fd8046987c16a46a33d5fc84eec29ef9dcddc2ac9e31526b7c" - -[[package]] -name = "winapi" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" - -[[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3269,12 +2865,6 @@ dependencies = [ ] [[package]] -name = "winapi-build" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" - -[[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3286,7 +2876,7 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" dependencies = [ - "winapi 0.3.9", + "winapi", ] [[package]] @@ -3297,30 +2887,11 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "winreg" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2986deb581c4fe11b621998a5e53361efe6b48a151178d0cd9eeffa4dc6acc9" -dependencies = [ - "winapi 0.3.9", -] - -[[package]] -name = "winreg" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69" dependencies = [ - "winapi 0.3.9", -] - -[[package]] -name = "ws2_32-sys" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" -dependencies = [ - "winapi 0.2.8", - "winapi-build", + "winapi", ] [[package]] @@ -3352,9 +2923,9 @@ checksum = "9fc79f4a1e39857fc00c3f662cbf2651c771f00e9c15fe2abc341806bd46bd71" [[package]] name = "zip" -version = "0.5.12" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c83dc9b784d252127720168abd71ea82bf8c3d96b17dc565b5e2a02854f2b27" +checksum = "93ab48844d61251bb3835145c521d88aa4031d7139e8485990f60ca911fa0815" dependencies = [ "byteorder", "bzip2", @@ -3363,3 +2934,32 @@ dependencies = [ "thiserror", "time 0.1.43", ] + +[[package]] +name = "zstd" +version = "0.7.0+zstd.1.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9428752481d8372e15b1bf779ea518a179ad6c771cca2d2c60e4fbff3cc2cd52" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "3.1.0+zstd.1.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa1926623ad7fe406e090555387daf73db555b948134b4d73eac5eb08fb666d" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "1.5.0+zstd.1.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e6c094340240369025fc6b731b054ee2a834328fa584310ac96aa4baebdc465" +dependencies = [ + "cc", + "libc", +] @@ -1,6 +1,6 @@ [package] name = "miniserve" -version = "0.14.1-alpha.0" +version = "0.15.1-alpha.0" description = "For when you really just want to serve some files over HTTP right now!" authors = ["Sven-Hendrik Haase <svenstaro@gmail.com>", "Boastful Squirrel <boastful.squirrel@gmail.com>"] repository = "https://github.com/svenstaro/miniserve" @@ -9,6 +9,7 @@ readme = "README.md" keywords = ["serve", "http-server", "static-files", "http", "server"] categories = ["command-line-utilities", "network-programming", "web-programming::http-server"] edition = "2018" +resolver = "2" [profile.release] lto = true @@ -17,11 +18,11 @@ codegen-units = 1 panic = 'abort' [dependencies] -actix-web = "3" -actix-files = "0.5" -actix-multipart = "0.3" -actix-web-httpauth = "0.5" -maud = { version = "0.22", features = ["actix-web"] } +actix-web = "4.0.0-beta.8" +actix-files = "0.6.0-beta.6" +actix-multipart = "0.4.0-beta.5" +actix-web-httpauth = "0.6.0-beta.2" +maud = "0.22" yansi = "0.5" simplelog = "0.10" percent-encoding = "2" @@ -37,9 +38,10 @@ tar = "0.4" futures = "0.3" libflate = "1" thiserror = "1" +anyhow = "1" log = "0.4" -strum = "0.20" -strum_macros = "0.20" +strum = "0.21" +strum_macros = "0.21" sha2 = "0.9" hex = "0.4" zip = "0.5.11" @@ -49,16 +51,26 @@ httparse = "1" http = "0.2" bytes = "1" atty = "0.2" +rustls = { version = "0.19", optional = true } + +[features] +default = ["tls"] +# This feature allows us to use rustls only on architectures supported by ring. +# See also https://github.com/briansmith/ring/issues/1182 +# and https://github.com/briansmith/ring/issues/562 +# and https://github.com/briansmith/ring/issues/1367 +tls = ["rustls", "actix-web/rustls"] [dev-dependencies] -assert_cmd = "1" +assert_cmd = "2" reqwest = { version = "0.11", features = ["blocking", "multipart", "rustls-tls"], default-features = false } assert_fs = "1" select = "0.5" -rstest = "0.9" +rstest = "0.11" regex = "1" pretty_assertions = "0.7" url = "2" +predicates = "2" [build-dependencies] grass = "0.10" @@ -49,6 +49,10 @@ Sometimes this is just a more practical and quick way than doing things properly miniserve -i 192.168.0.1 -i 10.13.37.10 -i ::1 /tmp/myshare +### Start with TLS: + + miniserve --tls-cert my.cert --tls-key my.key /tmp/myshare + ### Upload a file using `curl`: # in one terminal @@ -71,10 +75,11 @@ Sometimes this is just a more practical and quick way than doing things properly - Scan QR code for quick access - Shell completions - Sane and secure defaults +- TLS (for supported architectures) ## Usage - miniserve 0.14.0 + miniserve 0.15.0 Sven-Hendrik Haase <svenstaro@gmail.com>, Boastful Squirrel <boastful.squirrel@gmail.com> For when you really just want to serve some files over HTTP right now! @@ -102,6 +107,12 @@ Sometimes this is just a more practical and quick way than doing things properly -h, --help Prints help information + -H, --hidden + Show hidden files + + -F, --hide-version-footer + Hide version footer + -P, --no-symlinks Do not follow symbolic links @@ -134,6 +145,7 @@ Sometimes this is just a more practical and quick way than doing things properly zenburn, monokai] --header <header>... Set custom header for responses + --index <index_file> The name of a directory index file to serve, like "index.html" @@ -151,6 +163,12 @@ Sometimes this is just a more practical and quick way than doing things properly -t, --title <title> Shown instead of host in page title and heading + --tls-cert <tls-cert> + TLS certificate to use + + --tls-key <tls-key> + TLS private key to use + ARGS: <PATH> @@ -169,6 +187,10 @@ Alternatively, if you are on **Arch Linux**, you can do pacman -S miniserve +On [Termux](https://termux.com/) + + pkg install miniserve + **On OSX**: Download `miniserve-osx` from [the releases page](https://github.com/svenstaro/miniserve/releases) and run chmod +x miniserve-osx @@ -199,7 +221,7 @@ If you'd like to make use of the built-in shell completion support, you need to few examples with common paths are provided below: # For bash - miniserve --print-completions bash > ~/.local/share/bash-completion/miniserve + miniserve --print-completions bash > ~/.local/share/bash-completion/completions/miniserve # For zsh miniserve --print-completions zsh > /usr/local/share/zsh/site-functions/_miniserve # For fish diff --git a/data/style.scss b/data/style.scss index 0d07515..0a69222 100644 --- a/data/style.scss +++ b/data/style.scss @@ -129,7 +129,6 @@ nav p + * { left: 0; right: 0; top: 100%; - animation: show 0.5s ease; } @keyframes show { diff --git a/src/args.rs b/src/args.rs index 819618f..cea5658 100644 --- a/src/args.rs +++ b/src/args.rs @@ -133,6 +133,16 @@ pub struct CliArgs { /// Generate completion file for a shell #[structopt(long = "print-completions", value_name = "shell", possible_values = &structopt::clap::Shell::variants())] pub print_completions: Option<structopt::clap::Shell>, + + /// TLS certificate to use + #[cfg(feature = "tls")] + #[structopt(long = "tls-cert", requires = "tls-key")] + pub tls_cert: Option<PathBuf>, + + /// TLS private key to use + #[cfg(feature = "tls")] + #[structopt(long = "tls-key", requires = "tls-cert")] + pub tls_key: Option<PathBuf>, } /// Checks wether an interface is valid, i.e. it can be parsed into an IP address diff --git a/src/auth.rs b/src/auth.rs index 1a913d5..7c77758 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -1,8 +1,9 @@ -use actix_web::dev::ServiceRequest; +use actix_web::dev::{Service, ServiceRequest, ServiceResponse}; use actix_web::http::{header, StatusCode}; -use actix_web::{HttpRequest, HttpResponse, Result}; -use actix_web_httpauth::extractors::basic::BasicAuth; +use actix_web::{HttpRequest, HttpResponse}; +use futures::future::Either; use sha2::{Digest, Sha256, Sha512}; +use std::future::{ready, Future}; use crate::errors::{self, ContextualError}; use crate::renderer; @@ -14,12 +15,16 @@ pub struct BasicAuthParams { pub password: String, } -impl From<BasicAuth> for BasicAuthParams { - fn from(auth: BasicAuth) -> Self { - Self { +impl BasicAuthParams { + fn try_from_request(req: &HttpRequest) -> actix_web::Result<Self> { + use actix_web::http::header::Header; + use actix_web_httpauth::headers::authorization::{Authorization, Basic}; + + let auth = Authorization::<Basic>::parse(req)?.into_scheme(); + Ok(Self { username: auth.user_id().to_string(), password: auth.password().unwrap_or(&"".into()).to_string(), - } + }) } } @@ -72,25 +77,48 @@ pub fn get_hash<T: Digest>(text: &str) -> Vec<u8> { hasher.finalize().to_vec() } -pub async fn handle_auth(req: ServiceRequest, cred: BasicAuth) -> Result<ServiceRequest> { +/// When authentication succedes, return the request to be passed to downstream services. +/// Otherwise, return an error response +fn handle_auth(req: ServiceRequest) -> Result<ServiceRequest, ServiceResponse> { let (req, pl) = req.into_parts(); let required_auth = &req.app_data::<crate::MiniserveConfig>().unwrap().auth; - if match_auth(cred.into(), required_auth) { - Ok(ServiceRequest::from_parts(req, pl).unwrap_or_else(|_| unreachable!())) - } else { - Err(HttpResponse::Unauthorized() - .header( - header::WWW_AUTHENTICATE, - header::HeaderValue::from_static("Basic realm=\"miniserve\""), - ) - .body(build_unauthorized_response( - &req, - ContextualError::InvalidHttpCredentials, - true, - StatusCode::UNAUTHORIZED, - )) - .into()) + if required_auth.is_empty() { + // auth is disabled by configuration + return Ok(ServiceRequest::from_parts(req, pl)); + } else if let Ok(cred) = BasicAuthParams::try_from_request(&req) { + if match_auth(cred, required_auth) { + return Ok(ServiceRequest::from_parts(req, pl)); + } + } + + // auth failed; render and return the error response + let resp = HttpResponse::Unauthorized() + .append_header(( + header::WWW_AUTHENTICATE, + header::HeaderValue::from_static("Basic realm=\"miniserve\""), + )) + .body(build_unauthorized_response( + &req, + ContextualError::InvalidHttpCredentials, + true, + StatusCode::UNAUTHORIZED, + )); + + Err(ServiceResponse::new(req, resp)) +} + +pub fn auth_middleware<S>( + req: ServiceRequest, + srv: &S, +) -> impl Future<Output = actix_web::Result<ServiceResponse>> + 'static +where + S: Service<ServiceRequest, Response = ServiceResponse, Error = actix_web::Error>, + S::Future: 'static, +{ + match handle_auth(req) { + Ok(req) => Either::Left(srv.call(req)), + Err(resp) => Either::Right(ready(Ok(resp))), } } diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..e2b4c3a --- /dev/null +++ b/src/config.rs @@ -0,0 +1,192 @@ +use std::{ + fs::File, + io::BufReader, + net::{IpAddr, Ipv4Addr, Ipv6Addr}, + path::PathBuf, +}; + +use anyhow::{anyhow, Context, Result}; +use http::HeaderMap; + +#[cfg(feature = "tls")] +use rustls::internal::pemfile::{certs, pkcs8_private_keys}; + +use crate::{args::CliArgs, auth::RequiredAuth}; + +/// Possible characters for random routes +const ROUTE_ALPHABET: [char; 16] = [ + '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'a', 'b', 'c', 'd', 'e', 'f', +]; + +#[derive(Clone)] +/// Configuration of the Miniserve application +pub struct MiniserveConfig { + /// Enable verbose mode + pub verbose: bool, + + /// Path to be served by miniserve + pub path: std::path::PathBuf, + + /// Port on which miniserve will be listening + pub port: u16, + + /// IP address(es) on which miniserve will be available + pub interfaces: Vec<IpAddr>, + + /// Enable HTTP basic authentication + pub auth: Vec<RequiredAuth>, + + /// If false, miniserve will serve the current working directory + pub path_explicitly_chosen: bool, + + /// Enable symlink resolution + pub no_symlinks: bool, + + /// Show hidden files + pub show_hidden: bool, + + /// Enable random route generation + pub random_route: Option<String>, + + /// Randomly generated favicon route + pub favicon_route: String, + + /// Randomly generated css route + pub css_route: String, + + /// Default color scheme + pub default_color_scheme: String, + + /// Default dark mode color scheme + pub default_color_scheme_dark: String, + + /// The name of a directory index file to serve, like "index.html" + /// + /// Normally, when miniserve serves a directory, it creates a listing for that directory. + /// However, if a directory contains this file, miniserve will serve that file instead. + pub index: Option<std::path::PathBuf>, + + /// Enable QR code display + pub show_qrcode: bool, + + /// Enable file upload + pub file_upload: bool, + + /// Enable upload to override existing files + pub overwrite_files: bool, + + /// If false, creation of uncompressed tar archives is disabled + pub tar_enabled: bool, + + /// If false, creation of gz-compressed tar archives is disabled + pub tar_gz_enabled: bool, + + /// If false, creation of zip archives is disabled + pub zip_enabled: bool, + + /// If enabled, directories are listed first + pub dirs_first: bool, + + /// Shown instead of host in page title and heading + pub title: Option<String>, + + /// If specified, header will be added + pub header: Vec<HeaderMap>, + + /// If enabled, version footer is hidden + pub hide_version_footer: bool, + + /// If set, use provided rustls config for TLS + #[cfg(feature = "tls")] + pub tls_rustls_config: Option<rustls::ServerConfig>, + + #[cfg(not(feature = "tls"))] + pub tls_rustls_config: Option<()>, +} + +impl MiniserveConfig { + /// Parses the command line arguments + pub fn try_from_args(args: CliArgs) -> Result<Self> { + let interfaces = if !args.interfaces.is_empty() { + args.interfaces + } else { + vec![ + IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), + IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), + ] + }; + + let random_route = if args.random_route { + Some(nanoid::nanoid!(6, &ROUTE_ALPHABET)) + } else { + None + }; + + // Generate some random routes for the favicon and css so that they are very unlikely to conflict with + // real files. + let favicon_route = nanoid::nanoid!(10, &ROUTE_ALPHABET); + let css_route = nanoid::nanoid!(10, &ROUTE_ALPHABET); + + let default_color_scheme = args.color_scheme; + let default_color_scheme_dark = args.color_scheme_dark; + + let path_explicitly_chosen = args.path.is_some() || args.index.is_some(); + + let port = match args.port { + 0 => port_check::free_local_port().context("No free ports available")?, + _ => args.port, + }; + + #[cfg(feature = "tls")] + let tls_rustls_server_config = if let (Some(tls_cert), Some(tls_key)) = + (args.tls_cert, args.tls_key) + { + let mut server_config = rustls::ServerConfig::new(rustls::NoClientAuth::new()); + let cert_file = &mut BufReader::new( + File::open(&tls_cert) + .context(format!("Couldn't access TLS certificate {:?}", tls_cert))?, + ); + let key_file = &mut BufReader::new( + File::open(&tls_key).context(format!("Couldn't access TLS key {:?}", tls_key))?, + ); + let cert_chain = certs(cert_file).map_err(|_| anyhow!("Couldn't load certificates"))?; + let mut keys = + pkcs8_private_keys(key_file).map_err(|_| anyhow!("Couldn't load private key"))?; + server_config.set_single_cert(cert_chain, keys.remove(0))?; + Some(server_config) + } else { + None + }; + + #[cfg(not(feature = "tls"))] + let tls_rustls_server_config = None; + + Ok(MiniserveConfig { + verbose: args.verbose, + path: args.path.unwrap_or_else(|| PathBuf::from(".")), + port, + interfaces, + auth: args.auth, + path_explicitly_chosen, + no_symlinks: args.no_symlinks, + show_hidden: args.hidden, + random_route, + favicon_route, + css_route, + default_color_scheme, + default_color_scheme_dark, + index: args.index, + overwrite_files: args.overwrite_files, + show_qrcode: args.qrcode, + file_upload: args.file_upload, + tar_enabled: args.enable_tar, + tar_gz_enabled: args.enable_tar_gz, + zip_enabled: args.enable_zip, + dirs_first: args.dirs_first, + title: args.title, + header: args.header, + hide_version_footer: args.hide_version_footer, + tls_rustls_config: tls_rustls_server_config, + }) + } +} diff --git a/src/file_upload.rs b/src/file_upload.rs index 93b7109..6fa99ef 100644 --- a/src/file_upload.rs +++ b/src/file_upload.rs @@ -2,11 +2,10 @@ use actix_web::{ http::{header, StatusCode}, HttpRequest, HttpResponse, }; -use futures::{future, Future, FutureExt, Stream, TryStreamExt}; +use futures::TryStreamExt; use std::{ io::Write, path::{Component, PathBuf}, - pin::Pin, }; use crate::errors::{self, ContextualError}; @@ -14,88 +13,62 @@ use crate::listing::{self, SortingMethod, SortingOrder}; use crate::renderer; /// Create future to save file. -fn save_file( +async fn save_file( field: actix_multipart::Field, file_path: PathBuf, overwrite_files: bool, -) -> Pin<Box<dyn Future<Output = Result<i64, ContextualError>>>> { +) -> Result<u64, ContextualError> { if !overwrite_files && file_path.exists() { - return Box::pin(future::err(ContextualError::DuplicateFileError)); + return Err(ContextualError::DuplicateFileError); } - let mut file = match std::fs::File::create(&file_path) { - Ok(file) => file, - Err(e) => { - return Box::pin(future::err(ContextualError::IoError( - format!("Failed to create {}", file_path.display()), - e, - ))); - } - }; - Box::pin( - field - .map_err(ContextualError::MultipartError) - .try_fold(0i64, move |acc, bytes| { - let rt = file - .write_all(bytes.as_ref()) - .map(|_| acc + bytes.len() as i64) - .map_err(|e| { - ContextualError::IoError("Failed to write to file".to_string(), e) - }); - future::ready(rt) - }), - ) + let file = std::fs::File::create(&file_path).map_err(|e| { + ContextualError::IoError(format!("Failed to create {}", file_path.display()), e) + })?; + + let (_, written_len) = field + .map_err(ContextualError::MultipartError) + .try_fold((file, 0u64), |(mut file, written_len), bytes| async move { + file.write_all(bytes.as_ref()) + .map_err(|e| ContextualError::IoError("Failed to write to file".to_string(), e))?; + Ok((file, written_len + bytes.len() as u64)) + }) + .await?; + + Ok(written_len) } /// Create new future to handle file as multipart data. -fn handle_multipart( +async fn handle_multipart( field: actix_multipart::Field, - mut file_path: PathBuf, + file_path: PathBuf, overwrite_files: bool, -) -> Pin<Box<dyn Stream<Item = Result<i64, ContextualError>>>> { +) -> Result<u64, ContextualError> { let filename = field - .headers() - .get(header::CONTENT_DISPOSITION) - .ok_or(ContextualError::ParseError) - .and_then(|cd| { - header::ContentDisposition::from_raw(cd).map_err(|_| ContextualError::ParseError) - }) - .and_then(|content_disposition| { - content_disposition - .get_filename() - .ok_or(ContextualError::ParseError) - .map(String::from) - }); - let err = |e: ContextualError| Box::pin(future::err(e).into_stream()); - match filename { - Ok(f) => { - match std::fs::metadata(&file_path) { - Ok(metadata) => { - if !metadata.is_dir() { - return err(ContextualError::InvalidPathError(format!( - "cannot upload file to {}, since it's not a directory", - &file_path.display() - ))); - } else if metadata.permissions().readonly() { - return err(ContextualError::InsufficientPermissionsError( - file_path.display().to_string(), - )); - } - } - Err(_) => { - return err(ContextualError::InsufficientPermissionsError( - file_path.display().to_string(), - )); - } - } - file_path = file_path.join(f); - Box::pin(save_file(field, file_path, overwrite_files).into_stream()) - } - Err(e) => err(e( - "HTTP header".to_string(), - "Failed to retrieve the name of the file to upload".to_string(), + .content_disposition() + .and_then(|cd| cd.get_filename().map(String::from)) + .ok_or_else(|| { + ContextualError::ParseError( + "HTTP header".to_string(), + "Failed to retrieve the name of the file to upload".to_string(), + ) + })?; + + match std::fs::metadata(&file_path) { + Err(_) => Err(ContextualError::InsufficientPermissionsError( + file_path.display().to_string(), )), - } + Ok(metadata) if !metadata.is_dir() => Err(ContextualError::InvalidPathError(format!( + "cannot upload file to {}, since it's not a directory", + &file_path.display() + ))), + Ok(metadata) if metadata.permissions().readonly() => Err( + ContextualError::InsufficientPermissionsError(file_path.display().to_string()), + ), + Ok(_) => Ok(()), + }?; + + save_file(field, file_path.join(filename), overwrite_files).await } /// Handle incoming request to upload file. @@ -104,16 +77,16 @@ fn handle_multipart( /// invalid. /// This method returns future. #[allow(clippy::too_many_arguments)] -pub fn upload_file( +pub async fn upload_file( req: HttpRequest, payload: actix_web::web::Payload, uses_random_route: bool, favicon_route: String, css_route: String, - default_color_scheme: &str, - default_color_scheme_dark: &str, + default_color_scheme: String, + default_color_scheme_dark: String, hide_version_footer: bool, -) -> Pin<Box<dyn Future<Output = Result<HttpResponse, actix_web::Error>>>> { +) -> Result<HttpResponse, actix_web::Error> { let conf = req.app_data::<crate::MiniserveConfig>().unwrap(); let return_path = if let Some(header) = req.headers().get(header::REFERER) { header.to_str().unwrap_or("/").to_owned() @@ -131,7 +104,7 @@ pub fn upload_file( let err = ContextualError::InvalidHttpRequestError( "Missing query parameter 'path'".to_string(), ); - return Box::pin(create_error_response( + return Ok(create_error_response( &err.to_string(), StatusCode::BAD_REQUEST, &return_path, @@ -140,8 +113,8 @@ pub fn upload_file( uses_random_route, &favicon_route, &css_route, - default_color_scheme, - default_color_scheme_dark, + &default_color_scheme, + &default_color_scheme_dark, hide_version_footer, )); } @@ -154,7 +127,7 @@ pub fn upload_file( "Failed to resolve path served by miniserve".to_string(), e, ); - return Box::pin(create_error_response( + return Ok(create_error_response( &err.to_string(), StatusCode::INTERNAL_SERVER_ERROR, &return_path, @@ -163,8 +136,8 @@ pub fn upload_file( uses_random_route, &favicon_route, &css_route, - default_color_scheme, - default_color_scheme_dark, + &default_color_scheme, + &default_color_scheme_dark, hide_version_footer, )); } @@ -177,7 +150,7 @@ pub fn upload_file( let err = ContextualError::InvalidHttpRequestError( "Invalid value for 'path' parameter".to_string(), ); - return Box::pin(create_error_response( + return Ok(create_error_response( &err.to_string(), StatusCode::BAD_REQUEST, &return_path, @@ -186,8 +159,8 @@ pub fn upload_file( uses_random_route, &favicon_route, &css_route, - default_color_scheme, - default_color_scheme_dark, + &default_color_scheme, + &default_color_scheme_dark, hide_version_footer, )); } @@ -196,33 +169,29 @@ pub fn upload_file( let default_color_scheme = conf.default_color_scheme.clone(); let default_color_scheme_dark = conf.default_color_scheme_dark.clone(); - Box::pin( - actix_multipart::Multipart::new(req.headers(), payload) - .map_err(ContextualError::MultipartError) - .map_ok(move |item| handle_multipart(item, target_dir.clone(), overwrite_files)) - .try_flatten() - .try_collect::<Vec<_>>() - .then(move |e| match e { - Ok(_) => future::ok( - HttpResponse::SeeOther() - .header(header::LOCATION, return_path) - .finish(), - ), - Err(e) => create_error_response( - &e.to_string(), - StatusCode::INTERNAL_SERVER_ERROR, - &return_path, - query_params.sort, - query_params.order, - uses_random_route, - &favicon_route, - &css_route, - &default_color_scheme, - &default_color_scheme_dark, - hide_version_footer, - ), - }), - ) + match actix_multipart::Multipart::new(req.headers(), payload) + .map_err(ContextualError::MultipartError) + .and_then(move |field| handle_multipart(field, target_dir.clone(), overwrite_files)) + .try_collect::<Vec<u64>>() + .await + { + Ok(_) => Ok(HttpResponse::SeeOther() + .append_header((header::LOCATION, return_path)) + .finish()), + Err(e) => Ok(create_error_response( + &e.to_string(), + StatusCode::INTERNAL_SERVER_ERROR, + &return_path, + query_params.sort, + query_params.order, + uses_random_route, + &favicon_route, + &css_route, + &default_color_scheme, + &default_color_scheme_dark, + hide_version_footer, + )), + } } /// Convenience method for creating response errors, if file upload fails. @@ -239,27 +208,25 @@ fn create_error_response( default_color_scheme: &str, default_color_scheme_dark: &str, hide_version_footer: bool, -) -> future::Ready<Result<HttpResponse, actix_web::Error>> { +) -> HttpResponse { errors::log_error_chain(description.to_string()); - future::ok( - HttpResponse::BadRequest() - .content_type("text/html; charset=utf-8") - .body( - renderer::render_error( - description, - error_code, - return_path, - sorting_method, - sorting_order, - true, - !uses_random_route, - &favicon_route, - &css_route, - default_color_scheme, - default_color_scheme_dark, - hide_version_footer, - ) - .into_string(), - ), - ) + HttpResponse::BadRequest() + .content_type("text/html; charset=utf-8") + .body( + renderer::render_error( + description, + error_code, + return_path, + sorting_method, + sorting_order, + true, + !uses_random_route, + favicon_route, + css_route, + default_color_scheme, + default_color_scheme_dark, + hide_version_footer, + ) + .into_string(), + ) } diff --git a/src/listing.rs b/src/listing.rs index 43cfb0e..33a0342 100644 --- a/src/listing.rs +++ b/src/listing.rs @@ -2,7 +2,7 @@ use actix_web::body::Body; use actix_web::dev::ServiceResponse; use actix_web::http::StatusCode; use actix_web::web::Query; -use actix_web::{HttpRequest, HttpResponse, Result}; +use actix_web::{HttpRequest, HttpResponse}; use bytesize::ByteSize; use percent_encoding::{percent_decode_str, utf8_percent_encode}; use qrcodegen::{QrCode, QrCodeEcc}; @@ -24,7 +24,7 @@ mod percent_encode_sets { const BASE: &AsciiSet = &CONTROLS.add(b'%'); pub const QUERY: &AsciiSet = &BASE.add(b' ').add(b'"').add(b'#').add(b'<').add(b'>'); pub const PATH: &AsciiSet = &QUERY.add(b'?').add(b'`').add(b'{').add(b'}'); - pub const PATH_SEGMENT: &AsciiSet = &PATH.add(b'/'); + pub const PATH_SEGMENT: &AsciiSet = &PATH.add(b'/').add(b'\\'); } /// Query parameters @@ -142,7 +142,7 @@ impl Breadcrumb { } } -pub async fn file_handler(req: HttpRequest) -> Result<actix_files::NamedFile> { +pub async fn file_handler(req: HttpRequest) -> actix_web::Result<actix_files::NamedFile> { let path = &req.app_data::<crate::MiniserveConfig>().unwrap().path; actix_files::NamedFile::open(path).map_err(Into::into) } @@ -169,25 +169,10 @@ pub fn directory_listing( dirs_first: bool, hide_version_footer: bool, title: Option<String>, -) -> Result<ServiceResponse, io::Error> { +) -> io::Result<ServiceResponse> { use actix_web::dev::BodyEncoding; let serve_path = req.path(); - // In case the current path is a directory, we want to make sure that the current URL ends - // on a slash ("/"). - if !serve_path.ends_with('/') { - let query = match req.query_string() { - "" => String::new(), - _ => format!("?{}", req.query_string()), - }; - return Ok(ServiceResponse::new( - req.clone(), - HttpResponse::MovedPermanently() - .header("Location", format!("{}/{}", serve_path, query)) - .body("301"), - )); - } - let base = Path::new(serve_path); let random_route_abs = format!("/{}", random_route.clone().unwrap_or_default()); let is_root = base.parent().is_none() || Path::new(&req.path()) == Path::new(&random_route_abs); @@ -243,10 +228,10 @@ pub fn directory_listing( if let Some(url) = query_params.qrcode { let res = match QrCode::encode_text(&url, QrCodeEcc::Medium) { Ok(qr) => HttpResponse::Ok() - .header("Content-Type", "image/svg+xml") - .body(qr.to_svg_string(2)), + .append_header(("Content-Type", "image/svg+xml")) + .body(qr_to_svg_string(&qr, 2)), Err(err) => { - log::error!("URL is too long: {:?}", err); + log::error!("URL is invalid (too long?): {:?}", err); HttpResponse::UriTooLong().body(Body::Empty) } }; @@ -376,7 +361,7 @@ pub fn directory_listing( // We will create the archive in a separate thread, and stream the content using a pipe. // The pipe is made of a futures channel, and an adapter to implement the `Write` trait. // Include 10 messages of buffer for erratic connection speeds. - let (tx, rx) = futures::channel::mpsc::channel::<Result<actix_web::web::Bytes, ()>>(10); + let (tx, rx) = futures::channel::mpsc::channel::<io::Result<actix_web::web::Bytes>>(10); let pipe = crate::pipe::Pipe::new(tx); // Start the actual archive creation in a separate thread. @@ -392,11 +377,11 @@ pub fn directory_listing( HttpResponse::Ok() .content_type(archive_method.content_type()) .encoding(archive_method.content_encoding()) - .header("Content-Transfer-Encoding", "binary") - .header( + .append_header(("Content-Transfer-Encoding", "binary")) + .append_header(( "Content-Disposition", format!("attachment; filename={:?}", file_name), - ) + )) .body(actix_web::body::BodyStream::new(rx)), )) } else { @@ -452,3 +437,34 @@ pub fn extract_query_parameters(req: &HttpRequest) -> QueryParameters { } } } + +// Returns a string of SVG code for an image depicting +// the given QR Code, with the given number of border modules. +// The string always uses Unix newlines (\n), regardless of the platform. +fn qr_to_svg_string(qr: &QrCode, border: i32) -> String { + assert!(border >= 0, "Border must be non-negative"); + let mut result = String::new(); + result += "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; + result += "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n"; + let dimension = qr + .size() + .checked_add(border.checked_mul(2).unwrap()) + .unwrap(); + result += &format!( + "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" viewBox=\"0 0 {0} {0}\" stroke=\"none\">\n", dimension); + result += "\t<rect width=\"100%\" height=\"100%\" fill=\"#FFFFFF\"/>\n"; + result += "\t<path d=\""; + for y in 0..qr.size() { + for x in 0..qr.size() { + if qr.get_module(x, y) { + if x != 0 || y != 0 { + result += " "; + } + result += &format!("M{},{}h1v1h-1z", x + border, y + border); + } + } + } + result += "\" fill=\"#000000\"/>\n"; + result += "</svg>\n"; + result +} diff --git a/src/main.rs b/src/main.rs index b6dd856..149f1ea 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,8 @@ use std::io; -use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}; +use std::io::Write; +use std::net::{IpAddr, Ipv4Addr, SocketAddr}; use std::thread; use std::time::Duration; -use std::{io::Write, path::PathBuf}; use actix_web::web; use actix_web::{ @@ -10,8 +10,7 @@ use actix_web::{ Responder, }; use actix_web::{middleware, App, HttpRequest, HttpResponse}; -use actix_web_httpauth::middleware::HttpAuthentication; -use http::header::HeaderMap; +use anyhow::Result; use log::{error, warn}; use structopt::clap::crate_version; use structopt::StructOpt; @@ -20,174 +19,31 @@ use yansi::{Color, Paint}; mod archive; mod args; mod auth; +mod config; mod errors; mod file_upload; mod listing; mod pipe; mod renderer; +use crate::config::MiniserveConfig; use crate::errors::ContextualError; -/// Possible characters for random routes -const ROUTE_ALPHABET: [char; 16] = [ - '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'a', 'b', 'c', 'd', 'e', 'f', -]; - -#[derive(Clone)] -/// Configuration of the Miniserve application -pub struct MiniserveConfig { - /// Enable verbose mode - pub verbose: bool, - - /// Path to be served by miniserve - pub path: std::path::PathBuf, - - /// Port on which miniserve will be listening - pub port: u16, - - /// IP address(es) on which miniserve will be available - pub interfaces: Vec<IpAddr>, - - /// Enable HTTP basic authentication - pub auth: Vec<auth::RequiredAuth>, - - /// If false, miniserve will serve the current working directory - pub path_explicitly_chosen: bool, - - /// Enable symlink resolution - pub no_symlinks: bool, - - /// Show hidden files - pub show_hidden: bool, - - /// Enable random route generation - pub random_route: Option<String>, - - /// Randomly generated favicon route - pub favicon_route: String, - - /// Randomly generated css route - pub css_route: String, - - /// Default color scheme - pub default_color_scheme: String, - - /// Default dark mode color scheme - pub default_color_scheme_dark: String, - - /// The name of a directory index file to serve, like "index.html" - /// - /// Normally, when miniserve serves a directory, it creates a listing for that directory. - /// However, if a directory contains this file, miniserve will serve that file instead. - pub index: Option<std::path::PathBuf>, - - /// Enable QR code display - pub show_qrcode: bool, - - /// Enable file upload - pub file_upload: bool, - - /// Enable upload to override existing files - pub overwrite_files: bool, - - /// If false, creation of uncompressed tar archives is disabled - pub tar_enabled: bool, - - /// If false, creation of gz-compressed tar archives is disabled - pub tar_gz_enabled: bool, - - /// If false, creation of zip archives is disabled - pub zip_enabled: bool, - - /// If enabled, directories are listed first - pub dirs_first: bool, - - /// Shown instead of host in page title and heading - pub title: Option<String>, - - /// If specified, header will be added - pub header: Vec<HeaderMap>, - - /// If enabled, version footer is hidden - pub hide_version_footer: bool, -} - -impl MiniserveConfig { - /// Parses the command line arguments - fn from_args(args: args::CliArgs) -> Self { - let interfaces = if !args.interfaces.is_empty() { - args.interfaces - } else { - vec![ - IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), - IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), - ] - }; - - let random_route = if args.random_route { - Some(nanoid::nanoid!(6, &ROUTE_ALPHABET)) - } else { - None - }; - - // Generate some random routes for the favicon and css so that they are very unlikely to conflict with - // real files. - let favicon_route = nanoid::nanoid!(10, &ROUTE_ALPHABET); - let css_route = nanoid::nanoid!(10, &ROUTE_ALPHABET); - - let default_color_scheme = args.color_scheme; - let default_color_scheme_dark = args.color_scheme_dark; - - let path_explicitly_chosen = args.path.is_some() || args.index.is_some(); - - let port = match args.port { - 0 => port_check::free_local_port().expect("no free ports available"), - _ => args.port, - }; - - crate::MiniserveConfig { - verbose: args.verbose, - path: args.path.unwrap_or_else(|| PathBuf::from(".")), - port, - interfaces, - auth: args.auth, - path_explicitly_chosen, - no_symlinks: args.no_symlinks, - show_hidden: args.hidden, - random_route, - favicon_route, - css_route, - default_color_scheme, - default_color_scheme_dark, - index: args.index, - overwrite_files: args.overwrite_files, - show_qrcode: args.qrcode, - file_upload: args.file_upload, - tar_enabled: args.enable_tar, - tar_gz_enabled: args.enable_tar_gz, - zip_enabled: args.enable_zip, - dirs_first: args.dirs_first, - title: args.title, - header: args.header, - hide_version_footer: args.hide_version_footer, - } - } -} - -fn main() { +fn main() -> Result<()> { let args = args::CliArgs::from_args(); if let Some(shell) = args.print_completions { args::CliArgs::clap().gen_completions_to("miniserve", shell, &mut std::io::stdout()); - return; + return Ok(()); } - let miniserve_config = MiniserveConfig::from_args(args); + let miniserve_config = MiniserveConfig::try_from_args(args)?; match run(miniserve_config) { Ok(()) => (), Err(e) => errors::log_error_chain(e.to_string()), } + Ok(()) } #[actix_web::main(miniserve)] @@ -300,11 +156,17 @@ async fn run(miniserve_config: MiniserveConfig) -> Result<(), ContextualError> { if !addresses.is_empty() { addresses.push_str(", "); } + let protocol = if miniserve_config.tls_rustls_config.is_some() { + "https" + } else { + "http" + }; addresses.push_str(&format!( "{}", Color::Green .paint(format!( - "http://{interface}:{port}", + "{protocol}://{interface}:{port}", + protocol = protocol, interface = &interface, port = miniserve_config.port )) @@ -350,10 +212,11 @@ async fn run(miniserve_config: MiniserveConfig) -> Result<(), ContextualError> { App::new() .wrap(configure_header(&inside_config.clone())) .app_data(inside_config.clone()) - .wrap(middleware::Condition::new( - !inside_config.auth.is_empty(), - HttpAuthentication::basic(auth::handle_auth), - )) + // we should use `actix_web_httpauth::middleware::HttpAuthentication` + // but it is unfortuantrly broken + // see: https://github.com/actix/actix-extras/issues/127 + // TODO replace this when fixed upstream + .wrap_fn(auth::auth_middleware) .wrap(middleware::Logger::default()) .route( &format!("/{}", inside_config.favicon_route), @@ -362,11 +225,27 @@ async fn run(miniserve_config: MiniserveConfig) -> Result<(), ContextualError> { .route(&format!("/{}", inside_config.css_route), web::get().to(css)) .configure(|c| configure_app(c, &inside_config)) .default_service(web::get().to(error_404)) - }) - .bind(socket_addresses.as_slice()) - .map_err(|e| ContextualError::IoError("Failed to bind server".to_string(), e))? - .shutdown_timeout(0) - .run(); + }); + + #[cfg(feature = "tls")] + let srv = if let Some(tls_config) = miniserve_config.tls_rustls_config { + srv.bind_rustls(socket_addresses.as_slice(), tls_config) + .map_err(|e| ContextualError::IoError("Failed to bind server".to_string(), e))? + .shutdown_timeout(0) + .run() + } else { + srv.bind(socket_addresses.as_slice()) + .map_err(|e| ContextualError::IoError("Failed to bind server".to_string(), e))? + .shutdown_timeout(0) + .run() + }; + + #[cfg(not(feature = "tls"))] + let srv = srv + .bind(socket_addresses.as_slice()) + .map_err(|e| ContextualError::IoError("Failed to bind server".to_string(), e))? + .shutdown_timeout(0) + .run(); println!( "Serving path {path} at {addresses}", @@ -466,6 +345,7 @@ fn configure_app(app: &mut web::ServiceConfig, conf: &MiniserveConfig) { ) }) .prefer_utf8(true) + .redirect_to_slash_directory() .default_handler(web::to(error_404)); Some(files) } @@ -489,8 +369,8 @@ fn configure_app(app: &mut web::ServiceConfig, conf: &MiniserveConfig) { uses_random_route, favicon_route.clone(), css_route.clone(), - &default_color_scheme, - &default_color_scheme_dark, + default_color_scheme.clone(), + default_color_scheme_dark.clone(), hide_version_footer, ) })), @@ -538,14 +418,14 @@ async fn error_404(req: HttpRequest) -> HttpResponse { async fn favicon() -> impl Responder { let logo = include_str!("../data/logo.svg"); - web::HttpResponse::Ok() - .set(ContentType(mime::IMAGE_SVG)) + HttpResponse::Ok() + .insert_header(ContentType(mime::IMAGE_SVG)) .message_body(logo.into()) } async fn css() -> impl Responder { let css = include_str!(concat!(env!("OUT_DIR"), "/style.css")); - web::HttpResponse::Ok() - .set(ContentType(mime::TEXT_CSS)) + HttpResponse::Ok() + .insert_header(ContentType(mime::TEXT_CSS)) .message_body(css.into()) } diff --git a/src/pipe.rs b/src/pipe.rs index 374a45f..6bf32c2 100644 --- a/src/pipe.rs +++ b/src/pipe.rs @@ -3,19 +3,19 @@ use actix_web::web::{Bytes, BytesMut}; use futures::channel::mpsc::Sender; use futures::executor::block_on; use futures::sink::SinkExt; -use std::io::{Error, ErrorKind, Result, Write}; +use std::io::{self, Error, ErrorKind, Write}; /// Adapter to implement the `std::io::Write` trait on a `Sender<Bytes>` from a futures channel. /// /// It uses an intermediate buffer to transfer packets. pub struct Pipe { - dest: Sender<std::result::Result<Bytes, ()>>, + dest: Sender<io::Result<Bytes>>, bytes: BytesMut, } impl Pipe { /// Wrap the given sender in a `Pipe`. - pub fn new(destination: Sender<std::result::Result<Bytes, ()>>) -> Self { + pub fn new(destination: Sender<io::Result<Bytes>>) -> Self { Pipe { dest: destination, bytes: BytesMut::new(), @@ -30,7 +30,7 @@ impl Drop for Pipe { } impl Write for Pipe { - fn write(&mut self, buf: &[u8]) -> Result<usize> { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { // We are given a slice of bytes we do not own, so we must start by copying it. self.bytes.extend_from_slice(buf); @@ -42,7 +42,7 @@ impl Write for Pipe { Ok(buf.len()) } - fn flush(&mut self) -> Result<()> { + fn flush(&mut self) -> io::Result<()> { block_on(self.dest.flush()).map_err(|e| Error::new(ErrorKind::UnexpectedEof, e)) } } diff --git a/src/renderer.rs b/src/renderer.rs index d2beda3..66f0291 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -272,7 +272,7 @@ fn parametrized_link( if let Some(order) = sort_order { let parametrized_link = format!( "{}?sort={}&order={}", - make_link_with_trailing_slash(&link), + make_link_with_trailing_slash(link), method, order ); @@ -281,7 +281,7 @@ fn parametrized_link( } } - make_link_with_trailing_slash(&link) + make_link_with_trailing_slash(link) } /// Partial: table header link diff --git a/tests/archive.rs b/tests/archive.rs index 6a7f8bf..b8def22 100644 --- a/tests/archive.rs +++ b/tests/archive.rs @@ -1,30 +1,15 @@ mod fixtures; -use assert_cmd::prelude::*; -use assert_fs::fixture::TempDir; -use fixtures::{port, tmpdir, Error}; +use fixtures::{server, Error, TestServer}; use reqwest::StatusCode; use rstest::rstest; use select::document::Document; use select::predicate::Text; -use std::process::{Command, Stdio}; -use std::thread::sleep; -use std::time::Duration; #[rstest] -fn archives_are_disabled(tmpdir: TempDir, port: u16) -> Result<(), Error> { - let mut child = Command::cargo_bin("miniserve")? - .arg(tmpdir.path()) - .arg("-p") - .arg(port.to_string()) - .stdout(Stdio::null()) - .spawn()?; - - sleep(Duration::from_secs(1)); - +fn archives_are_disabled(server: TestServer) -> Result<(), Error> { // Ensure the links to the archives are not present - let body = reqwest::blocking::get(format!("http://localhost:{}", port).as_str())? - .error_for_status()?; + let body = reqwest::blocking::get(server.url())?.error_for_status()?; let parsed = Document::from_read(body)?; assert!(parsed .find(Text) @@ -32,63 +17,42 @@ fn archives_are_disabled(tmpdir: TempDir, port: u16) -> Result<(), Error> { // Try to download anyway, ensure it's forbidden assert_eq!( - reqwest::blocking::get(format!("http://localhost:{}/?download=tar_gz", port).as_str())? - .status(), + reqwest::blocking::get(server.url().join("?download=tar_gz")?)?.status(), StatusCode::FORBIDDEN ); assert_eq!( - reqwest::blocking::get(format!("http://localhost:{}/?download=tar", port).as_str())? - .status(), + reqwest::blocking::get(server.url().join("?download=tar")?)?.status(), StatusCode::FORBIDDEN ); assert_eq!( - reqwest::blocking::get(format!("http://localhost:{}/?download=zip", port).as_str())? - .status(), + reqwest::blocking::get(server.url().join("?download=zip")?)?.status(), StatusCode::FORBIDDEN ); - child.kill()?; - Ok(()) } #[rstest] -fn test_tar_archives(tmpdir: TempDir, port: u16) -> Result<(), Error> { - let mut child = Command::cargo_bin("miniserve")? - .arg(tmpdir.path()) - .arg("-p") - .arg(port.to_string()) - .arg("-g") - .stdout(Stdio::null()) - .spawn()?; - - sleep(Duration::from_secs(1)); - +fn test_tar_archives(#[with(&["-g"])] server: TestServer) -> Result<(), Error> { // Ensure the links to the tar archive exists and tar not exists - let body = reqwest::blocking::get(format!("http://localhost:{}", port).as_str())? - .error_for_status()?; + let body = reqwest::blocking::get(server.url())?.error_for_status()?; let parsed = Document::from_read(body)?; assert!(parsed.find(Text).any(|x| x.text() == "Download .tar.gz")); assert!(parsed.find(Text).all(|x| x.text() != "Download .tar")); // Try to download, only tar_gz should works assert_eq!( - reqwest::blocking::get(format!("http://localhost:{}/?download=tar_gz", port).as_str())? - .status(), + reqwest::blocking::get(server.url().join("?download=tar_gz")?)?.status(), StatusCode::OK ); assert_eq!( - reqwest::blocking::get(format!("http://localhost:{}/?download=tar", port).as_str())? - .status(), + reqwest::blocking::get(server.url().join("?download=tar")?)?.status(), StatusCode::FORBIDDEN ); assert_eq!( - reqwest::blocking::get(format!("http://localhost:{}/?download=zip", port).as_str())? - .status(), + reqwest::blocking::get(server.url().join("?download=zip")?)?.status(), StatusCode::FORBIDDEN ); - child.kill()?; - Ok(()) } diff --git a/tests/auth.rs b/tests/auth.rs index 09ea8d8..920f738 100644 --- a/tests/auth.rs +++ b/tests/auth.rs @@ -1,17 +1,12 @@ mod fixtures; -use assert_cmd::prelude::*; -use assert_fs::fixture::TempDir; -use fixtures::{port, tmpdir, Error, FILES}; +use fixtures::{server, server_no_stderr, Error, FILES}; use pretty_assertions::assert_eq; use reqwest::blocking::Client; use reqwest::StatusCode; use rstest::rstest; use select::document::Document; use select::predicate::Text; -use std::process::{Command, Stdio}; -use std::thread::sleep; -use std::time::Duration; #[rstest( cli_auth_arg, client_username, client_password, @@ -28,26 +23,14 @@ use std::time::Duration; ), )] fn auth_accepts( - tmpdir: TempDir, - port: u16, cli_auth_arg: &str, client_username: &str, client_password: &str, ) -> Result<(), Error> { - let mut child = Command::cargo_bin("miniserve")? - .arg(tmpdir.path()) - .arg("-p") - .arg(port.to_string()) - .arg("-a") - .arg(cli_auth_arg) - .stdout(Stdio::null()) - .spawn()?; - - sleep(Duration::from_secs(1)); - + let server = server(&["-a", cli_auth_arg]); let client = Client::new(); let response = client - .get(format!("http://localhost:{}", port).as_str()) + .get(server.url()) .basic_auth(client_username, Some(client_password)) .send()?; @@ -60,8 +43,6 @@ fn auth_accepts( assert!(parsed.find(Text).any(|x| x.text() == file)); } - child.kill()?; - Ok(()) } @@ -91,56 +72,39 @@ fn auth_accepts( ), )] fn auth_rejects( - tmpdir: TempDir, - port: u16, cli_auth_arg: &str, client_username: &str, client_password: &str, ) -> Result<(), Error> { - let mut child = Command::cargo_bin("miniserve")? - .arg(tmpdir.path()) - .arg("-p") - .arg(port.to_string()) - .arg("-a") - .arg(cli_auth_arg) - .stdout(Stdio::null()) - .stderr(Stdio::null()) - .spawn()?; - - sleep(Duration::from_secs(1)); - + let server = server_no_stderr(&["-a", cli_auth_arg]); let client = Client::new(); let status = client - .get(format!("http://localhost:{}", port).as_str()) + .get(server.url()) .basic_auth(client_username, Some(client_password)) .send()? .status(); assert_eq!(status, StatusCode::UNAUTHORIZED); - child.kill()?; - Ok(()) } -/// Helper function that registers multiple accounts -#[cfg(test)] -fn register_accounts<'a>(command: &'a mut Command) -> &'a mut Command { - command - .arg("--auth") - .arg("usr0:pwd0") - .arg("--auth") - .arg("usr1:pwd1") - .arg("--auth") - .arg("usr2:sha256:149d2937d1bce53fa683ae652291bd54cc8754444216a9e278b45776b76375af") // pwd2 - .arg("--auth") - .arg("usr3:sha256:ffc169417b4146cebe09a3e9ffbca33db82e3e593b4d04c0959a89c05b87e15d") // pwd3 - .arg("--auth") - .arg("usr4:sha512:68050a967d061ac480b414bc8f9a6d368ad0082203edcd23860e94c36178aad1a038e061716707d5479e23081a6d920dc6e9f88e5eb789cdd23e211d718d161a") // pwd4 - .arg("--auth") - .arg("usr5:sha512:be82a7dccd06122f9e232e9730e67e69e30ec61b268fd9b21a5e5d42db770d45586a1ce47816649a0107e9fadf079d9cf0104f0a3aaa0f67bad80289c3ba25a8") +/// Command line arguments that register multiple accounts +static ACCOUNTS: &[&str] = &[ + "--auth", + "usr0:pwd0", + "--auth", + "usr1:pwd1", + "--auth", + "usr2:sha256:149d2937d1bce53fa683ae652291bd54cc8754444216a9e278b45776b76375af", // pwd2 + "--auth", + "usr3:sha256:ffc169417b4146cebe09a3e9ffbca33db82e3e593b4d04c0959a89c05b87e15d", // pwd3 + "--auth", + "usr4:sha512:68050a967d061ac480b414bc8f9a6d368ad0082203edcd23860e94c36178aad1a038e061716707d5479e23081a6d920dc6e9f88e5eb789cdd23e211d718d161a", // pwd4 + "--auth", + "usr5:sha512:be82a7dccd06122f9e232e9730e67e69e30ec61b268fd9b21a5e5d42db770d45586a1ce47816649a0107e9fadf079d9cf0104f0a3aaa0f67bad80289c3ba25a8", // pwd5 -} +]; #[rstest( username, @@ -152,25 +116,12 @@ fn register_accounts<'a>(command: &'a mut Command) -> &'a mut Command { case("usr4", "pwd4"), case("usr5", "pwd5") )] -fn auth_multiple_accounts_pass( - tmpdir: TempDir, - port: u16, - username: &str, - password: &str, -) -> Result<(), Error> { - let mut child = register_accounts(&mut Command::cargo_bin("miniserve")?) - .arg("-p") - .arg(port.to_string()) - .arg(tmpdir.path()) - .stdout(Stdio::null()) - .spawn()?; - - sleep(Duration::from_secs(1)); - +fn auth_multiple_accounts_pass(username: &str, password: &str) -> Result<(), Error> { + let server = server(ACCOUNTS); let client = Client::new(); let response = client - .get(format!("http://localhost:{}", port).as_str()) + .get(server.url()) .basic_auth(username, Some(password)) .send()?; @@ -183,37 +134,22 @@ fn auth_multiple_accounts_pass( assert!(parsed.find(Text).any(|x| x.text() == file)); } - child.kill()?; - Ok(()) } #[rstest] -fn auth_multiple_accounts_wrong_username(tmpdir: TempDir, port: u16) -> Result<(), Error> { - let mut child = register_accounts( - Command::cargo_bin("miniserve")? - .arg(tmpdir.path()) - .arg("-p") - .arg(port.to_string()) - .stdout(Stdio::null()) - .stderr(Stdio::null()), - ) - .spawn()?; - - sleep(Duration::from_secs(1)); - +fn auth_multiple_accounts_wrong_username() -> Result<(), Error> { + let server = server_no_stderr(ACCOUNTS); let client = Client::new(); let status = client - .get(format!("http://localhost:{}", port).as_str()) + .get(server.url()) .basic_auth("unregistered user", Some("pwd0")) .send()? .status(); assert_eq!(status, StatusCode::UNAUTHORIZED); - child.kill()?; - Ok(()) } @@ -227,35 +163,17 @@ fn auth_multiple_accounts_wrong_username(tmpdir: TempDir, port: u16) -> Result<( case("usr4", "pwd1"), case("usr5", "pwd0") )] -fn auth_multiple_accounts_wrong_password( - tmpdir: TempDir, - port: u16, - username: &str, - password: &str, -) -> Result<(), Error> { - let mut child = register_accounts( - Command::cargo_bin("miniserve")? - .arg(tmpdir.path()) - .arg("-p") - .arg(port.to_string()) - .stdout(Stdio::null()) - .stderr(Stdio::null()), - ) - .spawn()?; - - sleep(Duration::from_secs(1)); - +fn auth_multiple_accounts_wrong_password(username: &str, password: &str) -> Result<(), Error> { + let server = server_no_stderr(ACCOUNTS); let client = Client::new(); let status = client - .get(format!("http://localhost:{}", port).as_str()) + .get(server.url()) .basic_auth(username, Some(password)) .send()? .status(); assert_eq!(status, StatusCode::UNAUTHORIZED); - child.kill()?; - Ok(()) } diff --git a/tests/data/cert.pem b/tests/data/cert.pem new file mode 100644 index 0000000..c907ef2 --- /dev/null +++ b/tests/data/cert.pem @@ -0,0 +1,29 @@ +-----BEGIN CERTIFICATE----- +MIIFCTCCAvGgAwIBAgIUJUf2QS/pOdHEW4EHTfdXxeTvtM8wDQYJKoZIhvcNAQEL +BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTIxMDgyNzAwMzEyOFoXDTMxMDgy +NTAwMzEyOFowFDESMBAGA1UEAwwJbG9jYWxob3N0MIICIjANBgkqhkiG9w0BAQEF +AAOCAg8AMIICCgKCAgEAwmYOqToI0R30lPyYtF9bSuhIOCp9cp0jl2nuHaO8mpr1 +gMiJKKN4HjAdgac+3hYkTRFqK2mKKpV9QdVKR24Ib7mC45Ek7BlLw3VbxPRKrK/j +rKW3M3ui+453B24yf6K8dH36x9gZo4glzghFxuodFakIX2zNKo6tEx0XVkbhsu/w +vj2s+0L3oToPAYZaiOB/7xYU6Yu9n7Tn6rE9/orDfK1DlrZDP3hzyxLzuf6tqXCh +66cgaPQTh+xyyWZcvl60kbB4H3bdhqbYGMMQO8bUxXTQXjwvUsvl0yn9qCpMIn99 +Pm9xhfDQSF3zawM3CQ/lmn9uFQzdOEfYlO6oaidTqxLtBhVUcEutIcmoW9nmmv2g +Ei49/3OmvWQcEdMWt8xwxSrMvKDSeUdF3rbalTHBFQHJlJiKRX9wTNtSZ5T8FTU7 +4Ip4EzAtP8wY5NDv253mddANoyKsVRGytS35LDFkCS/TxuVDZrjluc86yqUId/jf +HZAzQ7ifpC890aG0JOq/0mmVDvbn7MzdTsTWwhE8UaOiFljTiNQX3QjX3TaEu32M +XHKo5nebNqDVRGnFMFmfXw2ZP8lgQCWk1HxLr0qhRxIy8XmIK1ZUz7Uc4Cba73XB +pSxcIPytpDuuKotslBjoIYu9DY07n1Hu4zYPvpP9DnaunEW6zmANEtjSyrE/TQ0C +AwEAAaNTMFEwHQYDVR0OBBYEFH0VzGnFqGVB+11uyvqea2qXYxQKMB8GA1UdIwQY +MBaAFH0VzGnFqGVB+11uyvqea2qXYxQKMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI +hvcNAQELBQADggIBAA4FqzX34FCU1WYzmBRcq7QHSrc7LcuTbxhESB7mYbI8IPFt +cgrtXL1mTP+nz5nN+E6fyA8Y9zIyXm/6svYpJzXgUTtbdgDW22v5iN+YZvOaQ3Jt +/0eEtkx7wdNjLsN0aM6OjPXDw0mAVFDdevE7wgnra6x6/VHOt6pksNJa76ZVPX5X +dlLj+OU4eQPPMVxhL7p3xdSPFDZzXY7mNfVycO3tK5Fzrwko7OQKqEBMtc0oZxLd +m/FvqcJveHYHfXZl5XKMcsCNO8bG0XXDhwg0CLTf1p0hmp1oLieqplekOWs54Alo +FF4EBNdDaIFdQ4FAYaAU+9KLoPstorTl+3Owj/k3xhDB+0sGwGeX/e88nhs/ppEy +bxOt0j4AruwapkcvkwhQeMpQJRYyOrcvlbUEZqFABozZ9gbGRQvnConDNg7tz5zc +nVUupszA7zs0Vn9b1zVLOcOcS2ziQvoCyh687MsVbjw65Y6tkhvLI35G68zrFKsl +MS5mqnK4DZYFc1gGGI/rjsFUf3dD4ww6PTnwv3Ga2yBvXi7EckEeEqB+dRlVdvob +cH/grVUum3s5Y4PTnxyNAUFZlFNZ8jlOcgXtAFuTnJ/jcvboZdE7Oja2OIMJo53d +rbkqAPNGhQ98QDuTwWjHUq/Th1CQK4ALI/wqoc22TJpSh/mme5Dj4HhB7LWl +-----END CERTIFICATE----- diff --git a/tests/data/generate_tls_certs.sh b/tests/data/generate_tls_certs.sh new file mode 100755 index 0000000..969a38c --- /dev/null +++ b/tests/data/generate_tls_certs.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +openssl req -subj '/CN=localhost' -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -nodes -days 3650 diff --git a/tests/data/key.pem b/tests/data/key.pem new file mode 100644 index 0000000..4263815 --- /dev/null +++ b/tests/data/key.pem @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQDCZg6pOgjRHfSU +/Ji0X1tK6Eg4Kn1ynSOXae4do7yamvWAyIkoo3geMB2Bpz7eFiRNEWoraYoqlX1B +1UpHbghvuYLjkSTsGUvDdVvE9Eqsr+Ospbcze6L7jncHbjJ/orx0ffrH2BmjiCXO +CEXG6h0VqQhfbM0qjq0THRdWRuGy7/C+Paz7QvehOg8BhlqI4H/vFhTpi72ftOfq +sT3+isN8rUOWtkM/eHPLEvO5/q2pcKHrpyBo9BOH7HLJZly+XrSRsHgfdt2GptgY +wxA7xtTFdNBePC9Sy+XTKf2oKkwif30+b3GF8NBIXfNrAzcJD+Waf24VDN04R9iU +7qhqJ1OrEu0GFVRwS60hyahb2eaa/aASLj3/c6a9ZBwR0xa3zHDFKsy8oNJ5R0Xe +ttqVMcEVAcmUmIpFf3BM21JnlPwVNTvgingTMC0/zBjk0O/bneZ10A2jIqxVEbK1 +LfksMWQJL9PG5UNmuOW5zzrKpQh3+N8dkDNDuJ+kLz3RobQk6r/SaZUO9ufszN1O +xNbCETxRo6IWWNOI1BfdCNfdNoS7fYxccqjmd5s2oNVEacUwWZ9fDZk/yWBAJaTU +fEuvSqFHEjLxeYgrVlTPtRzgJtrvdcGlLFwg/K2kO64qi2yUGOghi70NjTufUe7j +Ng++k/0Odq6cRbrOYA0S2NLKsT9NDQIDAQABAoICAQC9eAEEGQcs4fhXGZav/lyZ +Nqnk7CzWf6eH1Pv6sXKKcUukmE9uZ10UdyrbCimxBX2eC8Ihy7yZYpfxiTPbSLg6 +RGH48Kc+4izAtWqbHMqHYusRg3Z6XB9u9Ny4RkQ7uF3bYEoDa3EZvQGzvMZdaCKu +0M/TSdTxjJvNjEYJlg42e7t1f+FQB2YZIuArSUqGK+ElIq2BLuzDcuuzB8r3g0Gj +C7BbfQswGnMpUzBvcHTMN3Xpmztwb6t1iBQcjYMJHH77nDaH3C9vJMBr6fqxeEo6 +pW7M2fX5ybcXR87tj0QjP4TPTIkl1Z77WW59N2X1lCPhoB+nrqESUJwcFDvbMrdM +yUZoDTdGui/fGa+91Yl2wn7IIB5AzSH3Vkb6Z2cEFKuKCNcfobfNSOVrrnFBj52u +IJGJhOj8FZz0HTYnIBQDpjVE92/+2CaCms5thlihm2ccG6jG2KGyjyNXRw548q/K +NVr65VG3B9IS0PVQ5z5ue5pt36ig057OtmCBGx23fqKwprzSTWQhsgZoUKSH4+UN +aBjqwcuhQJVPf4In6eJtW9Gf04cLDUMAWiaCHUTLVci3kauGqoxjj0Y4ysYbq16j +di51k+XVwas0LLjFf2+eaGfd0nMFHPoXXlfaPGJSl2QAnIQGJ2d1b+/EYHlhswr3 +EPO+V22U5aiAXjBYGEb9IQKCAQEA+GlAJzigOc8F9A1HPXuDYAFZxDYF8TEjQOrW +btFek55RTqO3pPgi5XR7gQLsqpno+3IMwkJPi9LE4HJ04dGlIiLAFsWWWsB7eshE +E/dm9ddfcvUlcMQ5vT0Z8r6kyLZR5NG+x5KMZ5AB4Uv8PLLaXQd2LyXQzysfPX00 +tWs0/6/DA99uVNiAi9K6ebV5ZJxgbEqiDd0wn1W0MH0lvxIJumTKLiWpOR7FlXlL +c+xRmyC0YqcX8LpI880GdnRI13SGPD9cu+/nivgjl18UC+j+WapeBLDCQHRcjaVy +UBKGwOTla3mdx6//jWxFQzZNsapR8dxIxuxY5b+cNUhV7W2LNQKCAQEAyFZkJxQf +Of7fHyBCL9ldzxgu4MHtGIeH/z+0nnJj+/b5HFlWAK9A1lSmTEMwNZ7tSQWAhmQb +lS3DEA4a12JKvqtpamYyj17hdx3dCGe9wU8z2aS08wDuM9L1g5xqhhrn2ewcpJNp +9cqoBKoqLjk9yA2X4GEUCaKuHbOMrkfQAq8jQBgYe3aPWZjMuDAI2RNpGxGwyslR +AM+LnWFskGtgB5q1rBNQduNXEKVqNd5Zsqztd/tkcLmgqLZHbpUWwqYYTaVE3wW9 +cir+9VGTuOi9kKEjZ2P35f4VP2GNA7V3fgU/LYv81V2osQPsngheL5RVA1RVvCqo +XTpsEUKie9WdeQKCAQEAhry34k4xggmLRhupp2yGDp3M7cMLqA4p+/0kgAkqDlGR +8mCUrHM2olRy5MAMVGCU4UW0K+3BraqNxNvwD8ghlIlavT9A1UqP70IOwvGvM+s0 +x2q2exrD4qPwnhzPzlotwzoNC7yuUUHn8ya+0sGD9W+lp98QCj5ufHCcFUboAUN5 +OHGJK5Ye6zhKktde17aGClbU3UY7KEFZMe+/eIq1IhenHi6pQeUx8GhRB7iHbufn +T5coQhcYmLx9I+Tg2ZRHdwg7KWjvow4CaAlXGzquMz5YLp0dT86NoPq7LTlPQ/Mj +iQ73CKeqqi+uxcz/iT1DozcDdnodocgzVyc8DEMdfQKCAQAQ37Xv1LIMoHsKlBz/ +Cr/sAY1xQORHfKLnzOXZsqjZQCQbTyr/Q8OiSd737XDSE2DJFb2NlED+f6w+XfHE +0nKZPLbUT2dSzBsRfWJwosxIy/MCEe1rylhF5S7otvQB96IvqMOA2SnDmh4sxmhn +HEsn3n08WPDnHtyrg8QFqebLUxUVAPKO851/Xm9f1CvqnMftj7/kVLCN8O1BhEMw +ptqfyVgj9jyAxwU+UbBweRn1Aru9r172X6w4iaHanpQcMQE7CQCUCFe8lgKDhyt6 +F6Bf3jKtMq5eoNgJTp4iAdbetnJr066oCgt7XWlAplPIjiXa8e+GudEUiScxDPvC +kmuBAoIBAH/+OwEZBEnMb5c+aWTgxUh3NGtAy6LgD+1cj5IT2s215si6ea4QzPM0 +Ddht4nbs2oPML5kwpym4IKI1OY+07haZJoxt14xo7eLhO8+7+t6yka/Y6SlIuSqP +Cku40Ok2JyWRQxe3n371wmEKKuJyqVMDR1bY5tkwhh1MYUO8xkGbbZcbrUx6GLuJ +E53ybjzdaxFYbHO2ZvqQALZq5h8mb+5IFFhIQjM2PLXHY3Ok3xNgrR9Se1Bb6tZY +x+j6/xEBVw1Yg2J/UgMjRQDzax/wTBzTlUkc1kpp0Xi2iQcxVQSZZ1nQU3opcmwJ +UbBWUEN95O4LnWFuyhEIOIEmp5JtGks= +-----END PRIVATE KEY----- diff --git a/tests/fixtures/mod.rs b/tests/fixtures/mod.rs index 1cf6c59..ec17f3e 100644 --- a/tests/fixtures/mod.rs +++ b/tests/fixtures/mod.rs @@ -1,7 +1,12 @@ +use assert_cmd::prelude::*; use assert_fs::fixture::TempDir; use assert_fs::prelude::*; use port_check::free_local_port; +use reqwest::Url; use rstest::fixture; +use std::process::{Child, Command, Stdio}; +use std::thread::sleep; +use std::time::{Duration, Instant}; /// Error type used by tests pub type Error = Box<dyn std::error::Error>; @@ -19,6 +24,8 @@ pub static FILES: &[&str] = &[ "#[]{}()@!$&'`+,;= %20.test", #[cfg(unix)] ":?#[]{}<>()@!$&'`|*+,;= %20.test", + #[cfg(not(windows))] + "foo\\bar.test", ]; /// Hidden files for testing purpose @@ -76,3 +83,112 @@ pub fn tmpdir() -> TempDir { pub fn port() -> u16 { free_local_port().expect("Couldn't find a free local port") } + +/// Run miniserve as a server; Start with a temporary directory, a free port and some +/// optional arguments then wait for a while for the server setup to complete. +#[fixture] +#[allow(dead_code)] +pub fn server<I>(#[default(&[] as &[&str])] args: I) -> TestServer +where + I: IntoIterator + Clone, + I::Item: AsRef<std::ffi::OsStr>, +{ + let port = port(); + let tmpdir = tmpdir(); + let child = Command::cargo_bin("miniserve") + .expect("Couldn't find test binary") + .arg(tmpdir.path()) + .arg("-p") + .arg(port.to_string()) + .args(args.clone()) + .stdout(Stdio::null()) + .spawn() + .expect("Couldn't run test binary"); + let is_tls = args + .into_iter() + .any(|x| x.as_ref().to_str().unwrap().contains("tls")); + + wait_for_port(port); + TestServer::new(port, tmpdir, child, is_tls) +} + +/// Same as `server()` but ignore stderr +#[fixture] +#[allow(dead_code)] +pub fn server_no_stderr<I>(#[default(&[] as &[&str])] args: I) -> TestServer +where + I: IntoIterator + Clone, + I::Item: AsRef<std::ffi::OsStr>, +{ + let port = port(); + let tmpdir = tmpdir(); + let child = Command::cargo_bin("miniserve") + .expect("Couldn't find test binary") + .arg(tmpdir.path()) + .arg("-p") + .arg(port.to_string()) + .args(args.clone()) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .spawn() + .expect("Couldn't run test binary"); + let is_tls = args + .into_iter() + .any(|x| x.as_ref().to_str().unwrap().contains("tls")); + + wait_for_port(port); + TestServer::new(port, tmpdir, child, is_tls) +} + +/// Wait a max of 1s for the port to become available. +fn wait_for_port(port: u16) { + let start_wait = Instant::now(); + + while !port_check::is_port_reachable(format!("localhost:{}", port)) { + sleep(Duration::from_millis(100)); + + if start_wait.elapsed().as_secs() > 1 { + panic!("timeout waiting for port {}", port); + } + } +} + +#[allow(dead_code)] +pub struct TestServer { + port: u16, + tmpdir: TempDir, + child: Child, + is_tls: bool, +} + +#[allow(dead_code)] +impl TestServer { + pub fn new(port: u16, tmpdir: TempDir, child: Child, is_tls: bool) -> Self { + Self { + port, + tmpdir, + child, + is_tls, + } + } + + pub fn url(&self) -> Url { + let protocol = if self.is_tls { "https" } else { "http" }; + Url::parse(&format!("{}://localhost:{}", protocol, self.port)).unwrap() + } + + pub fn path(&self) -> &std::path::Path { + self.tmpdir.path() + } + + pub fn port(&self) -> u16 { + self.port + } +} + +impl Drop for TestServer { + fn drop(&mut self) { + self.child.kill().expect("Couldn't kill test server"); + self.child.wait().unwrap(); + } +} diff --git a/tests/header.rs b/tests/header.rs index e46044c..4ac38b1 100644 --- a/tests/header.rs +++ b/tests/header.rs @@ -1,29 +1,15 @@ mod fixtures; -use assert_cmd::prelude::*; -use assert_fs::fixture::TempDir; -use fixtures::{port, tmpdir, Error}; +use fixtures::{server, Error}; use rstest::rstest; -use std::process::{Command, Stdio}; -use std::thread::sleep; -use std::time::Duration; #[rstest(headers, case(vec!["x-info: 123".to_string()]), case(vec!["x-info1: 123".to_string(), "x-info2: 345".to_string()]) )] -fn custom_header_set(tmpdir: TempDir, port: u16, headers: Vec<String>) -> Result<(), Error> { - let mut child = Command::cargo_bin("miniserve")? - .arg(tmpdir.path()) - .arg("-p") - .arg(port.to_string()) - .args(headers.iter().flat_map(|h| vec!["--header", h])) - .stdout(Stdio::null()) - .spawn()?; - - sleep(Duration::from_secs(1)); - - let resp = reqwest::blocking::get(format!("http://localhost:{}", port).as_str())?; +fn custom_header_set(headers: Vec<String>) -> Result<(), Error> { + let server = server(headers.iter().flat_map(|h| vec!["--header", h])); + let resp = reqwest::blocking::get(server.url())?; for header in headers { let mut header_split = header.splitn(2, ':'); @@ -32,7 +18,5 @@ fn custom_header_set(tmpdir: TempDir, port: u16, headers: Vec<String>) -> Result assert_eq!(resp.headers().get(header_name).unwrap(), header_value); } - child.kill()?; - Ok(()) } diff --git a/tests/navigation.rs b/tests/navigation.rs index c5c18cb..f4a2e1f 100644 --- a/tests/navigation.rs +++ b/tests/navigation.rs @@ -1,16 +1,11 @@ mod fixtures; mod utils; -use assert_cmd::prelude::*; -use assert_fs::fixture::TempDir; -use fixtures::{port, tmpdir, Error, DEEPLY_NESTED_FILE, DIRECTORIES}; +use fixtures::{server, Error, TestServer, DEEPLY_NESTED_FILE, DIRECTORIES}; use pretty_assertions::{assert_eq, assert_ne}; use rstest::rstest; use select::document::Document; use std::process::{Command, Stdio}; -use std::thread::sleep; -use std::time::Duration; -use url::Url; use utils::get_link_from_text; #[rstest( @@ -22,45 +17,19 @@ use utils::get_link_from_text; case("/very/deeply/nested", "/very/deeply/nested/") )] /// Directories get a trailing slash. -fn index_gets_trailing_slash( - tmpdir: TempDir, - port: u16, - input: &str, - expected: &str, -) -> Result<(), Error> { - let mut child = Command::cargo_bin("miniserve")? - .arg("-p") - .arg(port.to_string()) - .arg(tmpdir.path()) - .stdout(Stdio::null()) - .spawn()?; - - sleep(Duration::from_secs(1)); - - let base_url = Url::parse(&format!("http://localhost:{}", port))?; - let resp = reqwest::blocking::get(base_url.join(input)?)?; +fn index_gets_trailing_slash(server: TestServer, input: &str, expected: &str) -> Result<(), Error> { + let resp = reqwest::blocking::get(server.url().join(input)?)?; assert!(resp.url().as_str().ends_with(expected)); - child.kill()?; - Ok(()) } #[rstest] /// Can't navigate up the root. -fn cant_navigate_up_the_root(tmpdir: TempDir, port: u16) -> Result<(), Error> { - let mut child = Command::cargo_bin("miniserve")? - .arg("-p") - .arg(port.to_string()) - .arg(tmpdir.path()) - .stdout(Stdio::null()) - .spawn()?; - - sleep(Duration::from_secs(1)); - +fn cant_navigate_up_the_root(server: TestServer) -> Result<(), Error> { // We're using curl for this as it has the option `--path-as-is` which doesn't normalize // invalid urls. A useful feature in this particular case. - let base_url = Url::parse(&format!("http://localhost:{}", port))?; + let base_url = server.url(); let curl_successful = Command::new("curl") .arg("-s") .arg("--fail") @@ -71,24 +40,13 @@ fn cant_navigate_up_the_root(tmpdir: TempDir, port: u16) -> Result<(), Error> { .success(); assert!(curl_successful); - child.kill()?; - Ok(()) } #[rstest] /// We can navigate into directories and back using shown links. -fn can_navigate_into_dirs_and_back(tmpdir: TempDir, port: u16) -> Result<(), Error> { - let mut child = Command::cargo_bin("miniserve")? - .arg("-p") - .arg(port.to_string()) - .arg(tmpdir.path()) - .stdout(Stdio::null()) - .spawn()?; - - sleep(Duration::from_secs(1)); - - let base_url = Url::parse(&format!("http://localhost:{}/", port))?; +fn can_navigate_into_dirs_and_back(server: TestServer) -> Result<(), Error> { + let base_url = server.url(); let initial_body = reqwest::blocking::get(base_url.as_str())?.error_for_status()?; let initial_parsed = Document::from_read(initial_body)?; for &directory in DIRECTORIES { @@ -105,23 +63,12 @@ fn can_navigate_into_dirs_and_back(tmpdir: TempDir, port: u16) -> Result<(), Err assert_eq!(resp.url().as_str(), base_url.as_str()); } - child.kill()?; - Ok(()) } #[rstest] /// We can navigate deep into the file tree and back using shown links. -fn can_navigate_deep_into_dirs_and_back(tmpdir: TempDir, port: u16) -> Result<(), Error> { - let mut child = Command::cargo_bin("miniserve")? - .arg("-p") - .arg(port.to_string()) - .arg(tmpdir.path()) - .stdout(Stdio::null()) - .spawn()?; - - sleep(Duration::from_secs(1)); - +fn can_navigate_deep_into_dirs_and_back(server: TestServer) -> Result<(), Error> { // Create a vector of directory names. We don't need to fetch the file and so we'll // remove that part. let dir_names = { @@ -132,7 +79,7 @@ fn can_navigate_deep_into_dirs_and_back(tmpdir: TempDir, port: u16) -> Result<() comps.pop(); comps }; - let base_url = Url::parse(&format!("http://localhost:{}/", port))?; + let base_url = server.url(); // First we'll go forwards through the directory tree and then we'll go backwards. // In the end, we'll have to end up where we came from. @@ -157,29 +104,17 @@ fn can_navigate_deep_into_dirs_and_back(tmpdir: TempDir, port: u16) -> Result<() } assert_eq!(base_url, next_url); - child.kill()?; - Ok(()) } -#[rstest(use_custom_title, case(true), case(false))] +#[rstest] +#[case(server(&["--title", "some title"]), "some title")] +#[case(server(None::<&str>), format!("localhost:{}", server.port()))] /// We can use breadcrumbs to navigate. fn can_navigate_using_breadcrumbs( - tmpdir: TempDir, - port: u16, - use_custom_title: bool, + #[case] server: TestServer, + #[case] title_name: String, ) -> Result<(), Error> { - let mut command_base = Command::cargo_bin("miniserve")?; - let mut command = command_base.arg("-p").arg(port.to_string()); - - if use_custom_title { - command = command.arg("--title").arg("some title") - } - - let mut child = command.arg(tmpdir.path()).stdout(Stdio::null()).spawn()?; - - sleep(Duration::from_secs(1)); - // Create a vector of directory names. We don't need to fetch the file and so we'll // remove that part. let dir: String = { @@ -191,19 +126,13 @@ fn can_navigate_using_breadcrumbs( comps.join("") }; - let base_url = Url::parse(&format!("http://localhost:{}/", port))?; + let base_url = server.url(); let nested_url = base_url.join(&dir)?; let resp = reqwest::blocking::get(nested_url.as_str())?; let body = resp.error_for_status()?; let parsed = Document::from_read(body)?; - let title_name = if use_custom_title { - "some title".to_string() - } else { - format!("localhost:{}", port) - }; - // can go back to root dir by clicking title let title_link = get_link_from_text(&parsed, &title_name).expect("Root dir link not found."); assert_eq!("/", title_link); @@ -217,7 +146,5 @@ fn can_navigate_using_breadcrumbs( let current_dir_link = get_link_from_text(&parsed, "nested"); assert_eq!(None, current_dir_link); - child.kill()?; - Ok(()) } diff --git a/tests/qrcode.rs b/tests/qrcode.rs index d9a5529..a9c27fe 100644 --- a/tests/qrcode.rs +++ b/tests/qrcode.rs @@ -1,74 +1,34 @@ mod fixtures; -use assert_cmd::prelude::*; -use assert_fs::fixture::TempDir; -use fixtures::{port, tmpdir, Error}; +use fixtures::{server, server_no_stderr, Error, TestServer}; use reqwest::StatusCode; use rstest::rstest; use select::document::Document; use select::predicate::Attr; use std::iter::repeat_with; -use std::process::{Command, Stdio}; -use std::thread::sleep; -use std::time::Duration; #[rstest] -fn hide_qrcode_element(tmpdir: TempDir, port: u16) -> Result<(), Error> { - let mut child = Command::cargo_bin("miniserve")? - .arg(tmpdir.path()) - .arg("-p") - .arg(port.to_string()) - .stdout(Stdio::null()) - .spawn()?; - - sleep(Duration::from_secs(1)); - - let body = reqwest::blocking::get(format!("http://localhost:{}", port).as_str())? - .error_for_status()?; +fn hide_qrcode_element(server: TestServer) -> Result<(), Error> { + let body = reqwest::blocking::get(server.url())?.error_for_status()?; let parsed = Document::from_read(body)?; assert!(parsed.find(Attr("id", "qrcode")).next().is_none()); - child.kill()?; - Ok(()) } #[rstest] -fn show_qrcode_element(tmpdir: TempDir, port: u16) -> Result<(), Error> { - let mut child = Command::cargo_bin("miniserve")? - .arg(tmpdir.path()) - .arg("-p") - .arg(port.to_string()) - .arg("-q") - .stdout(Stdio::null()) - .spawn()?; - - sleep(Duration::from_secs(1)); - - let body = reqwest::blocking::get(format!("http://localhost:{}", port).as_str())? - .error_for_status()?; +fn show_qrcode_element(#[with(&["-q"])] server: TestServer) -> Result<(), Error> { + let body = reqwest::blocking::get(server.url())?.error_for_status()?; let parsed = Document::from_read(body)?; assert!(parsed.find(Attr("id", "qrcode")).next().is_some()); - child.kill()?; - Ok(()) } #[rstest] -fn get_svg_qrcode(tmpdir: TempDir, port: u16) -> Result<(), Error> { - let mut child = Command::cargo_bin("miniserve")? - .arg(tmpdir.path()) - .arg("-p") - .arg(port.to_string()) - .stdout(Stdio::null()) - .stderr(Stdio::null()) - .spawn()?; - - sleep(Duration::from_secs(1)); - +fn get_svg_qrcode(#[from(server_no_stderr)] server: TestServer) -> Result<(), Error> { // Ok - let resp = reqwest::blocking::get(format!("http://localhost:{}/?qrcode=test", port).as_str())?; + let resp = reqwest::blocking::get(server.url().join("/?qrcode=test")?)?; assert_eq!(resp.status(), StatusCode::OK); assert_eq!(resp.headers()["Content-Type"], "image/svg+xml"); @@ -78,12 +38,9 @@ fn get_svg_qrcode(tmpdir: TempDir, port: u16) -> Result<(), Error> { // Err let content: String = repeat_with(|| '0').take(8 * 1024).collect(); - let resp = - reqwest::blocking::get(format!("http://localhost:{}/?qrcode={}", port, content).as_str())?; + let resp = reqwest::blocking::get(server.url().join(&format!("?qrcode={}", content))?)?; assert_eq!(resp.status(), StatusCode::URI_TOO_LONG); - child.kill()?; - Ok(()) } diff --git a/tests/serve_request.rs b/tests/serve_request.rs index e259b9e..361801b 100644 --- a/tests/serve_request.rs +++ b/tests/serve_request.rs @@ -2,13 +2,14 @@ mod fixtures; use assert_cmd::prelude::*; use assert_fs::fixture::TempDir; -use fixtures::{port, tmpdir, Error, DIRECTORIES, FILES, HIDDEN_DIRECTORIES, HIDDEN_FILES}; +use fixtures::{ + port, server, tmpdir, Error, TestServer, DIRECTORIES, FILES, HIDDEN_DIRECTORIES, HIDDEN_FILES, +}; use http::StatusCode; use regex::Regex; use rstest::rstest; use select::document::Document; use select::node::Node; -use std::path::Path; use std::process::{Command, Stdio}; use std::thread::sleep; use std::time::Duration; @@ -39,28 +40,13 @@ fn serves_requests_with_no_options(tmpdir: TempDir) -> Result<(), Error> { } #[rstest] -fn serves_requests_with_non_default_port(tmpdir: TempDir, port: u16) -> Result<(), Error> { - let mut child = Command::cargo_bin("miniserve")? - .arg(tmpdir.path()) - .arg("-p") - .arg(port.to_string()) - .stdout(Stdio::null()) - .spawn()?; - - sleep(Duration::from_secs(1)); - - let body = reqwest::blocking::get(format!("http://localhost:{}", port).as_str())? - .error_for_status()?; +fn serves_requests_with_non_default_port(server: TestServer) -> Result<(), Error> { + let body = reqwest::blocking::get(server.url())?.error_for_status()?; let parsed = Document::from_read(body)?; for &file in FILES { let f = parsed.find(|x: &Node| x.text() == file).next().unwrap(); - reqwest::blocking::get(format!( - "http://localhost:{}/{}", - port, - f.attr("href").unwrap() - ))? - .error_for_status()?; + reqwest::blocking::get(server.url().join(f.attr("href").unwrap())?)?.error_for_status()?; assert_eq!( format!("/{}", file), percent_encoding::percent_decode_str(f.attr("href").unwrap()).decode_utf8_lossy(), @@ -73,8 +59,7 @@ fn serves_requests_with_non_default_port(tmpdir: TempDir, port: u16) -> Result<( .next() .is_some()); let dir_body = - reqwest::blocking::get(format!("http://localhost:{}/{}", port, directory).as_str())? - .error_for_status()?; + reqwest::blocking::get(server.url().join(&directory)?)?.error_for_status()?; let dir_body_parsed = Document::from_read(dir_body)?; for &file in FILES { assert!(dir_body_parsed @@ -84,25 +69,12 @@ fn serves_requests_with_non_default_port(tmpdir: TempDir, port: u16) -> Result<( } } - child.kill()?; - Ok(()) } #[rstest] -fn serves_requests_hidden_files(tmpdir: TempDir, port: u16) -> Result<(), Error> { - let mut child = Command::cargo_bin("miniserve")? - .arg(tmpdir.path()) - .arg("-p") - .arg(port.to_string()) - .arg("--hidden") - .stdout(Stdio::null()) - .spawn()?; - - sleep(Duration::from_secs(1)); - - let body = reqwest::blocking::get(format!("http://localhost:{}", port).as_str())? - .error_for_status()?; +fn serves_requests_hidden_files(#[with(&["--hidden"])] server: TestServer) -> Result<(), Error> { + let body = reqwest::blocking::get(server.url())?.error_for_status()?; let parsed = Document::from_read(body)?; for &file in FILES.into_iter().chain(HIDDEN_FILES) { @@ -119,8 +91,7 @@ fn serves_requests_hidden_files(tmpdir: TempDir, port: u16) -> Result<(), Error> .next() .is_some()); let dir_body = - reqwest::blocking::get(format!("http://localhost:{}/{}", port, directory).as_str())? - .error_for_status()?; + reqwest::blocking::get(server.url().join(&directory)?)?.error_for_status()?; let dir_body_parsed = Document::from_read(dir_body)?; for &file in FILES.into_iter().chain(HIDDEN_FILES) { assert!(dir_body_parsed @@ -130,24 +101,12 @@ fn serves_requests_hidden_files(tmpdir: TempDir, port: u16) -> Result<(), Error> } } - child.kill()?; - Ok(()) } #[rstest] -fn serves_requests_no_hidden_files_without_flag(tmpdir: TempDir, port: u16) -> Result<(), Error> { - let mut child = Command::cargo_bin("miniserve")? - .arg(tmpdir.path()) - .arg("-p") - .arg(port.to_string()) - .stdout(Stdio::null()) - .spawn()?; - - sleep(Duration::from_secs(1)); - - let body = reqwest::blocking::get(format!("http://localhost:{}", port).as_str())? - .error_for_status()?; +fn serves_requests_no_hidden_files_without_flag(server: TestServer) -> Result<(), Error> { + let body = reqwest::blocking::get(server.url())?.error_for_status()?; let parsed = Document::from_read(body)?; for &hidden_item in HIDDEN_FILES.into_iter().chain(HIDDEN_DIRECTORIES) { @@ -155,54 +114,38 @@ fn serves_requests_no_hidden_files_without_flag(tmpdir: TempDir, port: u16) -> R .find(|x: &Node| x.text() == hidden_item) .next() .is_none()); - let resp = - reqwest::blocking::get(format!("http://localhost:{}/{}", port, hidden_item).as_str())?; + let resp = reqwest::blocking::get(server.url().join(&hidden_item)?)?; assert_eq!(resp.status(), StatusCode::BAD_REQUEST); } - child.kill()?; - Ok(()) } -#[rstest(no_symlinks, case(true), case(false))] -fn serves_requests_symlinks(tmpdir: TempDir, port: u16, no_symlinks: bool) -> Result<(), Error> { - let mut comm = Command::cargo_bin("miniserve")?; - comm.arg(tmpdir.path()) - .arg("-p") - .arg(port.to_string()) - .stdout(Stdio::null()); - if no_symlinks { - comm.arg("--no-symlinks"); - } - - let mut child = comm.spawn()?; - sleep(Duration::from_secs(1)); - +#[rstest] +#[case(true, server(&["--no-symlinks"]))] +#[case(false, server(None::<&str>))] +fn serves_requests_symlinks( + #[case] no_symlinks: bool, + #[case] server: TestServer, +) -> Result<(), Error> { let files = &["symlink-file.html"]; let dirs = &["symlink-dir/"]; let broken = &["symlink broken"]; for &directory in dirs { - let orig = Path::new(DIRECTORIES[0].strip_suffix("/").unwrap()); - let link = tmpdir - .path() - .join(Path::new(directory.strip_suffix("/").unwrap())); + let orig = DIRECTORIES[0].strip_suffix("/").unwrap(); + let link = server.path().join(directory.strip_suffix("/").unwrap()); symlink_dir(orig, link).expect("Couldn't create symlink"); } for &file in files { - let orig = Path::new(FILES[0]); - let link = tmpdir.path().join(Path::new(file)); - symlink_file(orig, link).expect("Couldn't create symlink"); + symlink_file(FILES[0], server.path().join(file)).expect("Couldn't create symlink"); } for &file in broken { - let orig = Path::new("should-not-exist.xxx"); - let link = tmpdir.path().join(Path::new(file)); - symlink_file(orig, link).expect("Couldn't create symlink"); + symlink_file("should-not-exist.xxx", server.path().join(file)) + .expect("Couldn't create symlink"); } - let body = reqwest::blocking::get(format!("http://localhost:{}", port).as_str())? - .error_for_status()?; + let body = reqwest::blocking::get(server.url())?.error_for_status()?; let parsed = Document::from_read(body)?; for &entry in files.into_iter().chain(dirs) { @@ -216,8 +159,7 @@ fn serves_requests_symlinks(tmpdir: TempDir, port: u16, no_symlinks: bool) -> Re let node = node.unwrap(); assert_eq!(node.attr("href").unwrap().strip_prefix("/").unwrap(), entry); - reqwest::blocking::get(format!("http://localhost:{}/{}", port, entry))? - .error_for_status()?; + reqwest::blocking::get(server.url().join(&entry)?)?.error_for_status()?; if entry.ends_with("/") { assert_eq!(node.attr("class").unwrap(), "directory"); } else { @@ -228,8 +170,6 @@ fn serves_requests_symlinks(tmpdir: TempDir, port: u16, no_symlinks: bool) -> Re assert!(parsed.find(|x: &Node| x.text() == entry).next().is_none()); } - child.kill()?; - Ok(()) } diff --git a/tests/tls.rs b/tests/tls.rs new file mode 100644 index 0000000..2464e1f --- /dev/null +++ b/tests/tls.rs @@ -0,0 +1,53 @@ +mod fixtures; + +use assert_cmd::Command; +use fixtures::{server, Error, TestServer, FILES}; +use predicates::str::contains; +use reqwest::blocking::ClientBuilder; +use rstest::rstest; +use select::{document::Document, node::Node}; + +/// Can start the server with TLS and receive encrypted responses. +#[rstest] +fn tls_works( + #[with(&[ + "--tls-cert", "tests/data/cert.pem", + "--tls-key", "tests/data/key.pem" + ])] + server: TestServer, +) -> Result<(), Error> { + let client = ClientBuilder::new() + .danger_accept_invalid_certs(true) + .build()?; + let body = client.get(server.url()).send()?.error_for_status()?; + let parsed = Document::from_read(body)?; + for &file in FILES { + assert!(parsed.find(|x: &Node| x.text() == file).next().is_some()); + } + + Ok(()) +} + +/// Wrong path for cert throws error. +#[rstest] +fn wrong_path_cert() -> Result<(), Error> { + Command::cargo_bin("miniserve")? + .args(&["--tls-cert", "wrong", "--tls-key", "tests/data/key.pem"]) + .assert() + .failure() + .stderr(contains("Error: Couldn't access TLS certificate \"wrong\"")); + + Ok(()) +} + +/// Wrong paths for key throws errors. +#[rstest] +fn wrong_path_key() -> Result<(), Error> { + Command::cargo_bin("miniserve")? + .args(&["--tls-cert", "tests/data/cert.pem", "--tls-key", "wrong"]) + .assert() + .failure() + .stderr(contains("Error: Couldn't access TLS key \"wrong\"")); + + Ok(()) +} diff --git a/tests/upload_files.rs b/tests/upload_files.rs index 58707c5..698eb46 100644 --- a/tests/upload_files.rs +++ b/tests/upload_files.rs @@ -1,33 +1,17 @@ mod fixtures; -use assert_cmd::prelude::*; -use assert_fs::fixture::TempDir; -use fixtures::{port, tmpdir, Error}; +use fixtures::{server, Error, TestServer}; use reqwest::blocking::{multipart, Client}; use rstest::rstest; use select::document::Document; use select::predicate::{Attr, Text}; -use std::process::{Command, Stdio}; -use std::thread::sleep; -use std::time::Duration; #[rstest] -fn uploading_files_works(tmpdir: TempDir, port: u16) -> Result<(), Error> { +fn uploading_files_works(#[with(&["-u"])] server: TestServer) -> Result<(), Error> { let test_file_name = "uploaded test file.txt"; - let mut child = Command::cargo_bin("miniserve")? - .arg(tmpdir.path()) - .arg("-p") - .arg(port.to_string()) - .arg("-u") - .stdout(Stdio::null()) - .spawn()?; - - sleep(Duration::from_secs(1)); - // Before uploading, check whether the uploaded file does not yet exist. - let body = reqwest::blocking::get(format!("http://localhost:{}", port).as_str())? - .error_for_status()?; + let body = reqwest::blocking::get(server.url())?.error_for_status()?; let parsed = Document::from_read(body)?; assert!(parsed.find(Text).all(|x| x.text() != test_file_name)); @@ -46,37 +30,25 @@ fn uploading_files_works(tmpdir: TempDir, port: u16) -> Result<(), Error> { let client = Client::new(); client - .post(format!("http://localhost:{}{}", port, upload_action).as_str()) + .post(server.url().join(upload_action)?) .multipart(form) .send()? .error_for_status()?; // After uploading, check whether the uploaded file is now getting listed. - let body = reqwest::blocking::get(format!("http://localhost:{}", port).as_str())?; + let body = reqwest::blocking::get(server.url())?; let parsed = Document::from_read(body)?; assert!(parsed.find(Text).any(|x| x.text() == test_file_name)); - child.kill()?; - Ok(()) } #[rstest] -fn uploading_files_is_prevented(tmpdir: TempDir, port: u16) -> Result<(), Error> { +fn uploading_files_is_prevented(server: TestServer) -> Result<(), Error> { let test_file_name = "uploaded test file.txt"; - let mut child = Command::cargo_bin("miniserve")? - .arg(tmpdir.path()) - .arg("-p") - .arg(port.to_string()) - .stdout(Stdio::null()) - .spawn()?; - - sleep(Duration::from_secs(1)); - // Before uploading, check whether the uploaded file does not yet exist. - let body = reqwest::blocking::get(format!("http://localhost:{}", port).as_str())? - .error_for_status()?; + let body = reqwest::blocking::get(server.url())?.error_for_status()?; let parsed = Document::from_read(body)?; assert!(parsed.find(Text).all(|x| x.text() != test_file_name)); @@ -93,18 +65,16 @@ fn uploading_files_is_prevented(tmpdir: TempDir, port: u16) -> Result<(), Error> let client = Client::new(); // Ensure uploading fails and returns an error assert!(client - .post(format!("http://localhost:{}{}", port, "/upload?path=/").as_str()) + .post(server.url().join("/upload?path=/")?) .multipart(form) .send()? .error_for_status() .is_err()); // After uploading, check whether the uploaded file is now getting listed. - let body = reqwest::blocking::get(format!("http://localhost:{}", port).as_str())?; + let body = reqwest::blocking::get(server.url())?; let parsed = Document::from_read(body)?; assert!(!parsed.find(Text).any(|x| x.text() == test_file_name)); - child.kill()?; - Ok(()) } |