use std::fmt;
use crate::compression::CompressionError;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Error {
InvalidData(String),
BufferOverflow { size: usize, limit: usize },
TooManyHeaders { count: usize, limit: usize },
HeaderLineTooLong { size: usize, limit: usize },
BodyTooLarge { size: usize, limit: usize },
ChunkLineTooLong { size: usize, limit: usize },
Compression(CompressionError),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::InvalidData(msg) => write!(f, "invalid data: {}", msg),
Error::BufferOverflow { size, limit } => {
write!(f, "buffer overflow: {} > {}", size, limit)
}
Error::TooManyHeaders { count, limit } => {
write!(f, "too many headers: {} > {}", count, limit)
}
Error::HeaderLineTooLong { size, limit } => {
write!(f, "header line too long: {} > {}", size, limit)
}
Error::BodyTooLarge { size, limit } => {
write!(f, "body too large: {} > {}", size, limit)
}
Error::ChunkLineTooLong { size, limit } => {
write!(f, "chunk line too long: {} > {}", size, limit)
}
Error::Compression(e) => write!(f, "compression error: {}", e),
}
}
}
impl std::error::Error for Error {}
impl From<CompressionError> for Error {
fn from(e: CompressionError) -> Self {
Error::Compression(e)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum EncodeError {
MissingHostHeader,
ConflictingTransferEncodingAndContentLength,
ForbiddenTransferEncoding { status_code: u16 },
InvalidMethod { method: String },
InvalidRequestTarget { uri: String },
InvalidVersion { version: String },
InvalidHeaderName { name: String },
InvalidHeaderValue { name: String, value: String },
InvalidStatusCode { code: u16 },
InvalidReasonPhrase { phrase: String },
DuplicateHostHeader,
InvalidHostHeader { value: String },
HostAuthorityMismatch { host: String, authority: String },
ForbiddenBodyFor205,
ForbiddenContentLength { status_code: u16 },
ContentLengthMismatch { header_value: u64, body_length: u64 },
InvalidRequestTargetForm { method: String, uri: String },
ConnectRequestWithContent,
UserinfoInHttpUri { uri: String },
NonEmptyHostWithoutAuthority { host: String, uri: String },
EmptyHostInHttpUri { uri: String },
InvalidContentLengthValue { value: String },
DuplicateContentLength,
}
impl fmt::Display for EncodeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
EncodeError::MissingHostHeader => {
write!(f, "missing Host header (required for HTTP/1.1)")
}
EncodeError::ConflictingTransferEncodingAndContentLength => {
write!(
f,
"conflicting Transfer-Encoding and Content-Length headers (RFC 9112 Section 6.2)"
)
}
EncodeError::ForbiddenTransferEncoding { status_code } => {
write!(
f,
"Transfer-Encoding not allowed for {} response (RFC 9112 Section 6.1)",
status_code
)
}
EncodeError::InvalidMethod { method } => {
write!(f, "invalid method: {:?}", method)
}
EncodeError::InvalidRequestTarget { uri } => {
write!(f, "invalid request-target: {:?}", uri)
}
EncodeError::InvalidVersion { version } => {
write!(f, "invalid HTTP version: {:?}", version)
}
EncodeError::InvalidHeaderName { name } => {
write!(f, "invalid header name: {:?}", name)
}
EncodeError::InvalidHeaderValue { name, value } => {
write!(f, "invalid header value for {:?}: {:?}", name, value)
}
EncodeError::InvalidStatusCode { code } => {
write!(f, "invalid status code: {}", code)
}
EncodeError::InvalidReasonPhrase { phrase } => {
write!(f, "invalid reason-phrase: {:?}", phrase)
}
EncodeError::DuplicateHostHeader => {
write!(f, "duplicate Host header")
}
EncodeError::InvalidHostHeader { value } => {
write!(f, "invalid Host header value: {:?}", value)
}
EncodeError::HostAuthorityMismatch { host, authority } => {
write!(
f,
"Host header {:?} does not match request-target authority {:?}",
host, authority
)
}
EncodeError::ForbiddenBodyFor205 => {
write!(
f,
"205 Reset Content must not contain a body (RFC 9110 Section 15.3.6)"
)
}
EncodeError::ForbiddenContentLength { status_code } => {
write!(
f,
"Content-Length not allowed for {} response (RFC 9110 Section 8.6)",
status_code
)
}
EncodeError::ContentLengthMismatch {
header_value,
body_length,
} => {
write!(
f,
"Content-Length header value {} does not match body length {}",
header_value, body_length
)
}
EncodeError::InvalidRequestTargetForm { method, uri } => {
write!(
f,
"request-target form {:?} is invalid for method {:?} (RFC 9112 Section 3.2)",
uri, method
)
}
EncodeError::ConnectRequestWithContent => {
write!(
f,
"CONNECT request must not have content (RFC 9110 Section 9.3.6)"
)
}
EncodeError::UserinfoInHttpUri { uri } => {
write!(
f,
"userinfo not allowed in http/https URI {:?} (RFC 9110 Section 4.2.4)",
uri
)
}
EncodeError::NonEmptyHostWithoutAuthority { host, uri } => {
write!(
f,
"Host header {:?} must be empty for authority-less URI {:?} (RFC 9112 Section 3.2)",
host, uri
)
}
EncodeError::EmptyHostInHttpUri { uri } => {
write!(
f,
"empty host identifier in http/https URI {:?} (RFC 9110 Section 4.2)",
uri
)
}
EncodeError::InvalidContentLengthValue { value } => {
write!(
f,
"invalid Content-Length value {:?}: must be 1*DIGIT (RFC 9110 Section 8.6)",
value
)
}
EncodeError::DuplicateContentLength => {
write!(
f,
"duplicate Content-Length headers with mismatched values (RFC 9110 Section 8.6)"
)
}
}
}
}
impl std::error::Error for EncodeError {}