summaryrefslogtreecommitdiffstats
path: root/vendor/reqwest/src/error.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:59:35 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:59:35 +0000
commitd1b2d29528b7794b41e66fc2136e395a02f8529b (patch)
treea4a17504b260206dec3cf55b2dca82929a348ac2 /vendor/reqwest/src/error.rs
parentReleasing progress-linux version 1.72.1+dfsg1-1~progress7.99u1. (diff)
downloadrustc-d1b2d29528b7794b41e66fc2136e395a02f8529b.tar.xz
rustc-d1b2d29528b7794b41e66fc2136e395a02f8529b.zip
Merging upstream version 1.73.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/reqwest/src/error.rs')
-rw-r--r--vendor/reqwest/src/error.rs383
1 files changed, 383 insertions, 0 deletions
diff --git a/vendor/reqwest/src/error.rs b/vendor/reqwest/src/error.rs
new file mode 100644
index 000000000..0e6bd247d
--- /dev/null
+++ b/vendor/reqwest/src/error.rs
@@ -0,0 +1,383 @@
+#![cfg_attr(target_arch = "wasm32", allow(unused))]
+use std::error::Error as StdError;
+use std::fmt;
+use std::io;
+
+use crate::{StatusCode, Url};
+
+/// A `Result` alias where the `Err` case is `reqwest::Error`.
+pub type Result<T> = std::result::Result<T, Error>;
+
+/// The Errors that may occur when processing a `Request`.
+///
+/// Note: Errors may include the full URL used to make the `Request`. If the URL
+/// contains sensitive information (e.g. an API key as a query parameter), be
+/// sure to remove it ([`without_url`](Error::without_url))
+pub struct Error {
+ inner: Box<Inner>,
+}
+
+pub(crate) type BoxError = Box<dyn StdError + Send + Sync>;
+
+struct Inner {
+ kind: Kind,
+ source: Option<BoxError>,
+ url: Option<Url>,
+}
+
+impl Error {
+ pub(crate) fn new<E>(kind: Kind, source: Option<E>) -> Error
+ where
+ E: Into<BoxError>,
+ {
+ Error {
+ inner: Box::new(Inner {
+ kind,
+ source: source.map(Into::into),
+ url: None,
+ }),
+ }
+ }
+
+ /// Returns a possible URL related to this error.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # async fn run() {
+ /// // displays last stop of a redirect loop
+ /// let response = reqwest::get("http://site.with.redirect.loop").await;
+ /// if let Err(e) = response {
+ /// if e.is_redirect() {
+ /// if let Some(final_stop) = e.url() {
+ /// println!("redirect loop at {}", final_stop);
+ /// }
+ /// }
+ /// }
+ /// # }
+ /// ```
+ pub fn url(&self) -> Option<&Url> {
+ self.inner.url.as_ref()
+ }
+
+ /// Returns a mutable reference to the URL related to this error
+ ///
+ /// This is useful if you need to remove sensitive information from the URL
+ /// (e.g. an API key in the query), but do not want to remove the URL
+ /// entirely.
+ pub fn url_mut(&mut self) -> Option<&mut Url> {
+ self.inner.url.as_mut()
+ }
+
+ /// Add a url related to this error (overwriting any existing)
+ pub fn with_url(mut self, url: Url) -> Self {
+ self.inner.url = Some(url);
+ self
+ }
+
+ /// Strip the related url from this error (if, for example, it contains
+ /// sensitive information)
+ pub fn without_url(mut self) -> Self {
+ self.inner.url = None;
+ self
+ }
+
+ /// Returns true if the error is from a type Builder.
+ pub fn is_builder(&self) -> bool {
+ matches!(self.inner.kind, Kind::Builder)
+ }
+
+ /// Returns true if the error is from a `RedirectPolicy`.
+ pub fn is_redirect(&self) -> bool {
+ matches!(self.inner.kind, Kind::Redirect)
+ }
+
+ /// Returns true if the error is from `Response::error_for_status`.
+ pub fn is_status(&self) -> bool {
+ matches!(self.inner.kind, Kind::Status(_))
+ }
+
+ /// Returns true if the error is related to a timeout.
+ pub fn is_timeout(&self) -> bool {
+ let mut source = self.source();
+
+ while let Some(err) = source {
+ if err.is::<TimedOut>() {
+ return true;
+ }
+ source = err.source();
+ }
+
+ false
+ }
+
+ /// Returns true if the error is related to the request
+ pub fn is_request(&self) -> bool {
+ matches!(self.inner.kind, Kind::Request)
+ }
+
+ #[cfg(not(target_arch = "wasm32"))]
+ /// Returns true if the error is related to connect
+ pub fn is_connect(&self) -> bool {
+ let mut source = self.source();
+
+ while let Some(err) = source {
+ if let Some(hyper_err) = err.downcast_ref::<hyper::Error>() {
+ if hyper_err.is_connect() {
+ return true;
+ }
+ }
+
+ source = err.source();
+ }
+
+ false
+ }
+
+ /// Returns true if the error is related to the request or response body
+ pub fn is_body(&self) -> bool {
+ matches!(self.inner.kind, Kind::Body)
+ }
+
+ /// Returns true if the error is related to decoding the response's body
+ pub fn is_decode(&self) -> bool {
+ matches!(self.inner.kind, Kind::Decode)
+ }
+
+ /// Returns the status code, if the error was generated from a response.
+ pub fn status(&self) -> Option<StatusCode> {
+ match self.inner.kind {
+ Kind::Status(code) => Some(code),
+ _ => None,
+ }
+ }
+
+ // private
+
+ #[allow(unused)]
+ pub(crate) fn into_io(self) -> io::Error {
+ io::Error::new(io::ErrorKind::Other, self)
+ }
+}
+
+impl fmt::Debug for Error {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let mut builder = f.debug_struct("reqwest::Error");
+
+ builder.field("kind", &self.inner.kind);
+
+ if let Some(ref url) = self.inner.url {
+ builder.field("url", url);
+ }
+ if let Some(ref source) = self.inner.source {
+ builder.field("source", source);
+ }
+
+ builder.finish()
+ }
+}
+
+impl fmt::Display for Error {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self.inner.kind {
+ Kind::Builder => f.write_str("builder error")?,
+ Kind::Request => f.write_str("error sending request")?,
+ Kind::Body => f.write_str("request or response body error")?,
+ Kind::Decode => f.write_str("error decoding response body")?,
+ Kind::Redirect => f.write_str("error following redirect")?,
+ Kind::Upgrade => f.write_str("error upgrading connection")?,
+ Kind::Status(ref code) => {
+ let prefix = if code.is_client_error() {
+ "HTTP status client error"
+ } else {
+ debug_assert!(code.is_server_error());
+ "HTTP status server error"
+ };
+ write!(f, "{} ({})", prefix, code)?;
+ }
+ };
+
+ if let Some(url) = &self.inner.url {
+ write!(f, " for url ({})", url.as_str())?;
+ }
+
+ if let Some(e) = &self.inner.source {
+ write!(f, ": {}", e)?;
+ }
+
+ Ok(())
+ }
+}
+
+impl StdError for Error {
+ fn source(&self) -> Option<&(dyn StdError + 'static)> {
+ self.inner.source.as_ref().map(|e| &**e as _)
+ }
+}
+
+#[cfg(target_arch = "wasm32")]
+impl From<crate::error::Error> for wasm_bindgen::JsValue {
+ fn from(err: Error) -> wasm_bindgen::JsValue {
+ js_sys::Error::from(err).into()
+ }
+}
+
+#[cfg(target_arch = "wasm32")]
+impl From<crate::error::Error> for js_sys::Error {
+ fn from(err: Error) -> js_sys::Error {
+ js_sys::Error::new(&format!("{}", err))
+ }
+}
+
+#[derive(Debug)]
+pub(crate) enum Kind {
+ Builder,
+ Request,
+ Redirect,
+ Status(StatusCode),
+ Body,
+ Decode,
+ Upgrade,
+}
+
+// constructors
+
+pub(crate) fn builder<E: Into<BoxError>>(e: E) -> Error {
+ Error::new(Kind::Builder, Some(e))
+}
+
+pub(crate) fn body<E: Into<BoxError>>(e: E) -> Error {
+ Error::new(Kind::Body, Some(e))
+}
+
+pub(crate) fn decode<E: Into<BoxError>>(e: E) -> Error {
+ Error::new(Kind::Decode, Some(e))
+}
+
+pub(crate) fn request<E: Into<BoxError>>(e: E) -> Error {
+ Error::new(Kind::Request, Some(e))
+}
+
+pub(crate) fn redirect<E: Into<BoxError>>(e: E, url: Url) -> Error {
+ Error::new(Kind::Redirect, Some(e)).with_url(url)
+}
+
+pub(crate) fn status_code(url: Url, status: StatusCode) -> Error {
+ Error::new(Kind::Status(status), None::<Error>).with_url(url)
+}
+
+pub(crate) fn url_bad_scheme(url: Url) -> Error {
+ Error::new(Kind::Builder, Some(BadScheme)).with_url(url)
+}
+
+if_wasm! {
+ pub(crate) fn wasm(js_val: wasm_bindgen::JsValue) -> BoxError {
+ format!("{:?}", js_val).into()
+ }
+}
+
+pub(crate) fn upgrade<E: Into<BoxError>>(e: E) -> Error {
+ Error::new(Kind::Upgrade, Some(e))
+}
+
+// io::Error helpers
+
+#[allow(unused)]
+pub(crate) fn into_io(e: Error) -> io::Error {
+ e.into_io()
+}
+
+#[allow(unused)]
+pub(crate) fn decode_io(e: io::Error) -> Error {
+ if e.get_ref().map(|r| r.is::<Error>()).unwrap_or(false) {
+ *e.into_inner()
+ .expect("io::Error::get_ref was Some(_)")
+ .downcast::<Error>()
+ .expect("StdError::is() was true")
+ } else {
+ decode(e)
+ }
+}
+
+// internal Error "sources"
+
+#[derive(Debug)]
+pub(crate) struct TimedOut;
+
+impl fmt::Display for TimedOut {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.write_str("operation timed out")
+ }
+}
+
+impl StdError for TimedOut {}
+
+#[derive(Debug)]
+pub(crate) struct BadScheme;
+
+impl fmt::Display for BadScheme {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.write_str("URL scheme is not allowed")
+ }
+}
+
+impl StdError for BadScheme {}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ fn assert_send<T: Send>() {}
+ fn assert_sync<T: Sync>() {}
+
+ #[test]
+ fn test_source_chain() {
+ let root = Error::new(Kind::Request, None::<Error>);
+ assert!(root.source().is_none());
+
+ let link = super::body(root);
+ assert!(link.source().is_some());
+ assert_send::<Error>();
+ assert_sync::<Error>();
+ }
+
+ #[test]
+ fn mem_size_of() {
+ use std::mem::size_of;
+ assert_eq!(size_of::<Error>(), size_of::<usize>());
+ }
+
+ #[test]
+ fn roundtrip_io_error() {
+ let orig = super::request("orig");
+ // Convert reqwest::Error into an io::Error...
+ let io = orig.into_io();
+ // Convert that io::Error back into a reqwest::Error...
+ let err = super::decode_io(io);
+ // It should have pulled out the original, not nested it...
+ match err.inner.kind {
+ Kind::Request => (),
+ _ => panic!("{:?}", err),
+ }
+ }
+
+ #[test]
+ fn from_unknown_io_error() {
+ let orig = io::Error::new(io::ErrorKind::Other, "orly");
+ let err = super::decode_io(orig);
+ match err.inner.kind {
+ Kind::Decode => (),
+ _ => panic!("{:?}", err),
+ }
+ }
+
+ #[test]
+ fn is_timeout() {
+ let err = super::request(super::TimedOut);
+ assert!(err.is_timeout());
+
+ let io = io::Error::new(io::ErrorKind::Other, err);
+ let nested = super::request(io);
+ assert!(nested.is_timeout());
+ }
+}