1use thiserror::Error;
4
5#[derive(Debug, Error)]
7pub enum ProxyError {
8 #[error("bucket not found: {0}")]
10 BucketNotFound(String),
11
12 #[error("no such key: {0}")]
14 NoSuchKey(String),
15
16 #[error("access denied")]
18 AccessDenied,
19
20 #[error("signature mismatch")]
22 SignatureDoesNotMatch,
23
24 #[error("invalid request: {0}")]
26 InvalidRequest(String),
27
28 #[error("missing authentication")]
30 MissingAuth,
31
32 #[error("expired credentials")]
34 ExpiredCredentials,
35
36 #[error("invalid OIDC token: {0}")]
38 InvalidOidcToken(String),
39
40 #[error("role not found: {0}")]
42 RoleNotFound(String),
43
44 #[error("backend error: {0}")]
46 BackendError(String),
47
48 #[error("precondition failed")]
50 PreconditionFailed,
51
52 #[error("not modified")]
54 NotModified,
55
56 #[error("config error: {0}")]
58 ConfigError(String),
59
60 #[error("internal error: {0}")]
62 Internal(String),
63}
64
65impl ProxyError {
66 pub fn s3_error_code(&self) -> &'static str {
68 match self {
69 Self::BucketNotFound(_) => "NoSuchBucket",
70 Self::NoSuchKey(_) => "NoSuchKey",
71 Self::AccessDenied => "AccessDenied",
72 Self::SignatureDoesNotMatch => "SignatureDoesNotMatch",
73 Self::InvalidRequest(_) => "InvalidRequest",
74 Self::MissingAuth => "AccessDenied",
75 Self::ExpiredCredentials => "ExpiredToken",
76 Self::InvalidOidcToken(_) => "InvalidIdentityToken",
77 Self::RoleNotFound(_) => "AccessDenied",
78 Self::BackendError(_) => "ServiceUnavailable",
79 Self::PreconditionFailed => "PreconditionFailed",
80 Self::NotModified => "NotModified",
81 Self::ConfigError(_) => "InternalError",
82 Self::Internal(_) => "InternalError",
83 }
84 }
85
86 pub fn status_code(&self) -> u16 {
88 match self {
89 Self::BucketNotFound(_) | Self::NoSuchKey(_) => 404,
90 Self::AccessDenied | Self::MissingAuth | Self::ExpiredCredentials => 403,
91 Self::SignatureDoesNotMatch => 403,
92 Self::InvalidRequest(_) => 400,
93 Self::InvalidOidcToken(_) => 400,
94 Self::RoleNotFound(_) => 403,
95 Self::PreconditionFailed => 412,
96 Self::NotModified => 304,
97 Self::BackendError(_) => 503,
98 Self::ConfigError(_) | Self::Internal(_) => 500,
99 }
100 }
101
102 pub fn safe_message(&self) -> String {
109 match self {
110 Self::BackendError(_) => "Service unavailable".to_string(),
111 Self::ConfigError(_) | Self::Internal(_) => "Internal server error".to_string(),
112 other => other.to_string(),
113 }
114 }
115
116 pub fn from_object_store_error(e: object_store::Error) -> Self {
118 match e {
119 object_store::Error::NotFound { path, .. } => Self::NoSuchKey(path),
120 object_store::Error::Precondition { .. } => Self::PreconditionFailed,
121 object_store::Error::NotModified { .. } => Self::NotModified,
122 _ => Self::BackendError(e.to_string()),
123 }
124 }
125}