diff options
-rw-r--r-- | Cargo.lock | 62 | ||||
-rw-r--r-- | Cargo.toml | 4 | ||||
-rw-r--r-- | src/args.rs | 12 | ||||
-rw-r--r-- | src/file_upload.rs | 11 | ||||
-rw-r--r-- | src/listing.rs | 2 | ||||
-rw-r--r-- | src/main.rs | 33 | ||||
-rw-r--r-- | src/renderer.rs | 117 | ||||
-rw-r--r-- | tests/serve_request.rs | 28 | ||||
-rw-r--r-- | tests/upload_files.rs | 46 |
9 files changed, 212 insertions, 103 deletions
@@ -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" @@ -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(()) +} |