use thiserror::Error;
#[derive(Debug, Clone, PartialEq, Eq, Error)]
#[non_exhaustive]
pub enum BuildError {
#[error("request is missing required response header {header}")]
MissingRequiredResponseHeader {
header: &'static str,
},
#[error("illegal byte {byte:#04x} at offset {offset} in {field}")]
IllegalCharacter {
field: &'static str,
offset: usize,
byte: u8,
},
#[error("{field} is not a token")]
NotAToken {
field: &'static str,
},
}
#[derive(Debug, Clone, PartialEq, Eq, Error)]
#[non_exhaustive]
pub enum ParseError {
#[error("malformed start line: {0}")]
StartLine(#[from] StartLineError),
#[error("malformed header field on line {line}: {kind}")]
HeaderSyntax {
line: usize,
kind: HeaderSyntaxError,
},
#[error("cannot frame message body: {0}")]
Framing(#[from] FramingError),
#[error("{limit} limit exceeded ({value})")]
Limit {
limit: LimitKind,
value: usize,
},
#[error("incomplete message")]
Incomplete,
}
#[derive(Debug, Clone, PartialEq, Eq, Error)]
#[non_exhaustive]
pub enum StartLineError {
#[error("empty")]
Empty,
#[error("a request line must have exactly three space-separated elements")]
RequestLineShape,
#[error("method is not a token")]
Method,
#[error("bad Request-URI: {0}")]
Uri(#[from] UriError),
#[error("status line has no status code")]
MissingStatusCode,
#[error("status code is not three digits in 100..=699")]
StatusCode,
}
#[derive(Debug, Clone, PartialEq, Eq, Error)]
#[non_exhaustive]
pub enum HeaderSyntaxError {
#[error("no colon")]
MissingColon,
#[error("empty field name")]
EmptyName,
#[error("field name is not a token")]
NameNotToken,
#[error("bare CR or LF")]
BareNewline,
#[error("header section begins with a continuation line")]
LeadingFold,
}
#[derive(Debug, Clone, PartialEq, Eq, Error)]
#[non_exhaustive]
pub enum FramingError {
#[error("no blank line after headers")]
NoHeaderTerminator,
#[error("repeated Content-Length")]
ContentLengthRepeated,
#[error("Content-Length is not a decimal number")]
ContentLengthMalformed,
#[error("Content-Length exceeds the octets present")]
BodyTruncated,
#[error("Content-Length is required on stream transports")]
ContentLengthRequired,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LimitKind {
MessageBytes,
BodyBytes,
Headers,
HeaderBytes,
FoldingLines,
}
impl std::fmt::Display for LimitKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let name = match self {
Self::MessageBytes => "message size",
Self::BodyBytes => "body size",
Self::Headers => "header count",
Self::HeaderBytes => "header size",
Self::FoldingLines => "folding line count",
};
f.write_str(name)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Error)]
#[non_exhaustive]
pub enum UriError {
#[error("missing or malformed URI scheme")]
Scheme,
#[error("URI has no host")]
EmptyHost,
#[error("invalid character in host")]
Host,
#[error("invalid port")]
Port,
#[error("unterminated IPv6 reference")]
Ipv6Reference,
#[error("illegal character in URI")]
IllegalCharacter,
#[error("malformed percent escape")]
PercentEscape,
#[error("invalid SIP URI user part")]
User,
#[error("invalid tel URI telephone-subscriber")]
TelephoneSubscriber,
#[error("retained URI span is inconsistent with its wire representation")]
RetainedSpan,
#[error("empty parameter name")]
EmptyParameterName,
#[error("repeated uri-parameter name")]
DuplicateParameterName,
}
#[derive(Debug, Clone, PartialEq, Eq, Error)]
#[non_exhaustive]
pub enum HeaderError {
#[error("malformed {header} header")]
Syntax {
header: &'static str,
},
#[error("{header} value out of range")]
OutOfRange {
header: &'static str,
},
#[error("invalid URI in {header} header: {source}")]
Uri {
header: &'static str,
#[source]
source: UriError,
},
#[error("unterminated quoted string in {header} header")]
UnterminatedQuotedString {
header: &'static str,
},
}
#[derive(Debug, Clone, PartialEq, Eq, Error)]
#[non_exhaustive]
pub enum AddressEditError {
#[error("header does not have a supported address grammar")]
UnsupportedHeader,
#[error("malformed address field: {0}")]
Malformed(#[source] HeaderError),
#[error("address value index {index} is out of range")]
IndexOutOfRange {
index: usize,
},
#[error("invalid replacement URI: {0}")]
InvalidUri(#[source] UriError),
#[error("replacement display name contains a control byte")]
InvalidDisplayName,
}
#[derive(Debug, Clone, PartialEq, Eq, Error)]
#[non_exhaustive]
pub enum WarningEditError {
#[error("malformed Warning field: {0}")]
Malformed(#[source] HeaderError),
#[error("Warning value index {index} is out of range")]
IndexOutOfRange {
index: usize,
},
#[error("replacement Warning pseudonym is not a token")]
InvalidPseudonym,
}