use std::fmt::{Display, Formatter};
#[derive(Debug, PartialEq)]
pub enum BadContentLength {
NotUtf8(std::str::Utf8Error),
NotU64(<u64 as std::str::FromStr>::Err),
}
impl Display for BadContentLength {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
match self {
Self::NotUtf8(inner) => inner.fmt(f),
Self::NotU64(inner) => inner.fmt(f),
}
}
}
impl std::error::Error for BadContentLength {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::NotUtf8(inner) => Some(inner),
Self::NotU64(inner) => Some(inner),
}
}
}
#[derive(Debug, PartialEq)]
pub enum BadChunkHeader {
SizeNotHex,
SizeNotU64,
ExtChar,
Newline,
}
impl Display for BadChunkHeader {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
match self {
Self::SizeNotHex => write!(f, "Chunk size is not a hex number"),
Self::SizeNotU64 => write!(f, "Chunk size is too large"),
Self::ExtChar => write!(f, "Chunk extensions contains invalid character"),
Self::Newline => write!(f, "Chunk framing contains incorrect newlines"),
}
}
}
impl std::error::Error for BadChunkHeader {}
#[derive(Debug, PartialEq)]
pub enum InvalidData {
ParseHeaders(httparse::Error),
ResponseHeadersTooLong,
SwitchingProtocols,
ContentLengthAndTransferEncoding,
ContentLengthWithNoContent,
MultipleContentLengths,
BadContentLength(BadContentLength),
TransferEncodingWithNoContent,
MultipleTransferEncodings,
NotChunked,
BadChunkHeader(BadChunkHeader),
}
impl Display for InvalidData {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
match self {
Self::ParseHeaders(inner) => inner.fmt(f),
Self::ResponseHeadersTooLong => write!(f, "Response headers too long"),
Self::SwitchingProtocols => write!(f, "Unsupported 101 Switching Protocols received"),
Self::ContentLengthAndTransferEncoding => {
write!(f, "Content-Length and Transfer-Encoding both received")
}
Self::ContentLengthWithNoContent => {
write!(f, "Content-Length received in 204 No Content response")
}
Self::MultipleContentLengths => write!(f, "Multiple Content-Length headers received"),
Self::BadContentLength(inner) => {
write!(f, "Invalid Content-Length header received: {inner}")
}
Self::TransferEncodingWithNoContent => {
write!(f, "Transfer-Encoding received in 204 No Content response")
}
Self::MultipleTransferEncodings => {
write!(f, "Multiple Transfer-Encoding headers received")
}
Self::NotChunked => write!(f, "Unsupported Transfer-Encoding received"),
Self::BadChunkHeader(inner) => write!(f, "Invalid chunk header received: {inner}"),
}
}
}
impl std::error::Error for InvalidData {
fn source<'a>(&'a self) -> Option<&'a (dyn std::error::Error + 'static)> {
match self {
Self::ParseHeaders(inner) => Some(inner),
Self::BadContentLength(inner) => Some(inner),
Self::BadChunkHeader(inner) => Some(inner),
Self::ResponseHeadersTooLong
| Self::SwitchingProtocols
| Self::ContentLengthAndTransferEncoding
| Self::ContentLengthWithNoContent
| Self::MultipleContentLengths
| Self::TransferEncodingWithNoContent
| Self::MultipleTransferEncodings
| Self::NotChunked => None,
}
}
}
impl From<httparse::Error> for InvalidData {
fn from(inner: httparse::Error) -> Self {
Self::ParseHeaders(inner)
}
}
impl From<BadContentLength> for InvalidData {
fn from(inner: BadContentLength) -> Self {
Self::BadContentLength(inner)
}
}
impl From<BadChunkHeader> for InvalidData {
fn from(inner: BadChunkHeader) -> Self {
Self::BadChunkHeader(inner)
}
}
impl From<InvalidData> for std::io::Error {
#[cfg(feature = "detailed-errors")]
fn from(inner: InvalidData) -> Self {
Self::new(std::io::ErrorKind::InvalidData, inner)
}
#[cfg(not(feature = "detailed-errors"))]
fn from(_: InvalidData) -> Self {
std::io::ErrorKind::InvalidData.into()
}
}
impl From<BadContentLength> for std::io::Error {
fn from(inner: BadContentLength) -> Self {
Into::<InvalidData>::into(inner).into()
}
}
impl From<BadChunkHeader> for std::io::Error {
fn from(inner: BadChunkHeader) -> Self {
Into::<InvalidData>::into(inner).into()
}
}