Files
rustfs/crates/protocols/src/swift/errors.rs
T
Senol Colak b07383760f Add OpenStack Swift API Support (#2066)
Co-authored-by: houseme <housemecn@gmail.com>
Co-authored-by: Copilot <noreply@github.com>
2026-03-08 01:11:35 +08:00

143 lines
5.2 KiB
Rust

// Copyright 2024 RustFS Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Swift error types and responses
use axum::http::StatusCode;
use axum::response::{IntoResponse, Response};
use std::fmt;
/// Swift-specific error type
#[derive(Debug)]
#[allow(dead_code)] // Error variants used by Swift implementation
pub enum SwiftError {
/// 400 Bad Request
BadRequest(String),
/// 401 Unauthorized
Unauthorized(String),
/// 403 Forbidden
Forbidden(String),
/// 404 Not Found
NotFound(String),
/// 409 Conflict
Conflict(String),
/// 413 Request Entity Too Large (Payload Too Large)
RequestEntityTooLarge(String),
/// 422 Unprocessable Entity
UnprocessableEntity(String),
/// 429 Too Many Requests
TooManyRequests { retry_after: u64, limit: u32, reset: u64 },
/// 500 Internal Server Error
InternalServerError(String),
/// 501 Not Implemented
NotImplemented(String),
/// 503 Service Unavailable
ServiceUnavailable(String),
}
impl fmt::Display for SwiftError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
SwiftError::BadRequest(msg) => write!(f, "Bad Request: {}", msg),
SwiftError::Unauthorized(msg) => write!(f, "Unauthorized: {}", msg),
SwiftError::Forbidden(msg) => write!(f, "Forbidden: {}", msg),
SwiftError::NotFound(msg) => write!(f, "Not Found: {}", msg),
SwiftError::Conflict(msg) => write!(f, "Conflict: {}", msg),
SwiftError::RequestEntityTooLarge(msg) => write!(f, "Request Entity Too Large: {}", msg),
SwiftError::UnprocessableEntity(msg) => write!(f, "Unprocessable Entity: {}", msg),
SwiftError::TooManyRequests { retry_after, .. } => {
write!(f, "Too Many Requests: retry after {} seconds", retry_after)
}
SwiftError::InternalServerError(msg) => write!(f, "Internal Server Error: {}", msg),
SwiftError::NotImplemented(msg) => write!(f, "Not Implemented: {}", msg),
SwiftError::ServiceUnavailable(msg) => write!(f, "Service Unavailable: {}", msg),
}
}
}
impl std::error::Error for SwiftError {}
impl SwiftError {
fn status_code(&self) -> StatusCode {
match self {
SwiftError::BadRequest(_) => StatusCode::BAD_REQUEST,
SwiftError::Unauthorized(_) => StatusCode::UNAUTHORIZED,
SwiftError::Forbidden(_) => StatusCode::FORBIDDEN,
SwiftError::NotFound(_) => StatusCode::NOT_FOUND,
SwiftError::Conflict(_) => StatusCode::CONFLICT,
SwiftError::RequestEntityTooLarge(_) => StatusCode::PAYLOAD_TOO_LARGE,
SwiftError::UnprocessableEntity(_) => StatusCode::UNPROCESSABLE_ENTITY,
SwiftError::TooManyRequests { .. } => StatusCode::TOO_MANY_REQUESTS,
SwiftError::InternalServerError(_) => StatusCode::INTERNAL_SERVER_ERROR,
SwiftError::NotImplemented(_) => StatusCode::NOT_IMPLEMENTED,
SwiftError::ServiceUnavailable(_) => StatusCode::SERVICE_UNAVAILABLE,
}
}
fn generate_trans_id() -> String {
use std::time::{SystemTime, UNIX_EPOCH};
let timestamp = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_else(|_| std::time::Duration::from_secs(0))
.as_micros();
format!("tx{:x}", timestamp)
}
}
impl IntoResponse for SwiftError {
fn into_response(self) -> Response {
let trans_id = Self::generate_trans_id();
let status = self.status_code();
// Handle TooManyRequests specially to include rate limit headers
if let SwiftError::TooManyRequests {
retry_after,
limit,
reset,
} = &self
{
return (
status,
[
("content-type", "text/plain; charset=utf-8".to_string()),
("x-trans-id", trans_id.clone()),
("x-openstack-request-id", trans_id),
("x-ratelimit-limit", limit.to_string()),
("x-ratelimit-remaining", "0".to_string()),
("x-ratelimit-reset", reset.to_string()),
("retry-after", retry_after.to_string()),
],
self.to_string(),
)
.into_response();
}
let body = self.to_string();
(
status,
[
("content-type", "text/plain; charset=utf-8"),
("x-trans-id", trans_id.as_str()),
("x-openstack-request-id", trans_id.as_str()),
],
body,
)
.into_response()
}
}
/// Result type for Swift operations
pub type SwiftResult<T> = Result<T, SwiftError>;