diff --git a/Cargo.lock b/Cargo.lock index 2a820e6..cbea75c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -36,18 +36,17 @@ version = "0.7.0" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "comrak 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "derive_more 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "futures-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "handlebars 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "handlebars 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "http 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.13.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "mime 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", - "structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-fs 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -195,19 +194,6 @@ dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "derive_more" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "digest" version = "0.8.1" @@ -223,7 +209,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "env_logger" -version = "0.6.2" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", @@ -348,20 +334,27 @@ dependencies = [ [[package]] name = "handlebars" -version = "1.1.0" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hashbrown 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "pest 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "pest_derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "quick-error 1.2.2 (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.102 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "hashbrown" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "heck" version = "0.3.1" @@ -681,11 +674,13 @@ version = "0.1.0-alpha.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "proc-macro2" -version = "0.4.30" +name = "proc-macro-error" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "unicode-xid 0.1.0 (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.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -701,14 +696,6 @@ name = "quick-error" version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "quote" -version = "0.6.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "quote" version = "1.0.2" @@ -781,6 +768,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "serde" version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "serde_derive" @@ -846,32 +836,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "structopt" -version = "0.2.18" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "structopt-derive 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt-derive 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "structopt-derive" -version = "0.2.18" +version = "0.3.4" 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-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "syn" -version = "0.15.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-error 0.2.6 (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.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -900,6 +881,24 @@ dependencies = [ "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "thiserror" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "thiserror-impl 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.5" +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)", + "syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "thread_local" version = "0.3.6" @@ -1140,11 +1139,6 @@ name = "unicode-width" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "unicode-xid" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "unicode-xid" version = "0.2.0" @@ -1255,10 +1249,9 @@ dependencies = [ "checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b" "checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" "checksum crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce446db02cdc3165b94ae73111e570793400d0794e46125cc4056c81cbb039f4" -"checksum derive_more 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a141330240c921ec6d074a3e188a7c7ef95668bb95e7d44fa0e5778ec2a7afe" "checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" "checksum entities 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b5320ae4c3782150d900b79807611a59a99fc9a1d61d686faafc24b93fc8d7ca" -"checksum env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3" +"checksum env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" @@ -1272,7 +1265,8 @@ dependencies = [ "checksum futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)" = "5ce968633c17e5f97936bd2797b6e38fb56cf16a7422319f7ec2e30d3c470e8d" "checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" "checksum h2 0.2.0-alpha.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0f107db1419ef8271686187b1a5d47c6431af4a7f4d98b495e7b7fc249bb0a78" -"checksum handlebars 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d82e5750d8027a97b9640e3fefa66bbaf852a35228e1c90790efd13c4b09c166" +"checksum handlebars 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "91ef1ac30f2eaaa2b835fce73c57091cb6b9fc62b7eef285efbf980b0f20001b" +"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 hermit-abi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "307c3c9f937f38e3534b1d6447ecf090cafcc9744e4a6360e8b037b2cf5af120" "checksum http 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)" = "d7e06e336150b178206af098a055e3621e8336027e2b4d126bda0bc64824baaf" @@ -1309,10 +1303,9 @@ dependencies = [ "checksum pin-project 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c5fce7042b4e4338a3f868e563fff394709c3ff62cf6908d407dd9e2caff96ed" "checksum pin-project-internal 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "7644b4721cc27235f667e735da8732f5b781c442157315674c0cb7f28b4cabf3" "checksum pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5894c618ce612a3fa23881b152b608bafb8c56cfc22f434a3ba3120b40f7b587" -"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" +"checksum proc-macro-error 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "aeccfe4d5d8ea175d5f0e4a2ad0637e0f4121d63bd99d356fb1f39ab2e7c6097" "checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27" "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" -"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" "checksum regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd" @@ -1332,12 +1325,13 @@ dependencies = [ "checksum spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" "checksum string 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d24114bfcceb867ca7f71a0d3fe45d45619ec47a6fbfa98cb14e14250bfa5d6d" "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" -"checksum structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "16c2cdbf9cc375f15d1b4141bc48aeef444806655cd0e904207edc8d68d86ed7" -"checksum structopt-derive 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "53010261a84b37689f9ed7d395165029f9cc7abb9f56bbfe86bee2597ed25107" -"checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" +"checksum structopt 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c167b61c7d4c126927f5346a4327ce20abf8a186b8041bbeb1ce49e5db49587b" +"checksum structopt-derive 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "519621841414165d2ad0d4c92be8f41844203f2b67e245f9345a5a12d40c69d7" "checksum syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "661641ea2aa15845cddeb97dad000d22070bb5c1fb456b96c1cba883ec691e92" "checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e" "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +"checksum thiserror 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f9fb62ff737e573b1e677459bea6fd023cd5d6e868c3242d3cdf3ef2f0554824" +"checksum thiserror-impl 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "24069c0ba08aab54289d6a25f5036d94afc61e1538bbc42ae5501df141c9027d" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" "checksum tokio 0.2.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1f17f5d6ab0f35c1506678b28fb1798bdf74fcb737e9843c7b17b73e426eba38" @@ -1362,7 +1356,6 @@ dependencies = [ "checksum unchecked-index 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eeba86d422ce181a719445e51872fa30f1f7413b62becb52e95ec91aa262d85c" "checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0" "checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20" -"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" "checksum unicode_categories 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" "checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" diff --git a/Cargo.toml b/Cargo.toml index d428df0..1f7b64d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,17 +12,16 @@ edition = "2018" [dependencies] clap = "2.33.0" comrak = "0.6.2" -derive_more = "0.15.0" -env_logger = "0.6.2" +env_logger = "0.7.1" futures-preview = "0.3.0-alpha.19" -handlebars = "1.1.0" +handlebars = "2.0.2" http = "0.1.19" hyper = "0.13.0-alpha.4" log = "0.4.8" mime = "0.3.14" percent-encoding = "2.1.0" -serde = "1.0.102" -serde_derive = "1.0.102" +serde = {version = "1.0.102", features = ["derive"]} +thiserror = "1.0.5" tokio = "0.2.0-alpha.6" tokio-fs = "0.2.0-alpha.6" -structopt = "0.2.18" +structopt = "0.3.4" diff --git a/src/ext.rs b/src/ext.rs index 694dbf4..3ad3080 100644 --- a/src/ext.rs +++ b/src/ext.rs @@ -8,12 +8,13 @@ use comrak::ComrakOptions; use futures::{future, StreamExt}; use http::{Request, Response, StatusCode}; use hyper::{header, Body}; +use log::{trace, warn}; use percent_encoding::{utf8_percent_encode, AsciiSet, CONTROLS}; -use std::error::Error as StdError; use std::ffi::OsStr; use std::fmt::Write; use std::io; use std::path::{Path, PathBuf}; +use thiserror::Error; use tokio_fs::DirEntry; /// The entry point to extensions. Extensions are given both the request and the @@ -46,7 +47,7 @@ pub async fn serve( // If the requested file was not found, then try doing a directory listing. if let Err(e) = resp { match e { - super::Error::Io(e) => { + super::Error::Io { source: e } => { if e.kind() == io::ErrorKind::NotFound { let list_dir_resp = maybe_list_dir(&config.root_dir, &path).await?; trace!("using directory list extension"); @@ -68,7 +69,6 @@ pub async fn serve( /// Load a markdown file, render to HTML, and return the response. async fn md_path_to_html(path: &Path) -> Result> { - // Render Markdown like GitHub let mut options = ComrakOptions::default(); options.ext_autolink = true; @@ -131,14 +131,14 @@ async fn list_dir(root_dir: &Path, path: &Path) -> Result> { fn make_dir_list_body(root_dir: &Path, paths: &[PathBuf]) -> Result { let mut buf = String::new(); - writeln!(buf, "
").map_err(Error::WriteInDirList)?; + writeln!(buf, "
").map_err(|source| Error::WriteInDirList { source })?; let dot_dot = OsStr::new(".."); for path in paths { let full_url = path .strip_prefix(root_dir) - .map_err(Error::StripPrefixInDirList)?; + .map_err(|source| Error::StripPrefixInDirList { source })?; let maybe_dot_dot = || { if path.ends_with("..") { Some(dot_dot) @@ -159,7 +159,7 @@ fn make_dir_list_body(root_dir: &Path, paths: &[PathBuf]) -> Result { // TODO: Make this a relative URL writeln!(buf, "", full_url, file_name) - .map_err(Error::WriteInDirList)?; + .map_err(|source| Error::WriteInDirList { source })?; } else { warn!("non-unicode url: {}", full_url.to_string_lossy()); } @@ -171,7 +171,7 @@ fn make_dir_list_body(root_dir: &Path, paths: &[PathBuf]) -> Result { } } - writeln!(buf, "
").map_err(Error::WriteInDirList)?; + writeln!(buf, "
").map_err(|source| Error::WriteInDirList { source })?; let cfg = HtmlCfg { title: String::new(), @@ -183,60 +183,39 @@ fn make_dir_list_body(root_dir: &Path, paths: &[PathBuf]) -> Result { pub type Result = std::result::Result; -#[derive(Debug, Display)] +#[derive(Debug, Error)] pub enum Error { // blanket "pass-through" error types + #[error("engine error")] + Engine { source: Box }, - #[display(fmt = "engine error")] - Engine(Box), - - #[display(fmt = "HTTP error")] - Http(http::Error), + #[error("HTTP error")] + Http { + #[from] + source: http::Error, + }, - #[display(fmt = "I/O error")] - Io(io::Error), + #[error("I/O error")] + Io { + #[from] + source: io::Error, + }, // custom "semantic" error types - - #[display(fmt = "markdown is not UTF-8")] + #[error("markdown is not UTF-8")] MarkdownUtf8, - #[display(fmt = "failed to strip prefix in directory listing")] - StripPrefixInDirList(std::path::StripPrefixError), + #[error("failed to strip prefix in directory listing")] + StripPrefixInDirList { source: std::path::StripPrefixError }, - #[display(fmt = "formatting error while creating directory listing")] - WriteInDirList(std::fmt::Error), -} - -impl StdError for Error { - fn source(&self) -> Option<&(dyn StdError + 'static)> { - use Error::*; - - match self { - Engine(e) => Some(e), - Io(e) => Some(e), - Http(e) => Some(e), - MarkdownUtf8 => None, - StripPrefixInDirList(e) => Some(e), - WriteInDirList(e) => Some(e), - } - } + #[error("formatting error while creating directory listing")] + WriteInDirList { source: std::fmt::Error }, } impl From for Error { fn from(e: super::Error) -> Error { - Error::Engine(Box::new(e)) - } -} - -impl From for Error { - fn from(e: http::Error) -> Error { - Error::Http(e) - } -} - -impl From for Error { - fn from(e: io::Error) -> Error { - Error::Io(e) + Error::Engine { + source: Box::new(e), + } } } diff --git a/src/main.rs b/src/main.rs index 737d813..6e87a4c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,26 +1,21 @@ //! A simple HTTP server, for learning and local doc development. -#[macro_use] -extern crate derive_more; -#[macro_use] -extern crate log; -#[macro_use] -extern crate serde_derive; - use env_logger::{Builder, Env}; -use futures::FutureExt; use futures::future; +use futures::FutureExt; use handlebars::Handlebars; use http::status::StatusCode; use http::Uri; use hyper::service::{make_service_fn, service_fn}; use hyper::{header, Body, Request, Response, Server}; +use log::{debug, error, info, trace, warn}; use percent_encoding::percent_decode_str; -use std::error::Error as StdError; +use serde::Serialize; use std::io; use std::net::SocketAddr; use std::path::{Path, PathBuf}; use structopt::StructOpt; +use thiserror::Error; use tokio::runtime::Runtime; // Developer extensions. These are contained in their own module so that the @@ -36,7 +31,7 @@ fn main() { /// Basic error reporting, including the "cause chain". This is used both by the /// top-level error reporting and to report internal server errors. -fn log_error_chain(mut e: &dyn StdError) { +fn log_error_chain(mut e: &dyn std::error::Error) { error!("error: {}", e); while let Some(source) = e.source() { error!("caused by: {}", source); @@ -48,7 +43,6 @@ fn log_error_chain(mut e: &dyn StdError) { #[derive(Clone, StructOpt)] #[structopt(about = "A basic HTTP file server")] pub struct Config { - /// The IP:PORT combination. #[structopt( name = "ADDR", @@ -69,13 +63,12 @@ pub struct Config { } fn run() -> Result<()> { - // Initialize logging, and log the "info" level for this crate only, unless // the environment contains `RUST_LOG`. let env = Env::new().default_filter_or("basic_http_server=info"); Builder::from_env(env) - .default_format_module_path(false) - .default_format_timestamp(false) + .format_module_path(false) + .format_timestamp(None) .init(); // Create the configuration from the command line arguments. It @@ -123,7 +116,6 @@ fn run() -> Result<()> { /// Errors are turned into an Error response (404 or 500), and never propagated /// upward for hyper to deal with. async fn serve(config: Config, req: Request) -> Response { - // Serve the requested file. let resp = serve_file(&req, &config.root_dir).await; @@ -156,7 +148,6 @@ async fn transform_error(resp: Result>) -> Response { /// Serve static files from a root directory. async fn serve_file(req: &Request, root_dir: &PathBuf) -> Result> { - // First, try to do a redirect. If that doesn't happen, then find the path // to the static file we want to serve - which may be `index.html` for // directories - and send a response containing that file. @@ -189,7 +180,6 @@ async fn serve_file(req: &Request, root_dir: &PathBuf) -> Result, root_dir: &PathBuf) -> Result>> { - if req.uri().path().ends_with("/") { return Ok(None); } @@ -214,7 +204,6 @@ fn try_dir_redirect(req: &Request, root_dir: &PathBuf) -> Result Option { /// Convert an error to an HTTP error response future, with correct response code. async fn make_error_response(e: Error) -> Result> { let resp = match e { - Error::Io(e) => make_io_error_response(e).await?, - Error::Ext(ext::Error::Io(e)) => make_io_error_response(e).await?, + Error::Io { source: e } => make_io_error_response(e).await?, + Error::Ext { + source: ext::Error::Io { source: e }, + } => make_io_error_response(e).await?, e => make_internal_server_error_response(e).await?, }; Ok(resp) @@ -334,7 +325,7 @@ async fn make_io_error_response(error: io::Error) -> Result> { debug!("{}", error); make_error_response_from_code(StatusCode::NOT_FOUND).await? } - _ => make_internal_server_error_response(Error::Io(error)).await?, + _ => make_internal_server_error_response(error.into()).await?, }; Ok(resp) } @@ -372,7 +363,7 @@ fn render_html(cfg: HtmlCfg) -> Result { let reg = Handlebars::new(); let rendered = reg .render_template(HTML_TEMPLATE, &cfg) - .map_err(Error::TemplateRender)?; + .map_err(|source| Error::TemplateRender { source })?; Ok(rendered) } @@ -403,72 +394,44 @@ pub type Result = std::result::Result; /// The criteria of when to use which type of error variant, and their pros and /// cons, aren't obvious. /// -/// These errors use `derive(Display)` from the `derive-more` crate to reduce +/// These errors use `derive(Error)` from the `thiserror` crate to reduce /// boilerplate. -#[derive(Debug, Display)] +#[derive(Debug, Error)] pub enum Error { // blanket "pass-through" error types - - #[display(fmt = "Extension error")] - Ext(ext::Error), - - #[display(fmt = "HTTP error")] - Http(http::Error), - - #[display(fmt = "Hyper error")] - Hyper(hyper::Error), - - #[display(fmt = "I/O error")] - Io(io::Error), + #[error("Extension error")] + Ext { + #[from] + source: ext::Error, + }, + + #[error("HTTP error")] + Http { + #[from] + source: http::Error, + }, + + #[error("Hyper error")] + Hyper { + #[from] + source: hyper::Error, + }, + + #[error("I/O error")] + Io { + #[from] + source: io::Error, + }, // custom "semantic" error types + #[error("failed to parse IP address")] + AddrParse { source: std::net::AddrParseError }, - #[display(fmt = "failed to parse IP address")] - AddrParse(std::net::AddrParseError), - - #[display(fmt = "failed to render template")] - TemplateRender(handlebars::TemplateRenderError), + #[error("failed to render template")] + TemplateRender { + source: handlebars::TemplateRenderError, + }, - #[display(fmt = "failed to convert URL to local file path")] + #[error("failed to convert URL to local file path")] UrlToPath, } - -impl StdError for Error { - fn source(&self) -> Option<&(dyn StdError + 'static)> { - use Error::*; - - match self { - Ext(e) => Some(e), - Io(e) => Some(e), - Http(e) => Some(e), - Hyper(e) => Some(e), - AddrParse(e) => Some(e), - TemplateRender(e) => Some(e), - UrlToPath => None, - } - } -} - -impl From for Error { - fn from(e: ext::Error) -> Error { - Error::Ext(e) - } -} - -impl From for Error { - fn from(e: http::Error) -> Error { - Error::Http(e) - } -} - -impl From for Error { - fn from(e: hyper::Error) -> Error { - Error::Hyper(e) - } -} - -impl From for Error { - fn from(e: io::Error) -> Error { - Error::Io(e) - } -}