diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d8b0c8..067fecb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,9 @@ * `CheckError` now has an `HttpForbidden` variant. [PR#138] * The `check_http` field of `CheckContext` is now an enum instead of a boolean [PR#138] +* ureq has been upgraded to 2.0. This affects the public `CheckError` API, but should otherwise have no user-facing impact. [PR#134] +[PR#134]: https://github.com/deadlinks/cargo-deadlinks/pull/134 [PR#138]: https://github.com/deadlinks/cargo-deadlinks/pull/138 diff --git a/Cargo.lock b/Cargo.lock index ecd69cd..565949f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -680,15 +680,6 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f1383dff4092fe903ac180e391a8d4121cc48f08ccf850614b0290c6673b69d" -[[package]] -name = "qstring" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d464fae65fff2680baf48019211ce37aaec0c78e9264c84a3e484717f965104e" -dependencies = [ - "percent-encoding", -] - [[package]] name = "quote" version = "1.0.7" @@ -1194,15 +1185,14 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] name = "ureq" -version = "1.5.4" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "294b85ef5dbc3670a72e82a89971608a1fcc4ed5c7c5a2895230d31a95f0569b" +checksum = "96014ded8c85822677daee4f909d18acccca744810fd4f8ffc492c284f2324bc" dependencies = [ "base64", "chunked_transfer", "log", "once_cell", - "qstring", "rustls", "url", "webpki", diff --git a/Cargo.toml b/Cargo.toml index 92e259f..1ea9608 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,7 +33,7 @@ num_cpus = "1.8" once_cell = "1.5.1" rayon = "1.0" regex = { version = "1", default-features = false, features = ["std", "perf"] } -ureq = { version = "1.5.4", features = ["tls"], default-features = false } +ureq = { version = "2.0.1", features = ["tls"], default-features = false } serde = "1.0" serde_derive = "1.0" url = "2" diff --git a/src/check.rs b/src/check.rs index fe9c024..b37869f 100644 --- a/src/check.rs +++ b/src/check.rs @@ -23,21 +23,21 @@ const PREFIX_BLACKLIST: [&str; 1] = ["https://doc.rust-lang.org"]; #[derive(Debug)] pub enum IoError { - HttpUnexpectedStatus(Url, ureq::Response), - HttpFetch(Url, ureq::Error), + HttpUnexpectedStatus(ureq::Response), + HttpFetch(ureq::Transport), FileIo(String, std::io::Error), } impl fmt::Display for IoError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - IoError::HttpUnexpectedStatus(url, resp) => write!( + IoError::HttpUnexpectedStatus(resp) => write!( f, "Unexpected HTTP status fetching {}: {}", - url, + resp.get_url(), resp.status_text() ), - IoError::HttpFetch(url, e) => write!(f, "Error fetching {}: {}", url, e), + IoError::HttpFetch(e) => write!(f, "Error fetching {}", e), IoError::FileIo(url, e) => write!(f, "Error fetching {}: {}", url, e), } } @@ -89,6 +89,16 @@ pub enum CheckError { Io(Box), } +impl From for CheckError { + fn from(err: ureq::Error) -> Self { + let io_err = match err { + ureq::Error::Status(_, response) => IoError::HttpUnexpectedStatus(response), + ureq::Error::Transport(err) => IoError::HttpFetch(err), + }; + CheckError::Io(Box::new(io_err)) + } +} + impl fmt::Display for CheckError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { @@ -277,23 +287,7 @@ fn check_file_fragment( is_fragment_available(&Link::File(path.to_path_buf()), fragment, fetch_html) } -fn handle_response(url: &Url, resp: ureq::Response) -> Result { - if resp.synthetic() { - Err(CheckError::Io(Box::new(IoError::HttpFetch( - url.clone(), - resp.into_synthetic_error().unwrap(), - )))) - } else if resp.ok() { - Ok(resp) - } else { - Err(CheckError::Io(Box::new(IoError::HttpUnexpectedStatus( - url.clone(), - resp, - )))) - } -} - -/// Check a URL with "http" or "https" scheme for availability. Returns `false` if it is unavailable. +/// Check a URL with "http" or "https" scheme for availability. Returns `Err` if it is unavailable. fn check_http_url(url: &Url, ctx: &CheckContext) -> Result<(), CheckError> { if ctx.check_http == HttpCheck::Ignored { warn!( @@ -320,13 +314,15 @@ fn check_http_url(url: &Url, ctx: &CheckContext) -> Result<(), CheckError> { // The URL might contain a fragment. In that case we need a full GET // request to check if the fragment exists. if url.fragment().is_none() || !ctx.check_fragments { - let mut resp = ureq::head(url.as_str()).call(); - // If HEAD isn't allowed, try sending a GET instead - if resp.status() == 405 { - resp = ureq::get(url.as_str()).call(); + match ureq::head(url.as_str()).call() { + Err(ureq::Error::Status(405, _)) => { + // If HEAD isn't allowed, try sending a GET instead + ureq::get(url.as_str()).call()?; + Ok(()) + } + Err(other) => Err(other.into()), + Ok(_) => Ok(()), } - - handle_response(url, resp).map(|_: ureq::Response| ()) } else { // the URL might contain a fragment, in that case we need to check if // the fragment exists, this issues a GET request @@ -338,8 +334,8 @@ fn check_http_fragment(url: &Url, fragment: &str) -> Result<(), CheckError> { debug!("Checking fragment {} of URL {}.", fragment, url.as_str()); fn get_html(url: &Url) -> Result { - let resp = ureq::get(url.as_str()).call(); - handle_response(&url, resp).map(|resp| resp.into_string().unwrap()) + let resp = ureq::get(url.as_str()).call()?; + Ok(resp.into_string().unwrap()) } let fetch_html = || { @@ -359,7 +355,8 @@ fn check_http_fragment(url: &Url, fragment: &str) -> Result<(), CheckError> { } }; - is_fragment_available(&Link::Http(url.clone()), fragment, fetch_html) + is_fragment_available(&Link::Http(url.clone()), fragment, fetch_html)?; + Ok(()) } #[cfg(test)] diff --git a/tests/non_existent_http_link.rs b/tests/non_existent_http_link.rs index 4d39a18..ba13a36 100644 --- a/tests/non_existent_http_link.rs +++ b/tests/non_existent_http_link.rs @@ -1,6 +1,7 @@ extern crate assert_cmd; use assert_cmd::prelude::*; +use predicates::str::contains; use std::process::Command; mod non_existent_http_link { @@ -40,6 +41,9 @@ mod non_existent_http_link { .args(&["deadlinks", "--check-http"]) .current_dir("./tests/non_existent_http_link") .assert() - .failure(); + .failure() + .stdout(contains( + "Unexpected HTTP status fetching http://example.com/this/does/not/exist: Not Found", + )); } }