aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/dependabot.yml8
-rw-r--r--.github/workflows/publish.yml14
-rw-r--r--CHANGELOG.md10
-rw-r--r--Cargo.lock1496
-rw-r--r--Cargo.toml32
-rw-r--r--README.md26
-rw-r--r--data/style.scss1
-rw-r--r--src/args.rs10
-rw-r--r--src/auth.rs74
-rw-r--r--src/config.rs192
-rw-r--r--src/file_upload.rs233
-rw-r--r--src/listing.rs68
-rw-r--r--src/main.rs218
-rw-r--r--src/pipe.rs10
-rw-r--r--src/renderer.rs4
-rw-r--r--tests/archive.rs58
-rw-r--r--tests/auth.rs140
-rw-r--r--tests/data/cert.pem29
-rwxr-xr-xtests/data/generate_tls_certs.sh2
-rw-r--r--tests/data/key.pem52
-rw-r--r--tests/fixtures/mod.rs116
-rw-r--r--tests/header.rs24
-rw-r--r--tests/navigation.rs103
-rw-r--r--tests/qrcode.rs59
-rw-r--r--tests/serve_request.rs114
-rw-r--r--tests/tls.rs53
-rw-r--r--tests/upload_files.rs48
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
diff --git a/Cargo.lock b/Cargo.lock
index a3b25b4..ec29418 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -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",
+]
diff --git a/Cargo.toml b/Cargo.toml
index 66fbc2d..72e82b9 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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"
diff --git a/README.md b/README.md
index 82a2de9..ba007e2 100644
--- a/README.md
+++ b/README.md
@@ -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(())
}