net-cat 0.3.0

Minimal hand-rolled HTTP/1.1 client over std::net::TcpStream. v0.3.0 adds chunked-transfer decoding (`Transfer-Encoding: chunked` responses now yield the correct decoded body) and a redirect follower in `fetch` (RFC 7231 §6.4: 301/302/303 downgrade non-GET/HEAD to GET and drop the body; 307/308 preserve method + body; cross-origin hops strip `Cookie` and `Authorization`; capped at `MAX_REDIRECTS = 10` hops). Optional `tls` feature still wires rustls + webpki-roots for `https://` URLs. No external HTTP crate. Sixth sub-crate of a Servo-replacement webview runtime targeting Tauri.
//! HTTP-client error type.

/// All errors `net-cat` can produce.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Error {
    /// The URL was malformed.
    InvalidUrl {
        /// The offending source.
        source: String,
    },
    /// The URL used a scheme the v0 client cannot handle.  Currently
    /// returned for anything other than `http`.
    UnsupportedScheme {
        /// The scheme that was attempted.
        scheme: String,
    },
    /// A TCP-level I/O failure.
    Io {
        /// Human description of the failure.
        message: String,
    },
    /// The response status line was malformed.
    InvalidStatusLine {
        /// The text that failed to parse.
        text: String,
    },
    /// A header line was malformed.
    InvalidHeader {
        /// The header line text.
        line: String,
    },
    /// The header name contained illegal bytes.
    InvalidHeaderName {
        /// The name string.
        name: String,
    },
    /// TLS handshake / read / write failure (only produced when the
    /// `tls` feature is enabled).
    Tls {
        /// Human description of the failure.
        message: String,
    },
    /// The server's redirect chain exceeded [`crate::fetch::MAX_REDIRECTS`]
    /// hops.
    TooManyRedirects,
}

impl From<std::io::Error> for Error {
    fn from(value: std::io::Error) -> Self {
        Self::Io {
            message: format!("{value}"),
        }
    }
}

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::InvalidUrl { source } => write!(f, "invalid url: {source:?}"),
            Self::UnsupportedScheme { scheme } => write!(f, "unsupported scheme: {scheme:?}"),
            Self::Io { message } => write!(f, "i/o error: {message}"),
            Self::InvalidStatusLine { text } => write!(f, "invalid status line: {text:?}"),
            Self::InvalidHeader { line } => write!(f, "invalid header line: {line:?}"),
            Self::InvalidHeaderName { name } => write!(f, "invalid header name: {name:?}"),
            Self::Tls { message } => write!(f, "tls error: {message}"),
            Self::TooManyRedirects => write!(f, "exceeded redirect hop cap"),
        }
    }
}

impl std::error::Error for Error {}