use thiserror::Error;
pub type ParseResult<T> = Result<T, ParseError>;
#[derive(Error, Debug)]
pub enum ParseError {
#[error("Invalid HTTP method: {method}")]
InvalidMethod { method: String },
#[error("Invalid header name: {name}")]
InvalidHeaderName { name: String },
#[error("Invalid header value: {value}")]
InvalidHeaderValue { value: String },
#[error("Header value contains non-ASCII characters")]
HeaderToStrError,
#[error("Invalid status code: {code}")]
InvalidStatusCode { code: u16 },
#[error("JSON parsing failed: {message}")]
JsonRejection { message: String },
}
impl ParseError {
pub fn invalid_method<T: Into<String>>(method: T) -> Self {
ParseError::InvalidMethod {
method: method.into(),
}
}
pub fn invalid_header_name<T: Into<String>>(name: T) -> Self {
ParseError::InvalidHeaderName { name: name.into() }
}
pub fn invalid_header_value<T: Into<String>>(value: T) -> Self {
ParseError::InvalidHeaderValue {
value: value.into(),
}
}
pub fn header_to_str_error() -> Self {
ParseError::HeaderToStrError
}
pub fn invalid_status_code(code: u16) -> Self {
ParseError::InvalidStatusCode { code }
}
pub fn json_rejection<T: Into<String>>(message: T) -> Self {
ParseError::JsonRejection {
message: message.into(),
}
}
}
impl From<axum::http::method::InvalidMethod> for ParseError {
fn from(err: axum::http::method::InvalidMethod) -> Self {
ParseError::InvalidMethod {
method: err.to_string(),
}
}
}
impl From<axum::http::header::InvalidHeaderName> for ParseError {
fn from(err: axum::http::header::InvalidHeaderName) -> Self {
ParseError::InvalidHeaderName {
name: err.to_string(),
}
}
}
impl From<axum::http::header::InvalidHeaderValue> for ParseError {
fn from(err: axum::http::header::InvalidHeaderValue) -> Self {
ParseError::InvalidHeaderValue {
value: err.to_string(),
}
}
}
impl From<axum::http::header::ToStrError> for ParseError {
fn from(_: axum::http::header::ToStrError) -> Self {
ParseError::HeaderToStrError
}
}
impl From<axum::extract::rejection::JsonRejection> for ParseError {
fn from(err: axum::extract::rejection::JsonRejection) -> Self {
ParseError::JsonRejection {
message: err.to_string(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_error_creation() {
let error = ParseError::invalid_method("INVALID");
assert!(matches!(error, ParseError::InvalidMethod { .. }));
assert_eq!(error.to_string(), "Invalid HTTP method: INVALID");
}
#[test]
fn test_header_errors() {
let name_error = ParseError::invalid_header_name("bad name");
let value_error = ParseError::invalid_header_value("bad\x00value");
let str_error = ParseError::header_to_str_error();
assert!(matches!(name_error, ParseError::InvalidHeaderName { .. }));
assert!(matches!(value_error, ParseError::InvalidHeaderValue { .. }));
assert!(matches!(str_error, ParseError::HeaderToStrError));
}
#[test]
fn test_status_code_error() {
let error = ParseError::invalid_status_code(999);
assert!(matches!(error, ParseError::InvalidStatusCode { code: 999 }));
}
#[test]
fn test_json_error() {
let error = ParseError::json_rejection("Invalid JSON syntax");
assert!(matches!(error, ParseError::JsonRejection { .. }));
}
#[test]
fn test_axum_conversions() {
let axum_method_err =
axum::http::Method::from_bytes(b"INVALID METHOD WITH SPACES").unwrap_err();
let parse_err: ParseError = axum_method_err.into();
assert!(matches!(parse_err, ParseError::InvalidMethod { .. }));
}
}