use hyper::{Response, StatusCode}; use http_body_util::Full; use bytes::Bytes; #[derive(Debug, thiserror::Error)] #[error("S3Error({code}): {message}")] pub struct S3Error { pub code: String, pub message: String, pub status: StatusCode, } impl S3Error { pub fn new(code: &str, message: &str, status: StatusCode) -> Self { Self { code: code.to_string(), message: message.to_string(), status, } } pub fn no_such_key() -> Self { Self::new("NoSuchKey", "The specified key does not exist.", StatusCode::NOT_FOUND) } pub fn no_such_bucket() -> Self { Self::new("NoSuchBucket", "The specified bucket does not exist", StatusCode::NOT_FOUND) } pub fn bucket_not_empty() -> Self { Self::new("BucketNotEmpty", "The bucket you tried to delete is not empty", StatusCode::CONFLICT) } pub fn access_denied() -> Self { Self::new("AccessDenied", "Access Denied", StatusCode::FORBIDDEN) } pub fn no_such_upload() -> Self { Self::new("NoSuchUpload", "The specified upload does not exist", StatusCode::NOT_FOUND) } pub fn invalid_part_number() -> Self { Self::new("InvalidPartNumber", "Part number must be between 1 and 10000", StatusCode::BAD_REQUEST) } pub fn internal_error(msg: &str) -> Self { Self::new("InternalError", msg, StatusCode::INTERNAL_SERVER_ERROR) } pub fn invalid_request(msg: &str) -> Self { Self::new("InvalidRequest", msg, StatusCode::BAD_REQUEST) } pub fn signature_does_not_match() -> Self { Self::new( "SignatureDoesNotMatch", "The request signature we calculated does not match the signature you provided.", StatusCode::FORBIDDEN, ) } pub fn invalid_access_key_id() -> Self { Self::new( "InvalidAccessKeyId", "The AWS Access Key Id you provided does not exist in our records.", StatusCode::FORBIDDEN, ) } pub fn request_time_too_skewed() -> Self { Self::new( "RequestTimeTooSkewed", "The difference between the request time and the current time is too large.", StatusCode::FORBIDDEN, ) } pub fn authorization_header_malformed() -> Self { Self::new( "AuthorizationHeaderMalformed", "The authorization header is malformed.", StatusCode::BAD_REQUEST, ) } pub fn missing_security_header(msg: &str) -> Self { Self::new("MissingSecurityHeader", msg, StatusCode::BAD_REQUEST) } pub fn no_such_bucket_policy() -> Self { Self::new( "NoSuchBucketPolicy", "The bucket policy does not exist.", StatusCode::NOT_FOUND, ) } pub fn malformed_policy(msg: &str) -> Self { Self::new("MalformedPolicy", msg, StatusCode::BAD_REQUEST) } pub fn to_xml(&self) -> String { format!( "\n{}{}", self.code, self.message ) } pub fn to_response(&self, request_id: &str) -> Response> { let xml = self.to_xml(); Response::builder() .status(self.status) .header("content-type", "application/xml") .header("x-amz-request-id", request_id) .body(Full::new(Bytes::from(xml))) .unwrap() } }