Skip to main content

leyline/core/error/
from.rs

1use std::io;
2
3use super::{Error, Kind};
4use crate::h2::H2Error;
5#[cfg(feature = "http3")]
6use crate::quic::H3SendError;
7use crate::tls::TlsError;
8
9impl Error {
10    pub(crate) fn from_url_parse(e: url::ParseError) -> Self {
11        Error::new(Kind::Url).with_source(e)
12    }
13
14    pub(crate) fn from_json(e: serde_json::Error) -> Self {
15        Error::new(Kind::Json).with_source(e)
16    }
17
18    pub(crate) fn from_request_body(e: io::Error) -> Self {
19        Error::new(Kind::Body)
20            .with_message("request body stream failed")
21            .with_source(e)
22    }
23}
24
25impl From<url::ParseError> for Error {
26    fn from(e: url::ParseError) -> Self {
27        Error::from_url_parse(e)
28    }
29}
30
31impl From<io::Error> for Error {
32    fn from(e: io::Error) -> Self {
33        if !e.get_ref().is_some_and(|inner| inner.is::<Error>()) {
34            return Error::new(Kind::Io).with_source(e);
35        }
36        match e.into_inner().map(|inner| inner.downcast::<Error>()) {
37            Some(Ok(err)) => *err,
38            Some(Err(other)) => Error::new(Kind::Io).with_source(io::Error::other(other)),
39            None => Error::new(Kind::Io),
40        }
41    }
42}
43
44impl From<TlsError> for Error {
45    fn from(e: TlsError) -> Self {
46        let kind = match &e {
47            TlsError::Dns(_) | TlsError::TcpConnect(_) => Kind::Connect,
48            TlsError::Proxy { .. } | TlsError::ProxyTargetUnreachable { .. } => Kind::Proxy,
49            TlsError::SslConfig(_) | TlsError::Profile(_) | TlsError::TrustStore(_) => Kind::Config,
50            _ => Kind::Tls,
51        };
52        Error::new(kind).with_source(e)
53    }
54}
55
56impl From<H2Error> for Error {
57    fn from(e: H2Error) -> Self {
58        if let Some(limit) = e.body_limit() {
59            return limit.error();
60        }
61        match e {
62            H2Error::RequestBody(io) => Error::from_request_body(io),
63            other => Error::new(Kind::Http2).with_source(other),
64        }
65    }
66}
67
68#[cfg(feature = "http3")]
69impl From<H3SendError> for Error {
70    fn from(e: H3SendError) -> Self {
71        match e {
72            H3SendError::BodyLimit(limit) => limit.error(),
73            H3SendError::RequestBody(io) => Error::from_request_body(io),
74            H3SendError::NotSent(message) | H3SendError::Rejected(message) => {
75                Error::new(Kind::Http3)
76                    .with_message(message)
77                    .with_source(super::marker::NotProcessed)
78            }
79            other => Error::new(Kind::Http3).with_message(other.message().into_owned()),
80        }
81    }
82}
83
84impl From<http::Error> for Error {
85    fn from(e: http::Error) -> Self {
86        Error::new(Kind::Request).with_source(e)
87    }
88}
89
90impl From<http::header::InvalidHeaderName> for Error {
91    fn from(e: http::header::InvalidHeaderName) -> Self {
92        Error::new(Kind::Request).with_source(e)
93    }
94}
95
96impl From<http::header::InvalidHeaderValue> for Error {
97    fn from(e: http::header::InvalidHeaderValue) -> Self {
98        Error::new(Kind::Request).with_source(e)
99    }
100}
101
102impl From<http::uri::InvalidUri> for Error {
103    fn from(e: http::uri::InvalidUri) -> Self {
104        Error::new(Kind::Url).with_source(e)
105    }
106}