leyline-http 0.1.1

HTTP client that mimics browsers on the wire
Documentation
use crate::core::session::decompress::BodyLimit;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u32)]
#[non_exhaustive]
pub enum ErrorCode {
    NoError = 0x0,
    ProtocolError = 0x1,
    InternalError = 0x2,
    FlowControlError = 0x3,
    SettingsTimeout = 0x4,
    StreamClosed = 0x5,
    FrameSizeError = 0x6,
    RefusedStream = 0x7,
    Cancel = 0x8,
    CompressionError = 0x9,
    ConnectError = 0xa,
    EnhanceYourCalm = 0xb,
    InadequateSecurity = 0xc,
    Http11Required = 0xd,
}

impl ErrorCode {
    pub fn from_u32(val: u32) -> Self {
        match val {
            0x0 => Self::NoError,
            0x1 => Self::ProtocolError,
            0x2 => Self::InternalError,
            0x3 => Self::FlowControlError,
            0x4 => Self::SettingsTimeout,
            0x5 => Self::StreamClosed,
            0x6 => Self::FrameSizeError,
            0x7 => Self::RefusedStream,
            0x8 => Self::Cancel,
            0x9 => Self::CompressionError,
            0xa => Self::ConnectError,
            0xb => Self::EnhanceYourCalm,
            0xc => Self::InadequateSecurity,
            0xd => Self::Http11Required,
            _ => Self::InternalError,
        }
    }
}

#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum H2Error {
    #[error("connection error: {code:?} - {reason}")]
    Connection { code: ErrorCode, reason: String },

    #[error("stream {stream_id} error: {code:?}")]
    Stream { stream_id: u32, code: ErrorCode },

    #[error("io: {0}")]
    Io(#[from] std::io::Error),

    #[error("hpack: {0}")]
    Hpack(String),

    #[error("frame size {size} exceeds max {max}")]
    FrameTooLarge { size: u32, max: u32 },

    #[error("request body stream failed")]
    RequestBody(#[source] std::io::Error),
}

fn copy_io(io: &std::io::Error) -> std::io::Error {
    std::io::Error::new(io.kind(), io.to_string())
}

impl H2Error {
    pub(crate) fn duplicate(&self) -> Self {
        match self {
            Self::Connection { code, reason } => Self::Connection {
                code: *code,
                reason: reason.clone(),
            },
            Self::Stream { stream_id, code } => Self::Stream {
                stream_id: *stream_id,
                code: *code,
            },
            Self::Io(io) => Self::Io(copy_io(io)),
            Self::Hpack(message) => Self::Hpack(message.clone()),
            Self::FrameTooLarge { size, max } => Self::FrameTooLarge {
                size: *size,
                max: *max,
            },
            Self::RequestBody(io) => Self::RequestBody(copy_io(io)),
        }
    }

    pub(crate) fn connection_failed(&self) -> bool {
        self.body_limit().is_none() && !matches!(self, Self::RequestBody(_))
    }

    pub(crate) fn body_limit(&self) -> Option<BodyLimit> {
        match self {
            Self::Io(io) => BodyLimit::of_io(io),
            _ => None,
        }
    }
}