use crate::error::CustomError;
use http::StatusCode;
use std::fmt;
#[derive(Debug)]
pub enum MultipartError {
InvalidBoundary,
FieldTooLarge {
field_name: String,
max_size: usize,
},
TooManyFields {
max_fields: usize,
},
RequestTooLarge {
max_size: usize,
},
InvalidField(String),
Io(std::io::Error),
InvalidUtf8(std::str::Utf8Error),
Parse(String),
}
impl fmt::Display for MultipartError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
MultipartError::InvalidBoundary => {
write!(f, "Invalid multipart boundary")
}
MultipartError::FieldTooLarge {
field_name,
max_size,
} => {
write!(
f,
"Field '{}' exceeds maximum size of {} bytes",
field_name, max_size
)
}
MultipartError::TooManyFields { max_fields } => {
write!(f, "Too many fields, maximum allowed: {}", max_fields)
}
MultipartError::RequestTooLarge { max_size } => {
write!(f, "Request exceeds maximum size of {} bytes", max_size)
}
MultipartError::InvalidField(msg) => {
write!(f, "Invalid field: {}", msg)
}
MultipartError::Io(err) => {
write!(f, "I/O error: {}", err)
}
MultipartError::InvalidUtf8(err) => {
write!(f, "Invalid UTF-8: {}", err)
}
MultipartError::Parse(msg) => {
write!(f, "Parse error: {}", msg)
}
}
}
}
impl std::error::Error for MultipartError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
MultipartError::Io(err) => Some(err),
MultipartError::InvalidUtf8(err) => Some(err),
_ => None,
}
}
}
impl CustomError for MultipartError {
fn status_code(&self) -> StatusCode {
match self {
MultipartError::FieldTooLarge { .. }
| MultipartError::TooManyFields { .. }
| MultipartError::RequestTooLarge { .. } => StatusCode::PAYLOAD_TOO_LARGE,
_ => StatusCode::BAD_REQUEST,
}
}
fn error_type(&self) -> &'static str {
match self {
MultipartError::InvalidBoundary => "invalid_boundary",
MultipartError::FieldTooLarge { .. } => "field_too_large",
MultipartError::TooManyFields { .. } => "too_many_fields",
MultipartError::RequestTooLarge { .. } => "request_too_large",
MultipartError::InvalidField(_) => "invalid_field",
MultipartError::Io(_) => "io_error",
MultipartError::InvalidUtf8(_) => "invalid_utf8",
MultipartError::Parse(_) => "parse_error",
}
}
fn metadata(&self) -> Option<serde_json::Value> {
match self {
MultipartError::FieldTooLarge {
field_name,
max_size,
} => Some(serde_json::json!({
"field_name": field_name,
"max_size": max_size,
"limit_type": "field_size"
})),
MultipartError::TooManyFields { max_fields } => Some(serde_json::json!({
"max_fields": max_fields,
"limit_type": "field_count"
})),
MultipartError::RequestTooLarge { max_size } => Some(serde_json::json!({
"max_size": max_size,
"limit_type": "request_size"
})),
_ => None,
}
}
}
impl From<MultipartError> for crate::Error {
fn from(err: MultipartError) -> Self {
crate::Error::Custom(Box::new(err))
}
}
impl From<std::io::Error> for MultipartError {
fn from(err: std::io::Error) -> Self {
MultipartError::Io(err)
}
}
impl From<std::str::Utf8Error> for MultipartError {
fn from(err: std::str::Utf8Error) -> Self {
MultipartError::InvalidUtf8(err)
}
}
#[derive(Debug)]
pub struct MultipartRejection(pub MultipartError);
impl fmt::Display for MultipartRejection {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Multipart extraction failed: {}", self.0)
}
}
impl std::error::Error for MultipartRejection {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
Some(&self.0)
}
}
impl From<MultipartError> for MultipartRejection {
fn from(err: MultipartError) -> Self {
MultipartRejection(err)
}
}