use std::fmt;
use std::io;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum ParseErrorKind {
HeadersTooLarge,
ConnectionClosed,
NoRequestLine,
IncompleteHeaders,
MalformedRequestLine,
MalformedRequestTarget,
MalformedHeader,
UnsupportedMethod,
UnsupportedHttpVersion,
TooManyHeaders,
MissingHostHeader,
DuplicateHeader,
ConflictingHeaders,
InvalidContentLength,
UnsupportedTransferEncoding,
}
impl fmt::Display for ParseErrorKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::HeadersTooLarge => f.write_str("headers too large"),
Self::ConnectionClosed => f.write_str("connection closed before headers complete"),
Self::NoRequestLine => f.write_str("no request line"),
Self::IncompleteHeaders => f.write_str("headers not terminated by \\r\\n\\r\\n"),
Self::MalformedRequestLine => f.write_str("malformed request line"),
Self::MalformedRequestTarget => f.write_str("request target contains invalid byte"),
Self::MalformedHeader => f.write_str("malformed header line"),
Self::UnsupportedMethod => f.write_str("unsupported method"),
Self::UnsupportedHttpVersion => f.write_str("unsupported HTTP version"),
Self::TooManyHeaders => f.write_str("too many headers"),
Self::MissingHostHeader => f.write_str("missing required Host header"),
Self::DuplicateHeader => f.write_str("duplicate header not allowed"),
Self::ConflictingHeaders => {
f.write_str("conflicting Transfer-Encoding and Content-Length")
}
Self::InvalidContentLength => f.write_str("invalid Content-Length value"),
Self::UnsupportedTransferEncoding => {
f.write_str("unsupported Transfer-Encoding (only chunked is supported)")
}
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum BodyErrorKind {
BodyTooLarge,
UnexpectedEof,
InvalidChunkSize,
MalformedChunkedEncoding,
}
impl fmt::Display for BodyErrorKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::BodyTooLarge => f.write_str("body exceeds buffer size"),
Self::UnexpectedEof => f.write_str("connection closed before body complete"),
Self::InvalidChunkSize => f.write_str("invalid chunk size"),
Self::MalformedChunkedEncoding => f.write_str("malformed chunked encoding"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum PctErrorKind {
InvalidEscape,
BufferTooSmall,
}
impl fmt::Display for PctErrorKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::InvalidEscape => f.write_str("invalid percent-encoded escape"),
Self::BufferTooSmall => f.write_str("decode buffer too small"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum MediaErrorKind {
Empty,
MissingSlash,
InvalidToken,
}
impl fmt::Display for MediaErrorKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Empty => f.write_str("empty media type"),
Self::MissingSlash => f.write_str("media type missing '/'"),
Self::InvalidToken => f.write_str("media type has empty token"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum ResponseErrorKind {
HeaderCapacityExceeded,
InvalidHeaderName,
InvalidHeaderValue,
DuplicateContentLength,
}
impl fmt::Display for ResponseErrorKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::HeaderCapacityExceeded => f.write_str("response header capacity exceeded"),
Self::InvalidHeaderName => f.write_str("response header name contains invalid byte"),
Self::InvalidHeaderValue => {
f.write_str("response header value contains forbidden byte (NUL, CR, or LF)")
}
Self::DuplicateContentLength => f.write_str("duplicate Content-Length header"),
}
}
}
#[derive(Debug)]
pub enum Error {
Io(io::Error),
Parse(ParseErrorKind),
Body(BodyErrorKind),
Response(ResponseErrorKind),
Pct(PctErrorKind),
Media(MediaErrorKind),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Io(e) => fmt::Display::fmt(e, f),
Self::Parse(k) => fmt::Display::fmt(k, f),
Self::Body(k) => fmt::Display::fmt(k, f),
Self::Response(k) => fmt::Display::fmt(k, f),
Self::Pct(k) => fmt::Display::fmt(k, f),
Self::Media(k) => fmt::Display::fmt(k, f),
}
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::Io(e) => Some(e),
_ => None,
}
}
}
impl From<io::Error> for Error {
fn from(e: io::Error) -> Self {
Self::Io(e)
}
}
impl From<ParseErrorKind> for Error {
fn from(k: ParseErrorKind) -> Self {
Self::Parse(k)
}
}
impl From<BodyErrorKind> for Error {
fn from(k: BodyErrorKind) -> Self {
Self::Body(k)
}
}
impl From<ResponseErrorKind> for Error {
fn from(k: ResponseErrorKind) -> Self {
Self::Response(k)
}
}
impl From<PctErrorKind> for Error {
fn from(k: PctErrorKind) -> Self {
Self::Pct(k)
}
}
impl From<MediaErrorKind> for Error {
fn from(k: MediaErrorKind) -> Self {
Self::Media(k)
}
}
impl From<Error> for io::Error {
fn from(e: Error) -> Self {
match e {
Error::Io(e) => e,
Error::Response(_) | Error::Pct(_) | Error::Media(_) => {
Self::new(io::ErrorKind::InvalidInput, e)
}
other => Self::new(io::ErrorKind::InvalidData, other),
}
}
}
#[derive(Debug)]
pub struct ReadError {
pub error: Error,
pub bytes_read: usize,
}
impl fmt::Display for ReadError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.error.fmt(f)
}
}
impl std::error::Error for ReadError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
self.error.source()
}
}
impl From<ReadError> for io::Error {
fn from(e: ReadError) -> Self {
e.error.into()
}
}