aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--Cargo.lock62
-rw-r--r--Cargo.toml4
-rw-r--r--src/args.rs12
-rw-r--r--src/file_upload.rs11
-rw-r--r--src/listing.rs2
-rw-r--r--src/main.rs33
-rw-r--r--src/renderer.rs117
-rw-r--r--tests/serve_request.rs28
-rw-r--r--tests/upload_files.rs46
9 files changed, 212 insertions, 103 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 6009f3b..5dccdcf 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -53,7 +53,7 @@ dependencies = [
"derive_more 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
"either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
- "http 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)",
+ "http 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-current-thread 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -82,7 +82,7 @@ dependencies = [
"futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
"h2 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
"hashbrown 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "http 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)",
+ "http 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"indexmap 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -134,7 +134,7 @@ version = "0.1.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)",
- "http 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)",
+ "http 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -258,7 +258,7 @@ dependencies = [
"futures 0.1.29 (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.26 (registry+https://github.com/rust-lang/crates.io-index)",
- "http 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)",
+ "http 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -359,7 +359,7 @@ dependencies = [
[[package]]
name = "alphanumeric-sort"
-version = "1.0.11"
+version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -1078,7 +1078,7 @@ dependencies = [
"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.29 (registry+https://github.com/rust-lang/crates.io-index)",
- "http 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)",
+ "http 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"indexmap 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1101,7 +1101,7 @@ dependencies = [
[[package]]
name = "hex"
-version = "0.4.0"
+version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -1133,7 +1133,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "http"
-version = "0.1.19"
+version = "0.1.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1148,7 +1148,7 @@ 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.29 (registry+https://github.com/rust-lang/crates.io-index)",
- "http 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)",
+ "http 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-buf 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1166,7 +1166,7 @@ dependencies = [
"futures 0.1.29 (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.26 (registry+https://github.com/rust-lang/crates.io-index)",
- "http 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)",
+ "http 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"http-body 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1441,7 +1441,7 @@ version = "0.5.0"
dependencies = [
"actix 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)",
"actix-web 0.7.19 (registry+https://github.com/rust-lang/crates.io-index)",
- "alphanumeric-sort 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "alphanumeric-sort 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)",
"assert_cmd 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"assert_fs 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
"base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1451,7 +1451,7 @@ dependencies = [
"chrono-humanize 0.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
- "hex 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "hex 0.4.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.27 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1466,7 +1466,7 @@ dependencies = [
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
"sha2 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"simplelog 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "structopt 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "structopt 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"strum 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)",
"strum_macros 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)",
"tar 0.4.26 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1812,10 +1812,10 @@ dependencies = [
[[package]]
name = "proc-macro-error"
-version = "0.4.4"
+version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "proc-macro-error-attr 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro-error-attr 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rustversion 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1824,14 +1824,14 @@ dependencies = [
[[package]]
name = "proc-macro-error-attr"
-version = "0.4.3"
+version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rustversion 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn-mid 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn-mid 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -2100,7 +2100,7 @@ dependencies = [
"encoding_rs 0.8.20 (registry+https://github.com/rust-lang/crates.io-index)",
"flate2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
- "http 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)",
+ "http 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper 0.12.35 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper-tls 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2440,21 +2440,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "structopt"
-version = "0.3.8"
+version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "structopt-derive 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "structopt-derive 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "structopt-derive"
-version = "0.4.1"
+version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "proc-macro-error 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro-error 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2498,7 +2498,7 @@ dependencies = [
[[package]]
name = "syn-mid"
-version = "0.4.0"
+version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3195,7 +3195,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum actix_derive 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4300e9431455322ae393d43a2ba1ef96b8080573c0fc23b196219efedfb6ba69"
"checksum adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2"
"checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d"
-"checksum alphanumeric-sort 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "f37ce94154d73f6961f87571a3ab7814e1608f373bd55a933e3e771b6dd59fc4"
+"checksum alphanumeric-sort 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)" = "22b991f3d9c054bb99ed18f24e906b89ec3bc450e788d4911b2b9e123ab3109b"
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
"checksum arc-swap 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f1a1eca3195b729bbd64e292ef2f5fff6b1c28504fed762ce2b1013dde4d8e92"
"checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee"
@@ -3285,11 +3285,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum h2 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" = "a5b34c246847f938a410a03c5458c7fee2274436675e76d8b903c08efc29c462"
"checksum hashbrown 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e1de41fb8dba9714efd92241565cdff73f78508c95697dd56787d3cba27e2353"
"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
-"checksum hex 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "023b39be39e3a2da62a94feb433e91e8bcd37676fbc8bea371daf52b7a769a3e"
+"checksum hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35"
"checksum hostname 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "21ceb46a83a85e824ef93669c8b390009623863b5c195d1ba747292c0c72f94e"
"checksum html5ever 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5ce65ac8028cf5a287a7dbf6c4e0a6cf2dcf022ed5b167a81bae66ebf599a8b7"
"checksum htmlescape 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e9025058dae765dee5070ec375f591e2ba14638c63feff74f13805a72e523163"
-"checksum http 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)" = "d7e06e336150b178206af098a055e3621e8336027e2b4d126bda0bc64824baaf"
+"checksum http 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "d6ccf5ede3a895d8856620237b2f02972c1bbc78d2965ad7fe8838d4a0ed41f0"
"checksum http-body 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6741c859c1b2463a423a1dbce98d418e6c3c3fc720fb0d45528657320920292d"
"checksum httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9"
"checksum hyper 0.12.35 (registry+https://github.com/rust-lang/crates.io-index)" = "9dbe6ed1438e1f8ad955a4701e9a944938e9519f6888d12d8558b645e247d5f6"
@@ -3362,8 +3362,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum predicates-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "06075c3a3e92559ff8929e7a280684489ea27fe44805174c3ebd9328dcb37178"
"checksum predicates-tree 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8e63c4859013b38a76eca2414c64911fba30def9e3202ac461a2d22831220124"
"checksum pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f81e1644e1b54f5a68959a29aa86cde704219254669da328ecfdf6a1f09d427"
-"checksum proc-macro-error 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "53c98547ceaea14eeb26fcadf51dc70d01a2479a7839170eae133721105e4428"
-"checksum proc-macro-error-attr 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c2bf5d493cf5d3e296beccfd61794e445e830dfc8070a9c248ad3ee071392c6c"
+"checksum proc-macro-error 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "875077759af22fa20b610ad4471d8155b321c89c3f2785526c9839b099be4e0a"
+"checksum proc-macro-error-attr 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "c5717d9fa2664351a01ed73ba5ef6df09c01a521cb42cb65a061432a826f3c7a"
"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
"checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27"
"checksum publicsuffix 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9bf259a81de2b2eb9850ec990ec78e6a25319715584fd7652b9b26f96fcb1510"
@@ -3432,13 +3432,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum string_cache_codegen 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0f45ed1b65bf9a4bf2f7b7dc59212d1926e9eaf00fa998988e420fd124467c6"
"checksum string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b1884d1bc09741d466d9b14e6d37ac89d6909cbcac41dd9ae982d4d063bbedfc"
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
-"checksum structopt 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "df136b42d76b1fbea72e2ab3057343977b04b4a2e00836c3c7c0673829572713"
-"checksum structopt-derive 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd50a87d2f7b8958055f3e73a963d78feaccca3836767a9069844e34b5b03c0a"
+"checksum structopt 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "a1bcbed7d48956fcbb5d80c6b95aedb553513de0a1b451ea92679d999c010e98"
+"checksum structopt-derive 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "095064aa1f5b94d14e635d0a5684cf140c43ae40a0fd990708d38f5d669e5f64"
"checksum strum 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)" = "530efb820d53b712f4e347916c5e7ed20deb76a4f0457943b3182fb889b06d2c"
"checksum strum_macros 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5e6e163a520367c465f59e0a61a23cfae3b10b6546d78b6f672a382be79f7110"
"checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5"
"checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf"
-"checksum syn-mid 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9fd3937748a7eccff61ba5b90af1a20dbf610858923a9192ea0ecb0cb77db1d0"
+"checksum syn-mid 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7be3539f6c128a931cf19dcee741c1af532c7fd387baa739c03dd2e96479338a"
"checksum synstructure 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f085a5855930c0441ca1288cf044ea4aecf4f43a91668abdb870b4ba546a203"
"checksum take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60"
"checksum tar 0.4.26 (registry+https://github.com/rust-lang/crates.io-index)" = "b3196bfbffbba3e57481b6ea32249fbaf590396a52505a2615adbb79d9d826d3"
diff --git a/Cargo.toml b/Cargo.toml
index 93ed712..55ccc76 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -30,7 +30,7 @@ percent-encoding = "2.1"
htmlescape = "0.3.1"
bytesize = "1.0.0"
nanoid = "0.2.0"
-alphanumeric-sort = "1.0.11"
+alphanumeric-sort = "1.0.12"
structopt = "0.3"
chrono = "0.4.10"
chrono-humanize = "0.0.11"
@@ -45,7 +45,7 @@ log = "0.4.8"
strum = "0.17.1"
strum_macros = "0.17.1"
sha2 = "0.8.1"
-hex = "0.4.0"
+hex = "0.4.2"
[dev-dependencies]
assert_cmd = "0.12"
diff --git a/src/args.rs b/src/args.rs
index 8fde78a..fe976ed 100644
--- a/src/args.rs
+++ b/src/args.rs
@@ -27,6 +27,13 @@ struct CLIArgs {
#[structopt(name = "PATH", parse(from_os_str))]
path: Option<PathBuf>,
+ /// 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.
+ #[structopt(long, parse(from_os_str), name="index_file")]
+ index: Option<PathBuf>,
+
/// Port to use
#[structopt(short = "p", long = "port", default_value = "8080")]
port: u16,
@@ -108,8 +115,8 @@ fn parse_auth(src: &str) -> Result<auth::RequiredAuth, ContextualError> {
};
match second_part {
- "sha256" => auth::RequiredAuthPassword::Sha256(hash_bin.to_owned()),
- "sha512" => auth::RequiredAuthPassword::Sha512(hash_bin.to_owned()),
+ "sha256" => auth::RequiredAuthPassword::Sha256(hash_bin),
+ "sha512" => auth::RequiredAuthPassword::Sha512(hash_bin),
_ => return Err(ContextualError::InvalidHashMethod(second_part.to_owned())),
}
} else {
@@ -162,6 +169,7 @@ pub fn parse_args() -> crate::MiniserveConfig {
no_symlinks: args.no_symlinks,
random_route,
default_color_scheme,
+ index: args.index,
overwrite_files: args.overwrite_files,
file_upload: args.file_upload,
}
diff --git a/src/file_upload.rs b/src/file_upload.rs
index 3ef3a7e..af4fcf2 100644
--- a/src/file_upload.rs
+++ b/src/file_upload.rs
@@ -120,6 +120,7 @@ fn handle_multipart(
pub fn upload_file(
req: &HttpRequest<crate::MiniserveConfig>,
default_color_scheme: ColorScheme,
+ uses_random_route: bool
) -> FutureResponse<HttpResponse> {
let return_path = if let Some(header) = req.headers().get(header::REFERER) {
header.to_str().unwrap_or("/").to_owned()
@@ -146,6 +147,7 @@ pub fn upload_file(
query_params.order,
color_scheme,
default_color_scheme,
+ uses_random_route
));
}
};
@@ -165,6 +167,7 @@ pub fn upload_file(
query_params.order,
color_scheme,
default_color_scheme,
+ uses_random_route
));
}
};
@@ -184,6 +187,7 @@ pub fn upload_file(
query_params.order,
color_scheme,
default_color_scheme,
+ uses_random_route
));
}
};
@@ -197,7 +201,7 @@ pub fn upload_file(
.then(move |e| match e {
Ok(_) => future::ok(
HttpResponse::SeeOther()
- .header(header::LOCATION, return_path.to_string())
+ .header(header::LOCATION, return_path)
.finish(),
),
Err(e) => create_error_response(
@@ -208,12 +212,14 @@ pub fn upload_file(
query_params.order,
color_scheme,
default_color_scheme,
+ uses_random_route
),
}),
)
}
/// Convenience method for creating response errors, if file upload fails.
+#[allow(clippy::too_many_arguments)]
fn create_error_response(
description: &str,
error_code: StatusCode,
@@ -222,6 +228,7 @@ fn create_error_response(
sorting_order: Option<SortingOrder>,
color_scheme: ColorScheme,
default_color_scheme: ColorScheme,
+ uses_random_route: bool
) -> FutureResult<HttpResponse, actix_web::error::Error> {
errors::log_error_chain(description.to_string());
future::ok(
@@ -237,7 +244,7 @@ fn create_error_response(
color_scheme,
default_color_scheme,
true,
- true,
+ !uses_random_route,
)
.into_string(),
),
diff --git a/src/listing.rs b/src/listing.rs
index 42eb59a..d419775 100644
--- a/src/listing.rs
+++ b/src/listing.rs
@@ -152,7 +152,7 @@ pub fn directory_listing<S>(
let base = Path::new(serve_path);
let random_route = format!("/{}", random_route.unwrap_or_default());
- let is_root = base.parent().is_none() || req.path() == random_route;
+ let is_root = base.parent().is_none() || Path::new(&req.path()) == Path::new(&random_route);
let current_dir = match base.strip_prefix(random_route) {
Ok(c_d) => Path::new("/").join(c_d),
Err(_) => base.to_path_buf(),
diff --git a/src/main.rs b/src/main.rs
index eb90eaf..9b9c628 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -51,6 +51,12 @@ pub struct MiniserveConfig {
/// Default color scheme
pub default_color_scheme: themes::ColorScheme,
+ /// 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 file upload
pub file_upload: bool,
@@ -129,6 +135,14 @@ fn run() -> Result<(), ContextualError> {
let canon_path = miniserve_config.path.canonicalize().map_err(|e| {
ContextualError::IOError("Failed to resolve path to be served".to_string(), e)
})?;
+
+ if let Some(index_path) = &miniserve_config.index {
+ let has_index: std::path::PathBuf = [&canon_path, index_path].iter().collect();
+ if !has_index.exists() {
+
+ println!("{warning} The provided index file could not be found.", warning=Color::RGB(255, 192, 0).paint("Notice:").bold());
+ }
+ }
let path_string = canon_path.to_string_lossy();
println!(
@@ -244,6 +258,12 @@ fn configure_app(app: App<MiniserveConfig>) -> App<MiniserveConfig> {
};
if path.is_file() {
None
+ } else if let Some(index_file) = &app.state().index {
+ Some(
+ fs::StaticFiles::new(path)
+ .expect("Failed to setup static file handler")
+ .index_file(index_file.to_string_lossy())
+ )
} else {
let u_r = upload_route.clone();
Some(
@@ -267,6 +287,7 @@ fn configure_app(app: App<MiniserveConfig>) -> App<MiniserveConfig> {
};
let random_route = app.state().random_route.clone().unwrap_or_default();
+ let uses_random_route = app.state().random_route.clone().is_some();
let full_route = format!("/{}", random_route);
if let Some(s) = s {
@@ -275,7 +296,7 @@ fn configure_app(app: App<MiniserveConfig>) -> App<MiniserveConfig> {
// Allow file upload
app.resource(&upload_route, move |r| {
r.method(Method::POST)
- .f(move |file| file_upload::upload_file(file, default_color_scheme))
+ .f(move |file| file_upload::upload_file(file, default_color_scheme, uses_random_route))
})
// Handle directories
.handler(&full_route, s)
@@ -295,11 +316,7 @@ fn configure_app(app: App<MiniserveConfig>) -> App<MiniserveConfig> {
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 uses_random_route = req.state().random_route.is_some();
let query_params = listing::extract_query_parameters(req);
let color_scheme = query_params.theme.unwrap_or(default_color_scheme);
@@ -309,13 +326,13 @@ fn error_404(req: &HttpRequest<crate::MiniserveConfig>) -> Result<HttpResponse,
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,
+ !uses_random_route,
)
.into_string(),
))
diff --git a/src/renderer.rs b/src/renderer.rs
index cbad557..1821c48 100644
--- a/src/renderer.rs
+++ b/src/renderer.rs
@@ -33,61 +33,64 @@ pub fn page(
);
html! {
- (page_header(serve_path, color_scheme, file_upload, false))
- body#drop-container {
- @if file_upload {
- div.drag-form {
- div.drag-title {
- h1 { "Drop your file here to upload it" }
+ (DOCTYPE)
+ html {
+ (page_header(serve_path, color_scheme, file_upload, false))
+ body#drop-container {
+ @if file_upload {
+ div.drag-form {
+ div.drag-title {
+ h1 { "Drop your file here to upload it" }
+ }
}
}
- }
- (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, sort_method, sort_order, color_scheme, default_color_scheme))
+ (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, sort_method, sort_order, color_scheme, default_color_scheme))
+ }
}
- }
- @if file_upload {
- div.upload {
- 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="" {}
- button type="submit" { "Upload file" }
+ @if file_upload {
+ div.upload {
+ 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="" {}
+ button type="submit" { "Upload file" }
+ }
}
}
}
}
- }
- 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)) }
- }
- tbody {
- @if !is_root {
- tr {
- td colspan="3" {
- span.root-chevron { (chevron_left()) }
- a.root href=(parametrized_link("../", sort_method, sort_order, color_scheme, default_color_scheme)) {
- "Parent directory"
+ 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)) }
+ }
+ tbody {
+ @if !is_root {
+ tr {
+ td colspan="3" {
+ span.root-chevron { (chevron_left()) }
+ a.root href=(parametrized_link("../", sort_method, sort_order, color_scheme, default_color_scheme)) {
+ "Parent directory"
+ }
}
}
}
- }
- @for entry in entries {
- (entry_row(entry, sort_method, sort_order, color_scheme, default_color_scheme))
+ @for entry in entries {
+ (entry_row(entry, sort_method, sort_order, color_scheme, default_color_scheme))
+ }
}
}
- }
- a.back href="#top" {
- (arrow_up())
+ a.back href="#top" {
+ (arrow_up())
+ }
}
}
}
@@ -803,14 +806,13 @@ fn page_header(
is_error: bool,
) -> Markup {
html! {
- (DOCTYPE)
- html {
+ head {
meta charset="utf-8";
meta http-equiv="X-UA-Compatible" content="IE=edge";
meta name="viewport" content="width=device-width, initial-scale=1";
@if is_error {
title { (serve_path) }
- } else {
+ } @else {
title { "Index of " (serve_path) }
}
style { (css(color_scheme)) }
@@ -905,17 +907,20 @@ pub fn render_error(
};
html! {
- body {
+ (DOCTYPE)
+ html {
(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"
+ body {
+ 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/tests/serve_request.rs b/tests/serve_request.rs
index 7419ab1..064e196 100644
--- a/tests/serve_request.rs
+++ b/tests/serve_request.rs
@@ -55,7 +55,10 @@ fn serves_requests_with_non_default_port(tmpdir: TempDir, port: u16) -> Result<(
.error_for_status()?;
let dir_body_parsed = Document::from_read(dir_body)?;
for &file in FILES {
- assert!(dir_body_parsed.find(|x: &Node| x.text() == file).next().is_some());
+ assert!(dir_body_parsed
+ .find(|x: &Node| x.text() == file)
+ .next()
+ .is_some());
}
}
@@ -63,3 +66,26 @@ fn serves_requests_with_non_default_port(tmpdir: TempDir, port: u16) -> Result<(
Ok(())
}
+
+#[rstest]
+fn serves_requests_custom_index_notice(tmpdir: TempDir, port: u16) -> Result<(), Error> {
+ let mut child = Command::cargo_bin("miniserve")?
+ .arg("--index=not.html")
+ .arg("-p")
+ .arg(port.to_string())
+ .arg(tmpdir.path())
+ .stdout(Stdio::piped())
+ .spawn()?;
+
+ sleep(Duration::from_secs(1));
+
+ child.kill()?;
+ let output = child.wait_with_output().expect("Failed to read stdout");
+ let all_text = String::from_utf8(output.stdout);
+
+ assert!(all_text
+ .unwrap()
+ .contains("The provided index file could not be found"));
+
+ Ok(())
+}
diff --git a/tests/upload_files.rs b/tests/upload_files.rs
index 6a24aee..53833a6 100644
--- a/tests/upload_files.rs
+++ b/tests/upload_files.rs
@@ -59,3 +59,49 @@ fn uploading_files_works(tmpdir: TempDir, port: u16) -> Result<(), Error> {
Ok(())
}
+
+#[rstest]
+fn uploading_files_is_prevented(tmpdir: TempDir, port: u16) -> 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::get(format!("http://localhost:{}", port).as_str())?.error_for_status()?;
+ let parsed = Document::from_read(body)?;
+ assert!(parsed.find(Text).all(|x| x.text() != test_file_name));
+
+ // Ensure the file upload form is not present
+ assert!(parsed.find(Attr("id", "file_submit")).next().is_none());
+
+ // Then try to upload anyway
+ let form = multipart::Form::new();
+ let part = multipart::Part::text("this should not be uploaded")
+ .file_name(test_file_name)
+ .mime_str("text/plain")?;
+ let form = form.part("file_to_upload", part);
+
+ let client = reqwest::Client::new();
+ // Ensure uploading fails and returns an error
+ assert!(client
+ .post(format!("http://localhost:{}{}", port, "/upload?path=/").as_str())
+ .multipart(form)
+ .send()?
+ .error_for_status().is_err());
+
+ // After uploading, check whether the uploaded file is now getting listed.
+ let body = reqwest::get(format!("http://localhost:{}", port).as_str())?;
+ let parsed = Document::from_read(body)?;
+ assert!(!parsed.find(Text).any(|x| x.text() == test_file_name));
+
+ child.kill()?;
+
+ Ok(())
+}