aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkhai96_ <hvksmr1996@gmail.com>2019-05-17 07:11:38 +0000
committerkhai96_ <hvksmr1996@gmail.com>2019-05-17 07:11:38 +0000
commita77c71dde6a480c8c6a096b7cacd03de63a5ee6b (patch)
tree41709cb3662e07031cf318cb64404ea2d645bf92
parentUpdate unit tests (diff)
parentMerge pull request #116 from svenstaro/dependabot/cargo/reqwest-0.9.17 (diff)
downloadminiserve-a77c71dde6a480c8c6a096b7cacd03de63a5ee6b.tar.gz
miniserve-a77c71dde6a480c8c6a096b7cacd03de63a5ee6b.zip
Merge remote-tracking branch 'mainrepo/master' into multiple-auths-alt
Diffstat (limited to '')
-rw-r--r--Cargo.lock116
-rw-r--r--Cargo.toml6
-rw-r--r--src/archive.rs43
-rw-r--r--src/args.rs10
-rw-r--r--src/auth.rs87
-rw-r--r--src/errors.rs17
-rw-r--r--src/file_upload.rs120
-rw-r--r--src/listing.rs90
-rw-r--r--src/main.rs88
-rw-r--r--src/renderer.rs221
-rw-r--r--src/themes.rs15
-rw-r--r--tests/auth.rs70
12 files changed, 615 insertions, 268 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 9734566..f66e4f0 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -11,7 +11,7 @@ dependencies = [
"crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -36,7 +36,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"actix 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)",
"bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -69,7 +69,7 @@ dependencies = [
"encoding 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"flate2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"h2 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
"http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -87,7 +87,7 @@ dependencies = [
"percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_urlencoded 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
"sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -408,18 +408,25 @@ dependencies = [
]
[[package]]
+name = "cookie"
+version = "0.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
+ "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "cookie_store"
-version = "0.5.1"
+version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cookie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cookie 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"publicsuffix 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
"try_from 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -637,7 +644,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -743,7 +750,7 @@ dependencies = [
[[package]]
name = "futures"
-version = "0.1.26"
+version = "0.1.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -751,7 +758,7 @@ name = "futures-cpupool"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -792,7 +799,7 @@ dependencies = [
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
"fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
"http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
"indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -861,7 +868,7 @@ version = "0.12.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"h2 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
"http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -888,7 +895,7 @@ version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper 0.12.28 (registry+https://github.com/rust-lang/crates.io-index)",
"native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1132,7 +1139,7 @@ dependencies = [
"chrono-humanize 0.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
"hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"htmlescape 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libflate 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1142,16 +1149,16 @@ dependencies = [
"percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"port_check 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "reqwest 0.9.16 (registry+https://github.com/rust-lang/crates.io-index)",
+ "reqwest 0.9.17 (registry+https://github.com/rust-lang/crates.io-index)",
"rstest 0.2.2 (git+https://github.com/la10736/rstest.git)",
"select 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)",
"sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"simplelog 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"structopt 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
"strum 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
"strum_macros 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "tar 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tar 0.4.25 (registry+https://github.com/rust-lang/crates.io-index)",
"yansi 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1691,16 +1698,16 @@ dependencies = [
[[package]]
name = "reqwest"
-version = "0.9.16"
+version = "0.9.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
"bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
- "cookie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "cookie_store 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cookie 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cookie_store 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"encoding_rs 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
"flate2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
"http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper 0.12.28 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper-tls 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1708,7 +1715,7 @@ dependencies = [
"mime 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
"mime_guess 2.0.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)",
"native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_urlencoded 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1744,7 +1751,7 @@ dependencies = [
[[package]]
name = "rstest"
version = "0.2.2"
-source = "git+https://github.com/la10736/rstest.git#9f2ac13853e876ffef76f49443e7f2eca17cba92"
+source = "git+https://github.com/la10736/rstest.git#7c7211e5d6575ab4c43cd2e35370e94c5167c8b1"
dependencies = [
"cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 0.4.29 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1851,7 +1858,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde"
-version = "1.0.90"
+version = "1.0.91"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1874,7 +1881,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1884,7 +1891,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1977,7 +1984,7 @@ dependencies = [
"lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"phf_shared 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)",
"precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)",
"string_cache_codegen 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -2081,7 +2088,7 @@ dependencies = [
[[package]]
name = "tar"
-version = "0.4.24"
+version = "0.4.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"filetime 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2166,7 +2173,7 @@ version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2190,7 +2197,7 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -2199,7 +2206,7 @@ name = "tokio-current-thread"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -2209,7 +2216,7 @@ version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -2217,7 +2224,7 @@ name = "tokio-fs"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-threadpool 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -2228,7 +2235,7 @@ version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -2238,7 +2245,7 @@ version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2255,7 +2262,7 @@ name = "tokio-signal"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
"mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2272,7 +2279,7 @@ version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -2281,7 +2288,7 @@ version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2296,7 +2303,7 @@ dependencies = [
"crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2310,7 +2317,7 @@ version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -2329,7 +2336,7 @@ version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2343,7 +2350,7 @@ version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2359,7 +2366,7 @@ name = "tower-service"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -2374,7 +2381,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
"idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2397,7 +2404,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
"idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2420,7 +2427,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
"ipconfig 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2612,7 +2619,7 @@ name = "want"
version = "0.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -2739,7 +2746,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
"checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e"
"checksum cookie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1465f8134efa296b4c19db34d909637cb2bf0f7aaf21299e23e18fa29ac557cf"
-"checksum cookie_store 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b0d2f2ecb21dce00e2453268370312978af9b8024020c7a37ae2cc6dbbe64685"
+"checksum cookie 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "888604f00b3db336d2af898ec3c1d5d0ddf5e6d462220f2ededc33a87ac4bbd5"
+"checksum cookie_store 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46750b3f362965f197996c4448e4a0935e791bf7d6631bfce9ee0af3d24c919c"
"checksum core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "25b9e03f145fd4f2bf705e07b900cd41fc636598fe5dc452fd0db1441c3f496d"
"checksum core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b"
"checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb"
@@ -2779,7 +2787,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
"checksum futf 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7c9c1ce3fa9336301af935ab852c437817d14cd33690446569392e65170aac3b"
-"checksum futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" = "62941eff9507c8177d448bd83a44d9b9760856e184081d8cd79ba9f03dd24981"
+"checksum futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)" = "a2037ec1c6c1c4f79557762eab1f7eae1f64f6cb418ace90fae88f0942b60139"
"checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4"
"checksum generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c0f28c2f5bfb5960175af447a2da7c18900693738343dc896ffbcabd9839592"
"checksum globset 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ef4feaabe24a0a658fd9cf4a9acf6ed284f045c77df0f49020ba3245cfb7b454"
@@ -2884,7 +2892,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8f0a0bcab2fd7d1d7c54fa9eae6f43eddeb9ce2e7352f8518a814a4f65d60c58"
"checksum regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dcfd8681eebe297b81d98498869d4aae052137651ad7b96822f09ceb690d0a96"
"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
-"checksum reqwest 0.9.16 (registry+https://github.com/rust-lang/crates.io-index)" = "ddcfd2c13c6af0f9c45a1086be3b9c68af79e4430b42790759e2d34cce2a6c60"
+"checksum reqwest 0.9.17 (registry+https://github.com/rust-lang/crates.io-index)" = "e57803405f8ea0eb041c1567dac36127e0c8caa1251c843cb03d43fd767b3d50"
"checksum resolv-conf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b263b4aa1b5de9ffc0054a2386f96992058bb6870aab516f8cdeb8a667d56dcb"
"checksum ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)" = "2c4db68a2e35f3497146b7e4563df7d4773a2433230c5e4b448328e31740458a"
"checksum rstest 0.2.2 (git+https://github.com/la10736/rstest.git)" = "<none>"
@@ -2902,7 +2910,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum select 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7004292887d0a030e29abda3ae1b63a577c96a17e25d74eaa1952503e6c1c946"
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
-"checksum serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)" = "aa5f7c20820475babd2c077c3ab5f8c77a31c15e16ea38687b4c02d3e48680f4"
+"checksum serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)" = "a72e9b96fa45ce22a4bc23da3858dfccfd60acd28a25bcd328a98fdd6bea43fd"
"checksum serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)" = "58fc82bec244f168b23d1963b45c8bf5726e9a15a9d146a067f9081aeed2de79"
"checksum serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d"
"checksum serde_urlencoded 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "642dd69105886af2efd227f75a520ec9b44a820d65bc133a9131f7d229fd165a"
@@ -2929,7 +2937,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum syn 0.15.33 (registry+https://github.com/rust-lang/crates.io-index)" = "ec52cd796e5f01d0067225a5392e70084acc4c0013fa71d55166d38a8b307836"
"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
"checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015"
-"checksum tar 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)" = "2dd071a2604c8fd8902ca42908856821ed7a06e3cd846f84d75873c978dec7fb"
+"checksum tar 0.4.25 (registry+https://github.com/rust-lang/crates.io-index)" = "7201214ded95b34e3bc00c9557b6dcec34fd1af428d343143f5db67c661762f0"
"checksum tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b86c784c88d98c801132806dadd3819ed29d8600836c4088e855cdf3e178ed8a"
"checksum tendril 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1b72f8e2f5b73b65c315b1a70c730f24b9d7a25f39e98de8acbe2bb795caea"
"checksum term 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "edd106a334b7657c10b7c540a0106114feadeb4dc314513e97df481d5d966f42"
diff --git a/Cargo.toml b/Cargo.toml
index a345f7e..dba00c7 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -36,10 +36,10 @@ structopt = "0.2.15"
chrono = "0.4.6"
chrono-humanize = "0.0.11"
maud = { version = "0.20.0", features = ["actix-web"] }
-serde = { version = "1.0.90", features = ["derive"] }
-tar = "0.4.24"
+serde = { version = "1.0.91", features = ["derive"] }
+tar = "0.4.25"
bytes = "0.4.12"
-futures = "0.1.26"
+futures = "0.1.27"
libflate = "0.1.21"
failure = "0.1.5"
log = "0.4.6"
diff --git a/src/archive.rs b/src/archive.rs
index a76446a..02300c5 100644
--- a/src/archive.rs
+++ b/src/archive.rs
@@ -7,7 +7,7 @@ use std::path::PathBuf;
use strum_macros::{Display, EnumIter, EnumString};
use tar::Builder;
-use crate::errors::{ContextualError};
+use crate::errors::ContextualError;
/// Available compression methods
#[derive(Deserialize, Clone, EnumIter, EnumString, Display)]
@@ -62,17 +62,11 @@ fn tgz_compress(dir: &PathBuf, skip_symlinks: bool) -> Result<(String, Bytes), C
let mut tgz_data = Bytes::new();
let tar_data = tar(src_dir, directory.to_string(), skip_symlinks).map_err(|e| {
- ContextualError::ArchiveCreationError(
- "tarball".to_string(),
- Box::new(e),
- )
+ ContextualError::ArchiveCreationError("tarball".to_string(), Box::new(e))
})?;
let gz_data = gzip(&tar_data).map_err(|e| {
- ContextualError::ArchiveCreationError(
- "GZIP archive".to_string(),
- Box::new(e),
- )
+ ContextualError::ArchiveCreationError("GZIP archive".to_string(), Box::new(e))
})?;
tgz_data.extend_from_slice(&gz_data);
@@ -115,10 +109,7 @@ fn tar(
})?;
let tar_content = tar_builder.into_inner().map_err(|e| {
- ContextualError::IOError(
- "Failed to finish writing the TAR archive".to_string(),
- e,
- )
+ ContextualError::IOError("Failed to finish writing the TAR archive".to_string(), e)
})?;
Ok(tar_content)
@@ -126,24 +117,14 @@ fn tar(
/// Compresses a stream of bytes using the GZIP algorithm, and returns the resulting stream
fn gzip(mut data: &[u8]) -> Result<Vec<u8>, ContextualError> {
- let mut encoder = Encoder::new(Vec::new()).map_err(|e| {
- ContextualError::IOError(
- "Failed to create GZIP encoder".to_string(),
- e,
- )
- })?;
- io::copy(&mut data, &mut encoder).map_err(|e| {
- ContextualError::IOError(
- "Failed to write GZIP data".to_string(),
- e,
- )
- })?;
- let data = encoder.finish().into_result().map_err(|e| {
- ContextualError::IOError(
- "Failed to write GZIP trailer".to_string(),
- e,
- )
- })?;
+ let mut encoder = Encoder::new(Vec::new())
+ .map_err(|e| ContextualError::IOError("Failed to create GZIP encoder".to_string(), e))?;
+ io::copy(&mut data, &mut encoder)
+ .map_err(|e| ContextualError::IOError("Failed to write GZIP data".to_string(), e))?;
+ let data = encoder
+ .finish()
+ .into_result()
+ .map_err(|e| ContextualError::IOError("Failed to write GZIP trailer".to_string(), e))?;
Ok(data)
}
diff --git a/src/args.rs b/src/args.rs
index 39efe7e..11357c2 100644
--- a/src/args.rs
+++ b/src/args.rs
@@ -3,7 +3,7 @@ use std::path::PathBuf;
use structopt::StructOpt;
use crate::auth;
-use crate::errors::{ContextualError};
+use crate::errors::ContextualError;
use crate::themes;
/// Possible characters for random routes
@@ -40,6 +40,7 @@ struct CLIArgs {
/// Set authentication. Currently supported formats:
/// username:password, username:sha256:hash, username:sha512:hash
+ /// (e.g. joe:123, joe:sha256:a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3)
#[structopt(short = "a", long = "auth", parse(try_from_str = "parse_auth"))]
auth: Vec<auth::RequiredAuth>,
@@ -98,15 +99,13 @@ fn parse_auth(src: &str) -> Result<auth::RequiredAuth, ContextualError> {
let hash_bin = if let Ok(hash_bin) = hex::decode(hash_hex) {
hash_bin
} else {
- return Err(ContextualError::InvalidPasswordHash)
+ return Err(ContextualError::InvalidPasswordHash);
};
match second_part {
"sha256" => auth::RequiredAuthPassword::Sha256(hash_bin.to_owned()),
"sha512" => auth::RequiredAuthPassword::Sha512(hash_bin.to_owned()),
- _ => {
- return Err(ContextualError::InvalidHashMethod(second_part.to_owned()))
- },
+ _ => return Err(ContextualError::InvalidHashMethod(second_part.to_owned())),
}
} else {
// To make it Windows-compatible, the password needs to be shorter than 255 characters.
@@ -163,6 +162,7 @@ pub fn parse_args() -> crate::MiniserveConfig {
}
}
+#[rustfmt::skip]
#[cfg(test)]
mod tests {
use super::*;
diff --git a/src/auth.rs b/src/auth.rs
index da5f4a9..3828265 100644
--- a/src/auth.rs
+++ b/src/auth.rs
@@ -1,9 +1,10 @@
-use actix_web::http::header;
+use actix_web::http::{header, StatusCode};
use actix_web::middleware::{Middleware, Response};
use actix_web::{HttpRequest, HttpResponse, Result};
use sha2::{Digest, Sha256, Sha512};
-use crate::errors::{ContextualError};
+use crate::errors::{self, ContextualError};
+use crate::renderer;
pub struct Auth;
@@ -36,10 +37,7 @@ pub fn parse_basic_auth(
let basic_removed = authorization_header
.to_str()
.map_err(|e| {
- ContextualError::ParseError(
- "HTTP authentication header".to_string(),
- e.to_string(),
- )
+ ContextualError::ParseError("HTTP authentication header".to_string(), e.to_string())
})?
.replace("Basic ", "");
let decoded = base64::decode(&basic_removed).map_err(ContextualError::Base64DecodeError)?;
@@ -109,7 +107,14 @@ impl Middleware<crate::MiniserveConfig> for Auth {
Err(err) => {
let auth_err = ContextualError::HTTPAuthenticationError(Box::new(err));
return Ok(Response::Done(
- HttpResponse::BadRequest().body(auth_err.to_string()),
+ HttpResponse::BadRequest().body(
+ build_unauthorized_response(
+ &req,
+ auth_err,
+ true,
+ StatusCode::BAD_REQUEST,
+ ),
+ ),
));
}
};
@@ -118,20 +123,68 @@ impl Middleware<crate::MiniserveConfig> for Auth {
return Ok(Response::Done(resp));
}
- let new_resp = HttpResponse::Unauthorized().finish();
- return Ok(Response::Done(new_resp));
+ return Ok(Response::Done(
+ HttpResponse::Unauthorized().body(
+ build_unauthorized_response(
+ &req,
+ ContextualError::InvalidHTTPCredentials,
+ true,
+ StatusCode::UNAUTHORIZED,
+ )
+ )
+ ));
}
- let new_resp = HttpResponse::Unauthorized()
- .header(
- header::WWW_AUTHENTICATE,
- header::HeaderValue::from_static("Basic realm=\"miniserve\""),
- )
- .finish();
- Ok(Response::Done(new_resp))
+ Ok(Response::Done(
+ HttpResponse::Unauthorized()
+ .header(
+ header::WWW_AUTHENTICATE,
+ header::HeaderValue::from_static("Basic realm=\"miniserve\""),
+ )
+ .body(build_unauthorized_response(
+ &req,
+ ContextualError::InvalidHTTPCredentials,
+ true,
+ StatusCode::UNAUTHORIZED,
+ ))
+ ))
}
}
+/// Builds the unauthorized response body
+/// The reason why log_error_chain is optional is to handle cases where the auth pop-up appears and when the user clicks Cancel.
+/// In those case, we do not log the error to the terminal since it does not really matter.
+fn build_unauthorized_response(
+ req: &HttpRequest<crate::MiniserveConfig>,
+ error: ContextualError,
+ log_error_chain: bool,
+ error_code: StatusCode,
+) -> String {
+ let error = ContextualError::HTTPAuthenticationError(Box::new(error));
+
+ if log_error_chain {
+ errors::log_error_chain(error.to_string());
+ }
+ let return_path = match &req.state().random_route {
+ Some(random_route) => format!("/{}", random_route),
+ None => "/".to_string(),
+ };
+
+ renderer::render_error(
+ &error.to_string(),
+ error_code,
+ &return_path,
+ None,
+ None,
+ req.state().default_color_scheme,
+ req.state().default_color_scheme,
+ false,
+ false,
+ )
+ .into_string()
+}
+
+#[rustfmt::skip]
#[cfg(test)]
mod tests {
use super::*;
@@ -182,7 +235,7 @@ mod tests {
case(true, "obi", "hello there", "obi", "hello there", "sha256"),
case(false, "obi", "hello there", "obi", "hi!", "sha256"),
case(true, "obi", "hello there", "obi", "hello there", "sha512"),
- case(false, "obi", "hello there", "obi", "hi!", "sha512"),
+ case(false, "obi", "hello there", "obi", "hi!", "sha512")
)]
fn test_single_auth(
should_pass: bool,
diff --git a/src/errors.rs b/src/errors.rs
index b8af25d..2878e37 100644
--- a/src/errors.rs
+++ b/src/errors.rs
@@ -32,7 +32,10 @@ pub enum ContextualError {
InvalidAuthFormat,
/// This error might occure if the hash method is neither sha256 nor sha512
- #[fail(display = "{} is not a valid hashing method. Expected sha256 or sha512", _0)]
+ #[fail(
+ display = "{} is not a valid hashing method. Expected sha256 or sha512",
+ _0
+ )]
InvalidHashMethod(String),
/// This error might occur if the HTTP auth hash password is not a valid hex code
@@ -64,6 +67,18 @@ pub enum ContextualError {
_0
)]
HTTPAuthenticationError(Box<ContextualError>),
+
+ /// This error might occur when the HTTP credentials are not correct
+ #[fail(display = "Invalid credentials for HTTP authentication")]
+ InvalidHTTPCredentials,
+
+ /// This error might occur when an HTTP request is invalid
+ #[fail(display = "Invalid HTTP request\ncaused by: {}", _0)]
+ InvalidHTTPRequestError(String),
+
+ /// This error might occur when trying to access a page that does not exist
+ #[fail(display = "Route {} could not be found", _0)]
+ RouteNotFoundError(String),
}
pub fn log_error_chain(description: String) {
diff --git a/src/file_upload.rs b/src/file_upload.rs
index 7f9cede..537c90c 100644
--- a/src/file_upload.rs
+++ b/src/file_upload.rs
@@ -1,9 +1,9 @@
use actix_web::{
- dev, http::header, multipart, FromRequest, FutureResponse, HttpMessage, HttpRequest,
- HttpResponse, Query,
+ dev,
+ http::{header, StatusCode},
+ multipart, FutureResponse, HttpMessage, HttpRequest, HttpResponse,
};
use futures::{future, future::FutureResult, Future, Stream};
-use serde::Deserialize;
use std::{
fs,
io::Write,
@@ -11,13 +11,9 @@ use std::{
};
use crate::errors::{self, ContextualError};
+use crate::listing::{self, SortingMethod, SortingOrder};
use crate::renderer;
-
-/// Query parameters
-#[derive(Debug, Deserialize)]
-struct QueryParameters {
- path: PathBuf,
-}
+use crate::themes::ColorScheme;
/// Create future to save file.
fn save_file(
@@ -35,7 +31,7 @@ fn save_file(
Ok(file) => file,
Err(e) => {
return Box::new(future::err(ContextualError::IOError(
- format!("Failed to create file in {}", file_path.display()),
+ format!("Failed to create {}", file_path.display()),
e,
)));
}
@@ -121,37 +117,75 @@ fn handle_multipart(
/// server root directory. Any path which will go outside of this directory is considered
/// invalid.
/// This method returns future.
-pub fn upload_file(req: &HttpRequest<crate::MiniserveConfig>) -> FutureResponse<HttpResponse> {
+pub fn upload_file(
+ req: &HttpRequest<crate::MiniserveConfig>,
+ default_color_scheme: ColorScheme,
+) -> FutureResponse<HttpResponse> {
let return_path = if let Some(header) = req.headers().get(header::REFERER) {
header.to_str().unwrap_or("/").to_owned()
} else {
"/".to_string()
};
- let app_root_dir = if let Ok(dir) = req.state().path.canonicalize() {
- dir
- } else {
- return Box::new(create_error_response("Internal server error", &return_path));
- };
- let path = match Query::<QueryParameters>::extract(req) {
- Ok(query) => {
- if let Ok(stripped_path) = query.path.strip_prefix(Component::RootDir) {
- stripped_path.to_owned()
- } else {
- query.path.clone()
- }
+
+ let query_params = listing::extract_query_parameters(req);
+ let color_scheme = query_params.theme.unwrap_or(default_color_scheme);
+ let upload_path = match query_params.path.clone() {
+ Some(path) => match path.strip_prefix(Component::RootDir) {
+ Ok(stripped_path) => stripped_path.to_owned(),
+ Err(_) => path.clone(),
+ },
+ None => {
+ let err = ContextualError::InvalidHTTPRequestError(
+ "Missing query parameter 'path'".to_string(),
+ );
+ return Box::new(create_error_response(
+ &err.to_string(),
+ StatusCode::BAD_REQUEST,
+ &return_path,
+ query_params.sort,
+ query_params.order,
+ color_scheme,
+ default_color_scheme,
+ ));
}
- Err(_) => {
+ };
+
+ let app_root_dir = match req.state().path.canonicalize() {
+ Ok(dir) => dir,
+ Err(e) => {
+ let err = ContextualError::IOError(
+ "Failed to resolve path served by miniserve".to_string(),
+ e,
+ );
return Box::new(create_error_response(
- "Unspecified parameter path",
+ &err.to_string(),
+ StatusCode::INTERNAL_SERVER_ERROR,
&return_path,
- ))
+ query_params.sort,
+ query_params.order,
+ color_scheme,
+ default_color_scheme,
+ ));
}
};
// If the target path is under the app root directory, save the file.
- let target_dir = match &app_root_dir.clone().join(path).canonicalize() {
+ let target_dir = match &app_root_dir.clone().join(upload_path).canonicalize() {
Ok(path) if path.starts_with(&app_root_dir) => path.clone(),
- _ => return Box::new(create_error_response("Invalid path", &return_path)),
+ _ => {
+ let err = ContextualError::InvalidHTTPRequestError(
+ "Invalid value for 'path' parameter".to_string(),
+ );
+ return Box::new(create_error_response(
+ &err.to_string(),
+ StatusCode::BAD_REQUEST,
+ &return_path,
+ query_params.sort,
+ query_params.order,
+ color_scheme,
+ default_color_scheme,
+ ));
+ }
};
let overwrite_files = req.state().overwrite_files;
Box::new(
@@ -166,7 +200,15 @@ pub fn upload_file(req: &HttpRequest<crate::MiniserveConfig>) -> FutureResponse<
.header(header::LOCATION, return_path.to_string())
.finish(),
),
- Err(e) => create_error_response(&e.to_string(), &return_path),
+ Err(e) => create_error_response(
+ &e.to_string(),
+ StatusCode::INTERNAL_SERVER_ERROR,
+ &return_path,
+ query_params.sort,
+ query_params.order,
+ color_scheme,
+ default_color_scheme,
+ ),
}),
)
}
@@ -174,12 +216,30 @@ pub fn upload_file(req: &HttpRequest<crate::MiniserveConfig>) -> FutureResponse<
/// Convenience method for creating response errors, if file upload fails.
fn create_error_response(
description: &str,
+ error_code: StatusCode,
return_path: &str,
+ sorting_method: Option<SortingMethod>,
+ sorting_order: Option<SortingOrder>,
+ color_scheme: ColorScheme,
+ default_color_scheme: ColorScheme,
) -> FutureResult<HttpResponse, actix_web::error::Error> {
errors::log_error_chain(description.to_string());
future::ok(
HttpResponse::BadRequest()
.content_type("text/html; charset=utf-8")
- .body(renderer::render_error(description, return_path).into_string()),
+ .body(
+ renderer::render_error(
+ description,
+ error_code,
+ return_path,
+ sorting_method,
+ sorting_order,
+ color_scheme,
+ default_color_scheme,
+ true,
+ true,
+ )
+ .into_string(),
+ ),
)
}
diff --git a/src/listing.rs b/src/listing.rs
index 87fd8a8..49802bc 100644
--- a/src/listing.rs
+++ b/src/listing.rs
@@ -1,3 +1,4 @@
+use actix_web::http::StatusCode;
use actix_web::{fs, http, Body, FromRequest, HttpRequest, HttpResponse, Query, Result};
use bytesize::ByteSize;
use futures::stream::once;
@@ -5,26 +6,27 @@ use htmlescape::encode_minimal as escape_html_entity;
use percent_encoding::{utf8_percent_encode, DEFAULT_ENCODE_SET};
use serde::Deserialize;
use std::io;
-use std::path::Path;
+use std::path::{Path, PathBuf};
use std::time::SystemTime;
use strum_macros::{Display, EnumString};
-use crate::archive;
-use crate::errors;
+use crate::archive::{self, CompressionMethod};
+use crate::errors::{self, ContextualError};
use crate::renderer;
-use crate::themes;
+use crate::themes::ColorScheme;
/// Query parameters
#[derive(Deserialize)]
-struct QueryParameters {
- sort: Option<SortingMethod>,
- order: Option<SortingOrder>,
- download: Option<archive::CompressionMethod>,
- theme: Option<themes::ColorScheme>,
+pub struct QueryParameters {
+ pub path: Option<PathBuf>,
+ pub sort: Option<SortingMethod>,
+ pub order: Option<SortingOrder>,
+ pub theme: Option<ColorScheme>,
+ download: Option<CompressionMethod>,
}
/// Available sorting methods
-#[derive(Deserialize, Clone, EnumString, Display)]
+#[derive(Deserialize, Clone, EnumString, Display, Copy)]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum SortingMethod {
@@ -39,7 +41,7 @@ pub enum SortingMethod {
}
/// Available sorting orders
-#[derive(Deserialize, Clone, EnumString, Display)]
+#[derive(Deserialize, Clone, EnumString, Display, Copy)]
pub enum SortingOrder {
/// Ascending order
#[serde(alias = "asc")]
@@ -130,7 +132,7 @@ pub fn directory_listing<S>(
skip_symlinks: bool,
file_upload: bool,
random_route: Option<String>,
- default_color_scheme: themes::ColorScheme,
+ default_color_scheme: ColorScheme,
upload_route: String,
) -> Result<HttpResponse, io::Error> {
let serve_path = req.path();
@@ -143,23 +145,13 @@ pub fn directory_listing<S>(
Err(_) => base.to_path_buf(),
};
- let (sort_method, sort_order, download, color_scheme) =
- if let Ok(query) = Query::<QueryParameters>::extract(req) {
- (
- query.sort.clone(),
- query.order.clone(),
- query.download.clone(),
- query.theme.clone(),
- )
- } else {
- (None, None, None, None)
- };
+ let query_params = extract_query_parameters(req);
let mut entries: Vec<Entry> = Vec::new();
for entry in dir.path.read_dir()? {
if dir.is_visible(&entry) {
- let entry = entry.unwrap();
+ let entry = entry?;
let p = match entry.path().strip_prefix(&dir.path) {
Ok(p) => base.join(p),
Err(_) => continue,
@@ -211,7 +203,7 @@ pub fn directory_listing<S>(
}
}
- if let Some(sorting_method) = &sort_method {
+ if let Some(sorting_method) = query_params.sort {
match sorting_method {
SortingMethod::Name => entries
.sort_by(|e1, e2| alphanumeric_sort::compare_str(e1.name.clone(), e2.name.clone())),
@@ -235,15 +227,15 @@ pub fn directory_listing<S>(
entries.sort_by(|e1, e2| alphanumeric_sort::compare_str(e1.name.clone(), e2.name.clone()))
}
- if let Some(sorting_order) = &sort_order {
+ if let Some(sorting_order) = query_params.order {
if let SortingOrder::Descending = sorting_order {
entries.reverse()
}
}
- let color_scheme = color_scheme.unwrap_or_else(|| default_color_scheme.clone());
+ let color_scheme = query_params.theme.unwrap_or(default_color_scheme);
- if let Some(compression_method) = &download {
+ if let Some(compression_method) = &query_params.download {
log::info!(
"Creating an archive ({extension}) of {path}...",
extension = compression_method.extension(),
@@ -267,7 +259,20 @@ pub fn directory_listing<S>(
errors::log_error_chain(err.to_string());
Ok(HttpResponse::Ok()
.status(http::StatusCode::INTERNAL_SERVER_ERROR)
- .body(renderer::render_error(&err.to_string(), serve_path).into_string()))
+ .body(
+ renderer::render_error(
+ &err.to_string(),
+ StatusCode::INTERNAL_SERVER_ERROR,
+ serve_path,
+ query_params.sort,
+ query_params.order,
+ color_scheme,
+ default_color_scheme,
+ false,
+ true,
+ )
+ .into_string(),
+ ))
}
}
} else {
@@ -279,8 +284,8 @@ pub fn directory_listing<S>(
entries,
is_root,
page_parent,
- sort_method,
- sort_order,
+ query_params.sort,
+ query_params.order,
default_color_scheme,
color_scheme,
file_upload,
@@ -291,3 +296,26 @@ pub fn directory_listing<S>(
))
}
}
+
+pub fn extract_query_parameters<S>(req: &HttpRequest<S>) -> QueryParameters {
+ match Query::<QueryParameters>::extract(req) {
+ Ok(query) => QueryParameters {
+ sort: query.sort,
+ order: query.order,
+ download: query.download.clone(),
+ theme: query.theme,
+ path: query.path.clone(),
+ },
+ Err(e) => {
+ let err = ContextualError::ParseError("query parameters".to_string(), e.to_string());
+ errors::log_error_chain(err.to_string());
+ QueryParameters {
+ sort: None,
+ order: None,
+ download: None,
+ theme: None,
+ path: None,
+ }
+ }
+ }
+}
diff --git a/src/main.rs b/src/main.rs
index f227be9..f26369a 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,7 +1,7 @@
#![feature(proc_macro_hygiene)]
-use actix_web::http::Method;
-use actix_web::{fs, middleware, server, App};
+use actix_web::http::{Method, StatusCode};
+use actix_web::{fs, middleware, server, App, HttpRequest, HttpResponse};
use clap::crate_version;
use simplelog::{Config, LevelFilter, TermLogger};
use std::io::{self, Write};
@@ -19,7 +19,7 @@ mod listing;
mod renderer;
mod themes;
-use crate::errors::{ContextualError};
+use crate::errors::ContextualError;
#[derive(Clone)]
/// Configuration of the Miniserve application
@@ -83,12 +83,7 @@ fn run() -> Result<(), ContextualError> {
&& miniserve_config
.path
.symlink_metadata()
- .map_err(|e|
- ContextualError::IOError(
- "Failed to retrieve symlink's metadata".to_string(),
- e,
- )
- )?
+ .map_err(|e| ContextualError::IOError("Failed to retrieve symlink's metadata".to_string(), e))?
.file_type()
.is_symlink()
{
@@ -117,10 +112,7 @@ fn run() -> Result<(), ContextualError> {
.collect::<Vec<String>>();
let canon_path = miniserve_config.path.canonicalize().map_err(|e| {
- ContextualError::IOError(
- "Failed to resolve path to be served".to_string(),
- e,
- )
+ ContextualError::IOError("Failed to resolve path to be served".to_string(), e)
})?;
let path_string = canon_path.to_string_lossy();
@@ -135,20 +127,14 @@ fn run() -> Result<(), ContextualError> {
" Invoke with -h|--help to see options or invoke as `miniserve .` to hide this advice."
);
print!("Starting server in ");
- io::stdout().flush().map_err(|e| {
- ContextualError::IOError(
- "Failed to write data".to_string(),
- e,
- )
- })?;
+ io::stdout()
+ .flush()
+ .map_err(|e| ContextualError::IOError("Failed to write data".to_string(), e))?;
for c in "3… 2… 1… \n".chars() {
print!("{}", c);
- io::stdout().flush().map_err(|e| {
- ContextualError::IOError(
- "Failed to write data".to_string(),
- e,
- )
- })?;
+ io::stdout()
+ .flush()
+ .map_err(|e| ContextualError::IOError("Failed to write data".to_string(), e))?;
thread::sleep(Duration::from_millis(500));
}
}
@@ -210,12 +196,7 @@ fn run() -> Result<(), ContextualError> {
.configure(configure_app)
})
.bind(socket_addresses.as_slice())
- .map_err(|e| {
- ContextualError::IOError(
- "Failed to bind server".to_string(),
- e,
- )
- })?
+ .map_err(|e| ContextualError::IOError("Failed to bind server".to_string(), e))?
.shutdown_timeout(0)
.start();
@@ -239,7 +220,7 @@ fn configure_app(app: App<MiniserveConfig>) -> App<MiniserveConfig> {
let path = &app.state().path;
let no_symlinks = app.state().no_symlinks;
let random_route = app.state().random_route.clone();
- let default_color_scheme = app.state().default_color_scheme.clone();
+ let default_color_scheme = app.state().default_color_scheme;
let file_upload = app.state().file_upload;
upload_route = if let Some(random_route) = app.state().random_route.clone() {
format!("/{}/upload", random_route)
@@ -261,10 +242,11 @@ fn configure_app(app: App<MiniserveConfig>) -> App<MiniserveConfig> {
no_symlinks,
file_upload,
random_route.clone(),
- default_color_scheme.clone(),
+ default_color_scheme,
u_r.clone(),
)
- }),
+ })
+ .default_handler(error_404),
)
}
};
@@ -274,18 +256,52 @@ fn configure_app(app: App<MiniserveConfig>) -> App<MiniserveConfig> {
if let Some(s) = s {
if app.state().file_upload {
+ let default_color_scheme = app.state().default_color_scheme;
// Allow file upload
- app.resource(&upload_route, |r| {
- r.method(Method::POST).f(file_upload::upload_file)
+ app.resource(&upload_route, move |r| {
+ r.method(Method::POST)
+ .f(move |file| file_upload::upload_file(file, default_color_scheme))
})
// Handle directories
.handler(&full_route, s)
+ .default_resource(|r| r.method(Method::GET).f(error_404))
} else {
// Handle directories
app.handler(&full_route, s)
+ .default_resource(|r| r.method(Method::GET).f(error_404))
}
} else {
// Handle single files
app.resource(&full_route, |r| r.f(listing::file_handler))
+ .default_resource(|r| r.method(Method::GET).f(error_404))
}
}
+
+fn error_404(req: &HttpRequest<crate::MiniserveConfig>) -> Result<HttpResponse, io::Error> {
+ let err_404 = ContextualError::RouteNotFoundError(req.path().to_string());
+ let default_color_scheme = req.state().default_color_scheme;
+ let return_address = match &req.state().random_route {
+ Some(random_route) => format!("/{}", random_route),
+ None => "/".to_string(),
+ };
+
+ let query_params = listing::extract_query_parameters(req);
+ let color_scheme = query_params.theme.unwrap_or(default_color_scheme);
+
+ errors::log_error_chain(err_404.to_string());
+
+ Ok(actix_web::HttpResponse::NotFound().body(
+ renderer::render_error(
+ &err_404.to_string(),
+ StatusCode::NOT_FOUND,
+ &return_address,
+ query_params.sort,
+ query_params.order,
+ color_scheme,
+ default_color_scheme,
+ false,
+ true,
+ )
+ .into_string(),
+ ))
+}
diff --git a/src/renderer.rs b/src/renderer.rs
index 69224cf..d1e16ea 100644
--- a/src/renderer.rs
+++ b/src/renderer.rs
@@ -1,3 +1,4 @@
+use actix_web::http::StatusCode;
use chrono::{DateTime, Duration, Utc};
use chrono_humanize::{Accuracy, HumanTime, Tense};
use maud::{html, Markup, PreEscaped, DOCTYPE};
@@ -23,8 +24,17 @@ pub fn page(
upload_route: &str,
current_dir: &str,
) -> Markup {
+ let upload_action = build_upload_action(
+ upload_route,
+ current_dir,
+ sort_method,
+ sort_order,
+ color_scheme,
+ default_color_scheme,
+ );
+
html! {
- (page_header(serve_path, &color_scheme, file_upload))
+ (page_header(serve_path, color_scheme, file_upload, false))
body#drop-container {
@if file_upload {
div.drag-form {
@@ -33,19 +43,19 @@ pub fn page(
}
}
}
- (color_scheme_selector(&sort_method, &sort_order, &color_scheme, &default_color_scheme, serve_path))
+ (color_scheme_selector(sort_method, sort_order, color_scheme, default_color_scheme, serve_path))
div.container {
span#top { }
h1.title { "Index of " (serve_path) }
div.toolbar {
div.download {
@for compression_method in CompressionMethod::iter() {
- (archive_button(compression_method))
+ (archive_button(compression_method, sort_method, sort_order, color_scheme, default_color_scheme))
}
}
@if file_upload {
div.upload {
- form id="file_submit" action={(upload_route) "?path=" (current_dir)} method="POST" enctype="multipart/form-data" {
+ form id="file_submit" action=(upload_action) method="POST" enctype="multipart/form-data" {
p { "Select a file to upload or drag it anywhere into the window" }
div {
input#file-input type="file" name="file_to_upload" required="" {}
@@ -57,9 +67,9 @@ pub fn page(
}
table {
thead {
- th { (build_link("name", "Name", &sort_method, &sort_order, &color_scheme, &default_color_scheme)) }
- th { (build_link("size", "Size", &sort_method, &sort_order, &color_scheme, &default_color_scheme)) }
- th { (build_link("date", "Last modification", &sort_method, &sort_order, &color_scheme, &default_color_scheme)) }
+ th { (build_link("name", "Name", sort_method, sort_order, color_scheme, default_color_scheme)) }
+ th { (build_link("size", "Size", sort_method, sort_order, color_scheme, default_color_scheme)) }
+ th { (build_link("date", "Last modification", sort_method, sort_order, color_scheme, default_color_scheme)) }
}
tbody {
@if !is_root {
@@ -67,7 +77,7 @@ pub fn page(
tr {
td colspan="3" {
span.root-chevron { (chevron_left()) }
- a.root href=(parametrized_link(&parent, &sort_method, &sort_order, &color_scheme, &default_color_scheme)) {
+ a.root href=(parametrized_link(&parent, sort_method, sort_order, color_scheme, default_color_scheme)) {
"Parent directory"
}
}
@@ -75,7 +85,7 @@ pub fn page(
}
}
@for entry in entries {
- (entry_row(entry, &sort_method, &sort_order, &color_scheme, &default_color_scheme))
+ (entry_row(entry, sort_method, sort_order, color_scheme, default_color_scheme))
}
}
}
@@ -87,12 +97,35 @@ pub fn page(
}
}
+/// Build the action of the upload form
+fn build_upload_action(
+ upload_route: &str,
+ current_dir: &str,
+ sort_method: Option<SortingMethod>,
+ sort_order: Option<SortingOrder>,
+ color_scheme: ColorScheme,
+ default_color_scheme: ColorScheme,
+) -> String {
+ let mut upload_action = format!("{}?path={}", upload_route, current_dir);
+ if let Some(sorting_method) = sort_method {
+ upload_action = format!("{}&sort={}", upload_action, &sorting_method);
+ }
+ if let Some(sorting_order) = sort_order {
+ upload_action = format!("{}&order={}", upload_action, &sorting_order);
+ }
+ if color_scheme != default_color_scheme {
+ upload_action = format!("{}&theme={}", upload_action, color_scheme.to_slug());
+ }
+
+ upload_action
+}
+
/// Partial: color scheme selector
fn color_scheme_selector(
- sort_method: &Option<SortingMethod>,
- sort_order: &Option<SortingOrder>,
- active_color_scheme: &ColorScheme,
- default_color_scheme: &ColorScheme,
+ sort_method: Option<SortingMethod>,
+ sort_order: Option<SortingOrder>,
+ active_color_scheme: ColorScheme,
+ default_color_scheme: ColorScheme,
serve_path: &str,
) -> Markup {
html! {
@@ -104,13 +137,13 @@ fn color_scheme_selector(
}
ul {
@for color_scheme in ColorScheme::iter() {
- @if active_color_scheme == &color_scheme {
+ @if active_color_scheme == color_scheme {
li.active {
- (color_scheme_link(&sort_method, &sort_order, &color_scheme, &default_color_scheme, serve_path))
+ (color_scheme_link(sort_method, sort_order, color_scheme, default_color_scheme, serve_path))
}
} @else {
li {
- (color_scheme_link(&sort_method, &sort_order, &color_scheme, &default_color_scheme, serve_path))
+ (color_scheme_link(sort_method, sort_order, color_scheme, default_color_scheme, serve_path))
}
}
}
@@ -123,18 +156,18 @@ fn color_scheme_selector(
/// Partial: color scheme link
fn color_scheme_link(
- sort_method: &Option<SortingMethod>,
- sort_order: &Option<SortingOrder>,
- color_scheme: &ColorScheme,
- default_color_scheme: &ColorScheme,
+ sort_method: Option<SortingMethod>,
+ sort_order: Option<SortingOrder>,
+ color_scheme: ColorScheme,
+ default_color_scheme: ColorScheme,
serve_path: &str,
) -> Markup {
let link = parametrized_link(
serve_path,
- &sort_method,
- &sort_order,
- &color_scheme,
- &default_color_scheme,
+ sort_method,
+ sort_order,
+ color_scheme,
+ default_color_scheme,
);
let title = format!("Switch to {} theme", color_scheme);
@@ -152,8 +185,30 @@ fn color_scheme_link(
}
/// Partial: archive button
-fn archive_button(compress_method: CompressionMethod) -> Markup {
- let link = format!("?download={}", compress_method);
+fn archive_button(
+ compress_method: CompressionMethod,
+ sort_method: Option<SortingMethod>,
+ sort_order: Option<SortingOrder>,
+ color_scheme: ColorScheme,
+ default_color_scheme: ColorScheme,
+) -> Markup {
+ let link =
+ if sort_method.is_none() && sort_order.is_none() && color_scheme == default_color_scheme {
+ format!("?download={}", compress_method)
+ } else {
+ format!(
+ "{}&download={}",
+ parametrized_link(
+ "",
+ sort_method,
+ sort_order,
+ color_scheme,
+ default_color_scheme
+ ),
+ compress_method
+ )
+ };
+
let text = format!("Download .{}", compress_method.extension());
html! {
@@ -166,10 +221,10 @@ fn archive_button(compress_method: CompressionMethod) -> Markup {
/// If they are set, adds query parameters to links to keep them across pages
fn parametrized_link(
link: &str,
- sort_method: &Option<SortingMethod>,
- sort_order: &Option<SortingOrder>,
- color_scheme: &ColorScheme,
- default_color_scheme: &ColorScheme,
+ sort_method: Option<SortingMethod>,
+ sort_order: Option<SortingOrder>,
+ color_scheme: ColorScheme,
+ default_color_scheme: ColorScheme,
) -> String {
if let Some(method) = sort_method {
if let Some(order) = sort_order {
@@ -194,10 +249,10 @@ fn parametrized_link(
fn build_link(
name: &str,
title: &str,
- sort_method: &Option<SortingMethod>,
- sort_order: &Option<SortingOrder>,
- color_scheme: &ColorScheme,
- default_color_scheme: &ColorScheme,
+ sort_method: Option<SortingMethod>,
+ sort_order: Option<SortingOrder>,
+ color_scheme: ColorScheme,
+ default_color_scheme: ColorScheme,
) -> Markup {
let mut link = format!("?sort={}&order=asc", name);
let mut help = format!("Sort by {} in ascending order", name);
@@ -232,17 +287,17 @@ fn build_link(
/// Partial: row for an entry
fn entry_row(
entry: Entry,
- sort_method: &Option<SortingMethod>,
- sort_order: &Option<SortingOrder>,
- color_scheme: &ColorScheme,
- default_color_scheme: &ColorScheme,
+ sort_method: Option<SortingMethod>,
+ sort_order: Option<SortingOrder>,
+ color_scheme: ColorScheme,
+ default_color_scheme: ColorScheme,
) -> Markup {
html! {
tr {
td {
p {
@if entry.is_dir() {
- a.directory href=(parametrized_link(&entry.link, &sort_method, &sort_order, &color_scheme, &default_color_scheme)) {
+ a.directory href=(parametrized_link(&entry.link, sort_method, sort_order, color_scheme, default_color_scheme)) {
(entry.name) "/"
}
} @else if entry.is_file() {
@@ -257,7 +312,7 @@ fn entry_row(
}
}
} @else if entry.is_symlink() {
- a.symlink href=(parametrized_link(&entry.link, &sort_method, &sort_order, &color_scheme, &default_color_scheme)) {
+ a.symlink href=(parametrized_link(&entry.link, sort_method, sort_order, color_scheme, default_color_scheme)) {
(entry.name) span.symlink-symbol { "⇢" }
}
}
@@ -287,8 +342,8 @@ fn entry_row(
}
/// Partial: CSS
-fn css(color_scheme: &ColorScheme) -> Markup {
- let theme = color_scheme.clone().get_theme();
+fn css(color_scheme: ColorScheme) -> Markup {
+ let theme = color_scheme.get_theme();
let css = format!("
html {{
@@ -326,7 +381,7 @@ fn css(color_scheme: &ColorScheme) -> Markup {
font-weight: bold;
color: {directory_link_color};
}}
- a.file, a.file:visited {{
+ a.file, a.file:visited, .error-back, .error-back:visited {{
color: {file_link_color};
}}
a.symlink, a.symlink:visited {{
@@ -582,6 +637,25 @@ fn css(color_scheme: &ColorScheme) -> Markup {
width: 100%;
text-align: center;
}}
+ .error {{
+ margin: 2rem;
+ }}
+ .error p {{
+ margin: 1rem 0;
+ font-size: 0.9rem;
+ word-break: break-all;
+ }}
+ .error p:first-of-type {{
+ font-size: 1.25rem;
+ color: {error_color};
+ margin-bottom: 2rem;
+ }}
+ .error p:nth-of-type(2) {{
+ font-weight: bold;
+ }}
+ .error-nav {{
+ margin-top: 4rem;
+ }}
@media (max-width: 760px) {{
nav {{
padding: 0 2.5rem;
@@ -662,7 +736,8 @@ fn css(color_scheme: &ColorScheme) -> Markup {
drag_border_color = theme.drag_border_color,
drag_text_color = theme.drag_text_color,
size_background_color = theme.size_background_color,
- size_text_color = theme.size_text_color);
+ size_text_color = theme.size_text_color,
+ error_color = theme.error_color);
(PreEscaped(css))
}
@@ -687,15 +762,24 @@ fn chevron_down() -> Markup {
}
/// Partial: page header
-fn page_header(serve_path: &str, color_scheme: &ColorScheme, file_upload: bool) -> Markup {
+fn page_header(
+ serve_path: &str,
+ color_scheme: ColorScheme,
+ file_upload: bool,
+ is_error: bool,
+) -> Markup {
html! {
(DOCTYPE)
html {
meta charset="utf-8";
meta http-equiv="X-UA-Compatible" content="IE=edge";
meta name="viewport" content="width=device-width, initial-scale=1";
- title { "Index of " (serve_path) }
- style { (css(&color_scheme)) }
+ @if is_error {
+ title { (serve_path) }
+ } else {
+ title { "Index of " (serve_path) }
+ }
+ style { (css(color_scheme)) }
@if file_upload {
(PreEscaped(r#"
<script>
@@ -762,11 +846,46 @@ fn humanize_systemtime(src_time: Option<SystemTime>) -> Option<String> {
}
/// Renders an error on the webpage
-pub fn render_error(error_description: &str, return_address: &str) -> Markup {
+#[allow(clippy::too_many_arguments)]
+pub fn render_error(
+ error_description: &str,
+ error_code: StatusCode,
+ return_address: &str,
+ sort_method: Option<SortingMethod>,
+ sort_order: Option<SortingOrder>,
+ color_scheme: ColorScheme,
+ default_color_scheme: ColorScheme,
+ has_referer: bool,
+ display_back_link: bool,
+) -> Markup {
+ let link = if has_referer {
+ return_address.to_string()
+ } else {
+ parametrized_link(
+ return_address,
+ sort_method,
+ sort_order,
+ color_scheme,
+ default_color_scheme,
+ )
+ };
+
html! {
- pre { (error_description) }
- a href=(return_address) {
- "Go back to file listing"
+ body {
+ (page_header(&error_code.to_string(), color_scheme, false, true))
+ div.error {
+ p { (error_code.to_string()) }
+ @for error in error_description.lines() {
+ p { (error) }
+ }
+ @if display_back_link {
+ div.error-nav {
+ a.error-back href=(link) {
+ "Go back to file listing"
+ }
+ }
+ }
+ }
}
}
}
diff --git a/src/themes.rs b/src/themes.rs
index a7b619e..65e9ab2 100644
--- a/src/themes.rs
+++ b/src/themes.rs
@@ -3,7 +3,7 @@ use structopt::clap::arg_enum;
use strum_macros::EnumIter;
arg_enum! {
- #[derive(PartialEq, Deserialize, Clone, EnumIter)]
+ #[derive(PartialEq, Deserialize, Clone, EnumIter, Copy)]
#[serde(rename_all = "lowercase")]
pub enum ColorScheme {
Archlinux,
@@ -17,8 +17,8 @@ impl ColorScheme {
/// Returns the URL-compatible name of a color scheme
/// This must correspond to the name of the variant, in lowercase
/// See https://github.com/svenstaro/miniserve/pull/55 for explanations
- pub fn to_slug(&self) -> String {
- match &self {
+ pub fn to_slug(self) -> String {
+ match self {
ColorScheme::Archlinux => "archlinux",
ColorScheme::Zenburn => "zenburn",
ColorScheme::Monokai => "monokai",
@@ -28,8 +28,8 @@ impl ColorScheme {
}
/// Returns wether a color scheme is dark
- pub fn is_dark(&self) -> bool {
- match &self {
+ pub fn is_dark(self) -> bool {
+ match self {
ColorScheme::Archlinux => true,
ColorScheme::Zenburn => true,
ColorScheme::Monokai => true,
@@ -81,6 +81,7 @@ impl ColorScheme {
drag_text_color: "#fefefe".to_string(),
size_background_color: "#5294e2".to_string(),
size_text_color: "#fefefe".to_string(),
+ error_color: "#e44b4b".to_string(),
},
ColorScheme::Zenburn => Theme {
background: "#3f3f3f".to_string(),
@@ -123,6 +124,7 @@ impl ColorScheme {
drag_text_color: "#efefef".to_string(),
size_background_color: "#7f9f7f".to_string(),
size_text_color: "#efefef".to_string(),
+ error_color: "#d06565".to_string(),
},
ColorScheme::Monokai => Theme {
background: "#272822".to_string(),
@@ -165,6 +167,7 @@ impl ColorScheme {
drag_text_color: "#F8F8F2".to_string(),
size_background_color: "#75715E".to_string(),
size_text_color: "#F8F8F2".to_string(),
+ error_color: "#d02929".to_string(),
},
ColorScheme::Squirrel => Theme {
background: "#FFFFFF".to_string(),
@@ -207,6 +210,7 @@ impl ColorScheme {
drag_text_color: "#ffffff".to_string(),
size_background_color: "#323232".to_string(),
size_text_color: "#FFFFFF".to_string(),
+ error_color: "#d02424".to_string(),
},
}
}
@@ -254,4 +258,5 @@ pub struct Theme {
pub drag_text_color: String,
pub size_background_color: String,
pub size_text_color: String,
+ pub error_color: String,
}
diff --git a/tests/auth.rs b/tests/auth.rs
index f43553b..128047d 100644
--- a/tests/auth.rs
+++ b/tests/auth.rs
@@ -3,6 +3,7 @@ mod fixtures;
use assert_cmd::prelude::*;
use assert_fs::fixture::TempDir;
use fixtures::{port, tmpdir, Error, FILES};
+use reqwest::StatusCode;
use rstest::rstest_parametrize;
use select::document::Document;
use select::predicate::Text;
@@ -24,7 +25,7 @@ use std::time::Duration;
"testpassword"
),
)]
-fn auth_works(
+fn auth_accepts(
tmpdir: TempDir,
port: u16,
cli_auth_arg: &str,
@@ -43,11 +44,15 @@ fn auth_works(
sleep(Duration::from_secs(1));
let client = reqwest::Client::new();
- let body = client
+ let response = client
.get(format!("http://localhost:{}", port).as_str())
.basic_auth(client_username, Some(client_password))
- .send()?
- .error_for_status()?;
+ .send()?;
+
+ let status_code = response.status();
+ assert_eq!(status_code, StatusCode::OK);
+
+ let body = response.error_for_status()?;
let parsed = Document::from_read(body)?;
for &file in FILES {
assert!(parsed.find(Text).any(|x| x.text() == file));
@@ -57,3 +62,60 @@ fn auth_works(
Ok(())
}
+
+#[rstest_parametrize(
+ cli_auth_arg, client_username, client_password,
+ case("rightuser:rightpassword", "wronguser", "rightpassword"),
+ case(
+ "rightuser:sha256:314eee236177a721d0e58d3ca4ff01795cdcad1e8478ba8183a2e58d69c648c0",
+ "wronguser",
+ "rightpassword"
+ ),
+ case(
+ "rightuser:sha512:84ec4056571afeec9f5b59453305877e9a66c3f9a1d91733fde759b370c1d540b9dc58bfc88c5980ad2d020c3a8ee84f21314a180856f5a82ba29ecba29e2cab",
+ "wronguser",
+ "rightpassword"
+ ),
+ case("rightuser:rightpassword", "rightuser", "wrongpassword"),
+ case(
+ "rightuser:sha256:314eee236177a721d0e58d3ca4ff01795cdcad1e8478ba8183a2e58d69c648c0",
+ "rightuser",
+ "wrongpassword"
+ ),
+ case(
+ "rightuser:sha512:84ec4056571afeec9f5b59453305877e9a66c3f9a1d91733fde759b370c1d540b9dc58bfc88c5980ad2d020c3a8ee84f21314a180856f5a82ba29ecba29e2cab",
+ "rightuser",
+ "wrongpassword"
+ ),
+)]
+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())
+ .spawn()?;
+
+ sleep(Duration::from_secs(1));
+
+ let client = reqwest::Client::new();
+ let status = client
+ .get(format!("http://localhost:{}", port).as_str())
+ .basic_auth(client_username, Some(client_password))
+ .send()?
+ .status();
+
+ assert_eq!(status, StatusCode::UNAUTHORIZED);
+
+ child.kill()?;
+
+ Ok(())
+}