From 9e270c77e8558f057ce0b36a18aeed6a9401ab85 Mon Sep 17 00:00:00 2001 From: Jacob Hoffman-Andrews Date: Sat, 5 Dec 2020 14:05:15 -0800 Subject: [PATCH 1/4] Remove error_on_non_2xx. After the recent changes in #257, it's probably not necessary. It's now quite easy to use a match statement to extract responses for certain status codes, or all status codes. --- src/request.rs | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/src/request.rs b/src/request.rs index 0394ad9..132458c 100644 --- a/src/request.rs +++ b/src/request.rs @@ -121,7 +121,7 @@ impl Request { let response = unit::connect(unit, true, 0, reader, false).map_err(|e| e.url(url.clone()))?; - if self.error_on_non_2xx && response.status() >= 400 { + if response.status() >= 400 { Err(Error::Status(response.status(), response)) } else { Ok(response) @@ -337,26 +337,6 @@ impl Request { .push((param.to_string(), value.to_string())); self } - - /// By default, if a response's status is anything but a 2xx or 3xx, - /// call()/send() and related methods will return an Error. If you want - /// to handle such responses as non-errors, set this to `false`. - /// - /// Example: - /// ``` - /// # fn main() -> Result<(), ureq::Error> { - /// # ureq::is_test(true); - /// let response = ureq::get("http://httpbin.org/status/500") - /// .error_on_non_2xx(false) - /// .call()?; - /// assert_eq!(response.status(), 500); - /// # Ok(()) - /// # } - /// ``` - pub fn error_on_non_2xx(mut self, value: bool) -> Self { - self.error_on_non_2xx = value; - self - } } #[test] From ac93fa7e1823a4b0966c9a2ecc50d8366af4bc0e Mon Sep 17 00:00:00 2001 From: Jacob Hoffman-Andrews Date: Sat, 5 Dec 2020 20:32:30 -0800 Subject: [PATCH 2/4] Remove references to error_on_non_2xx --- src/agent.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/agent.rs b/src/agent.rs index 60f6a13..691cb93 100644 --- a/src/agent.rs +++ b/src/agent.rs @@ -418,12 +418,10 @@ impl AgentBuilder { /// .redirects(1) /// .build() /// .get("http://httpbin.org/status/301") - /// .error_on_non_2xx(false) /// .call()?; /// assert_ne!(result.status(), 301); /// /// let result = ureq::post("http://httpbin.org/status/307") - /// .error_on_non_2xx(false) /// .send_bytes(b"some data")?; /// assert_eq!(result.status(), 307); /// # Ok(()) From b9e3d3e76c695ef0e94db68ede0463ba2b156dd4 Mon Sep 17 00:00:00 2001 From: Jacob Hoffman-Andrews Date: Sun, 6 Dec 2020 14:55:55 -0800 Subject: [PATCH 3/4] Fix test --- src/agent.rs | 2 ++ src/testserver.rs | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/agent.rs b/src/agent.rs index 691cb93..5c018cc 100644 --- a/src/agent.rs +++ b/src/agent.rs @@ -417,6 +417,8 @@ impl AgentBuilder { /// let result = ureq::builder() /// .redirects(1) /// .build() + /// # ; + /// # let result = ureq::agent() /// .get("http://httpbin.org/status/301") /// .call()?; /// assert_ne!(result.status(), 301); diff --git a/src/testserver.rs b/src/testserver.rs index 8d7ea63..3cdef51 100644 --- a/src/testserver.rs +++ b/src/testserver.rs @@ -17,6 +17,8 @@ pub(crate) fn test_agent() -> Agent { let headers = read_request(&stream); if headers.0.is_empty() { // no headers probably means it's the initial request to check test server is up. + } else if headers.path() == "/status/200" { + stream.write_all(b"HTTP/1.1 200 OK\r\n\r\n")?; } else if headers.path() == "/status/500" { stream.write_all(b"HTTP/1.1 500 Server Internal Error\r\n\r\n")?; } else if headers.path() == "/bytes/100" { @@ -30,11 +32,11 @@ pub(crate) fn test_agent() -> Agent { stream.write_all(br#"{"hello": "world"}"#)?; } else if headers.path() == "/status/301" { stream.write_all(b"HTTP/1.1 301 Found\r\n")?; - stream.write_all(b"Location: /redirect/3\r\n")?; + stream.write_all(b"Location: /status/200\r\n")?; stream.write_all(b"\r\n")?; } else if headers.path() == "/status/307" { stream.write_all(b"HTTP/1.1 307 Found\r\n")?; - stream.write_all(b"Location: /redirect/3\r\n")?; + stream.write_all(b"Location: /status/200\r\n")?; stream.write_all(b"\r\n")?; } else { stream.write_all(b"HTTP/1.1 200 OK\r\n")?; From e25a6876f9bc9ecedb21025340d83ed1b6ee301d Mon Sep 17 00:00:00 2001 From: Jacob Hoffman-Andrews Date: Fri, 18 Dec 2020 22:04:00 -0800 Subject: [PATCH 4/4] Document error handling. --- README.md | 7 +++++++ README.tpl | 1 + src/error.rs | 17 +++++++++++++++++ src/lib.rs | 6 ++++++ 4 files changed, 31 insertions(+) diff --git a/README.md b/README.md index 45982ac..27176b1 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,12 @@ Ureq supports sending and receiving json, if you enable the "json" feature: .into_string()?; ``` +### Error handling + +ureq returns errors via `Result`. That includes I/O errors, +protocol errors, and status code errors (when the server responded 4xx or +5xx). More details on the [Error] type. + ### Features To enable a minimal dependency tree, some features are off by default. @@ -189,6 +195,7 @@ If ureq is not what you're looking for, check out these other Rust HTTP clients: [post()]: https://docs.rs/ureq/latest/ureq/fn.post.html [put()]: https://docs.rs/ureq/latest/ureq/fn.put.html [Request]: https://docs.rs/ureq/latest/ureq/struct.Request.html +[Error]: https://docs.rs/ureq/latest/ureq/enum.Error.html [Request::call()]: https://docs.rs/ureq/latest/ureq/struct.Request.html#method.call [Request::send()]: https://docs.rs/ureq/latest/ureq/struct.Request.html#method.send [Request::send_bytes()]: https://docs.rs/ureq/latest/ureq/struct.Request.html#method.send_bytes diff --git a/README.tpl b/README.tpl index 92a944d..a5da6df 100644 --- a/README.tpl +++ b/README.tpl @@ -12,6 +12,7 @@ [post()]: https://docs.rs/ureq/latest/ureq/fn.post.html [put()]: https://docs.rs/ureq/latest/ureq/fn.put.html [Request]: https://docs.rs/ureq/latest/ureq/struct.Request.html +[Error]: https://docs.rs/ureq/latest/ureq/enum.Error.html [Request::call()]: https://docs.rs/ureq/latest/ureq/struct.Request.html#method.call [Request::send()]: https://docs.rs/ureq/latest/ureq/struct.Request.html#method.send [Request::send_bytes()]: https://docs.rs/ureq/latest/ureq/struct.Request.html#method.send_bytes diff --git a/src/error.rs b/src/error.rs index ad1121d..ffb15f8 100644 --- a/src/error.rs +++ b/src/error.rs @@ -42,6 +42,23 @@ use crate::Response; /// ureq::get(url).call() /// } /// ``` +/// +/// If you'd like to treat all status code errors as normal, successful responses, +/// you can use [Result::or_else](std::result::Result::or_else) like this: +/// +/// ``` +/// use ureq::Error::Status; +/// # fn main() -> std::result::Result<(), ureq::Error> { +/// # ureq::is_test(true); +/// let resp = ureq::get("http://example.com/") +/// .call() +/// .or_else(|e| match e { +/// Status(_, r) => Ok(r), // turn status errors into Ok Responses. +/// _ => Err(e), +/// })?; +/// # Ok(()) +/// # } +/// ``` #[derive(Debug)] pub enum Error { /// A response was successfully received but had status code >= 400. diff --git a/src/lib.rs b/src/lib.rs index 8fc44ab..7a43af7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -82,6 +82,12 @@ //! # fn main() {} //! ``` //! +//! ## Error handling +//! +//! ureq returns errors via `Result`. That includes I/O errors, +//! protocol errors, and status code errors (when the server responded 4xx or +//! 5xx). More details on the [Error] type. +//! //! ## Features //! //! To enable a minimal dependency tree, some features are off by default.