1pub use aws_sdk_s3;
4
5use crate::secret::SecretCorruptionError;
6
7mod aws {
9 pub use super::aws_sdk_s3::{
10 error::SdkError,
11 operation::{
12 complete_multipart_upload::CompleteMultipartUploadError,
13 create_multipart_upload::CreateMultipartUploadError, get_object::GetObjectError,
14 head_object::HeadObjectError, put_object::PutObjectError, upload_part::UploadPartError,
15 },
16 primitives::ByteStreamError,
17 };
18}
19
20pub type S3GetObjectError = aws::SdkError<aws::GetObjectError>;
22pub type S3ByteStreamError = aws::ByteStreamError;
24
25#[derive(Debug)]
27pub struct CredentialsRetrievalError {
28 pub(crate) message: String,
29}
30
31impl std::fmt::Display for CredentialsRetrievalError {
32 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33 write!(
34 f,
35 "Failed to retrieve S3 credentials from external provider: {}",
36 self.message
37 )
38 }
39}
40
41impl std::error::Error for CredentialsRetrievalError {}
42
43#[derive(Debug)]
45pub enum ClientError {
46 CredentialsCorruption(SecretCorruptionError),
48 CredentialsRetrieval(CredentialsRetrievalError),
50 Proxy(super::proxy::error::ConnectionError),
52}
53
54impl std::fmt::Display for ClientError {
55 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
56 match self {
57 Self::CredentialsCorruption(e) => write!(f, "Credentials corruption: {e}"),
58 Self::CredentialsRetrieval(e) => {
59 write!(f, "{e}")
60 }
61 Self::Proxy(e) => write!(f, "Proxy setup failed: {e}"),
62 }
63 }
64}
65
66impl std::error::Error for ClientError {
67 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
68 match self {
69 Self::CredentialsCorruption(source) => Some(source),
70 Self::CredentialsRetrieval(source) => Some(source),
71 Self::Proxy(source) => Some(source),
72 }
73 }
74}
75
76impl From<SecretCorruptionError> for ClientError {
77 fn from(value: SecretCorruptionError) -> Self {
78 Self::CredentialsCorruption(value)
79 }
80}
81impl From<CredentialsRetrievalError> for ClientError {
82 fn from(value: CredentialsRetrievalError) -> Self {
83 Self::CredentialsRetrieval(value)
84 }
85}
86impl From<super::proxy::error::ConnectionError> for ClientError {
87 fn from(value: super::proxy::error::ConnectionError) -> Self {
88 Self::Proxy(value)
89 }
90}
91
92#[derive(Debug)]
94pub enum ReadChunksError {
95 Io(tokio::io::Error),
97 Send(tokio::sync::mpsc::error::SendError<super::BytesMut>),
99 DataTooLarge,
102}
103
104impl std::fmt::Display for ReadChunksError {
105 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
106 match self {
107 Self::Io(e) => write!(f, "Error while reading chunks from data: {e}"),
108 Self::Send(e) => write!(
109 f,
110 "Error while transferring data to the S3 object store: {e}"
111 ),
112 Self::DataTooLarge => write!(
113 f,
114 "Data is too large to be split into the maximum number of \
115 chunks allowed by the S3 protocol. If not already the case, \
116 consider using a 64-bit system to increase supported data size"
117 ),
118 }
119 }
120}
121
122impl std::error::Error for ReadChunksError {
123 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
124 match self {
125 Self::Io(source) => Some(source),
126 Self::Send(source) => Some(source),
127 Self::DataTooLarge => None,
128 }
129 }
130}
131
132impl From<tokio::io::Error> for ReadChunksError {
133 fn from(value: tokio::io::Error) -> Self {
134 Self::Io(value)
135 }
136}
137
138impl From<tokio::sync::mpsc::error::SendError<super::BytesMut>> for ReadChunksError {
139 fn from(value: tokio::sync::mpsc::error::SendError<super::BytesMut>) -> Self {
140 Self::Send(value)
141 }
142}
143
144impl From<std::num::TryFromIntError> for ReadChunksError {
145 fn from(_: std::num::TryFromIntError) -> Self {
146 Self::DataTooLarge
147 }
148}
149
150type MetadataError = crate::package::error::MetadataError<
151 <std::path::PathBuf as crate::package::source::PackageStream>::Error,
152>;
153
154#[derive(Debug)]
156pub enum UploadError {
157 ClientError(ClientError),
159 Io(tokio::io::Error),
161 InvalidPackage(MetadataError),
163 PutObject(Box<put::Error>),
165 ReadChunks(ReadChunksError),
167 AsyncTask(tokio::task::JoinError),
169}
170
171impl std::fmt::Display for UploadError {
172 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
173 write!(f, "Error while reading chunks")
174 }
175}
176
177impl std::error::Error for UploadError {
178 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
179 match self {
180 Self::ClientError(source) => Some(source),
181 Self::Io(source) => Some(source),
182 Self::InvalidPackage(source) => Some(source),
183 Self::PutObject(source) => Some(source),
184 Self::ReadChunks(source) => Some(source),
185 Self::AsyncTask(source) => Some(source),
186 }
187 }
188}
189
190impl From<ClientError> for UploadError {
191 fn from(value: ClientError) -> Self {
192 Self::ClientError(value)
193 }
194}
195impl From<tokio::io::Error> for UploadError {
196 fn from(value: tokio::io::Error) -> Self {
197 Self::Io(value)
198 }
199}
200impl From<MetadataError> for UploadError {
201 fn from(value: MetadataError) -> Self {
202 Self::InvalidPackage(value)
203 }
204}
205impl From<put::Error> for UploadError {
206 fn from(value: put::Error) -> Self {
207 Self::PutObject(Box::new(value))
208 }
209}
210impl From<ReadChunksError> for UploadError {
211 fn from(value: ReadChunksError) -> Self {
212 Self::ReadChunks(value)
213 }
214}
215impl From<tokio::task::JoinError> for UploadError {
216 fn from(value: tokio::task::JoinError) -> Self {
217 Self::AsyncTask(value)
218 }
219}
220
221pub mod put {
223 use super::aws;
224
225 #[non_exhaustive]
227 #[derive(Debug)]
228 pub enum Error {
229 Put(aws::SdkError<aws::PutObjectError>),
231 PutMultipart(aws::SdkError<aws::CreateMultipartUploadError>),
233 UploadPart(aws::SdkError<aws::UploadPartError>),
235 FetchMultipartId,
237 FetchEntityTag,
239 EmptyUpload,
241 CompleteMultipartUpload(aws::SdkError<aws::CompleteMultipartUploadError>),
243 Semaphore(tokio::sync::AcquireError),
245 Join(tokio::task::JoinError),
247 }
248 impl std::fmt::Display for Error {
249 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
250 match self {
251 Self::Put(source) => std::fmt::Display::fmt(&super::Error(source), f),
252 Self::PutMultipart(source) => std::fmt::Display::fmt(&super::Error(source), f),
253 Self::FetchMultipartId => write!(f, "Multipart upload ID could not be fetched"),
254 Self::UploadPart(source) => source.fmt(f),
255 Self::Semaphore(_) => write!(f, "Semaphore error"),
256 Self::EmptyUpload => write!(f, "No parts have been uploaded"),
257 Self::FetchEntityTag => write!(
258 f,
259 "Could not retrieve the entity tag for the uploaded object"
260 ),
261 Self::CompleteMultipartUpload(source) => source.fmt(f),
262 Self::Join(source) => source.fmt(f),
263 }
264 }
265 }
266
267 impl From<aws::SdkError<aws::PutObjectError>> for Error {
268 fn from(value: aws::SdkError<aws::PutObjectError>) -> Self {
269 Self::Put(value)
270 }
271 }
272
273 impl From<aws::SdkError<aws::UploadPartError>> for Error {
274 fn from(value: aws::SdkError<aws::UploadPartError>) -> Self {
275 Self::UploadPart(value)
276 }
277 }
278
279 impl From<aws::SdkError<aws::CreateMultipartUploadError>> for Error {
280 fn from(value: aws::SdkError<aws::CreateMultipartUploadError>) -> Self {
281 Self::PutMultipart(value)
282 }
283 }
284
285 impl From<tokio::sync::AcquireError> for Error {
286 fn from(value: tokio::sync::AcquireError) -> Self {
287 Self::Semaphore(value)
288 }
289 }
290
291 impl From<aws::SdkError<aws::CompleteMultipartUploadError>> for Error {
292 fn from(value: aws::SdkError<aws::CompleteMultipartUploadError>) -> Self {
293 Self::CompleteMultipartUpload(value)
294 }
295 }
296
297 impl From<tokio::task::JoinError> for Error {
298 fn from(value: tokio::task::JoinError) -> Self {
299 Self::Join(value)
300 }
301 }
302
303 impl std::error::Error for Error {
304 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
305 match self {
306 Self::Put(source) => Some(source),
307 Self::PutMultipart(source) => Some(source),
308 Self::UploadPart(source) => Some(source),
309 Self::FetchMultipartId => None,
310 Self::Semaphore(source) => Some(source),
311 Self::EmptyUpload => None,
312 Self::FetchEntityTag => None,
313 Self::CompleteMultipartUpload(source) => Some(source),
314 Self::Join(source) => Some(source),
315 }
316 }
317 }
318}
319
320pub mod get {
322 use super::aws;
323
324 #[non_exhaustive]
326 #[derive(Debug)]
327 pub struct Error(pub aws::SdkError<aws::HeadObjectError>);
328 impl std::fmt::Display for Error {
329 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
330 std::fmt::Display::fmt(&super::Error(self.source()), f)
331 }
332 }
333
334 impl Error {
335 pub fn source(&self) -> &aws::SdkError<aws::HeadObjectError> {
337 &self.0
338 }
339 }
340
341 impl From<aws::SdkError<aws::HeadObjectError>> for Error {
342 fn from(value: aws::SdkError<aws::HeadObjectError>) -> Self {
343 Self(value)
344 }
345 }
346
347 impl std::error::Error for Error {
348 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
349 Some(&self.0)
350 }
351 }
352}
353
354#[derive(Debug)]
356struct Error<E>(E);
357
358impl<E> std::fmt::Display for Error<&aws::SdkError<E>>
359where
360 E: ExtractMessage + MainMessage,
361{
362 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
363 match &self.0 {
364 aws::SdkError::DispatchFailure(e) => {
365 use std::error::Error;
366 if let Some(connector_error) = e.as_connector_error()
367 && let Some(source) = connector_error.source()
368 {
369 return write!(f, "could not connect to s3 store: {source}");
370 }
371 }
372 aws::SdkError::ServiceError(e) => {
373 if let Some(description) = e.err().extract_message() {
374 return write!(f, "{}: {description}", E::MAIN_MESSAGE);
375 }
376 if let Some(description) = e.raw().headers().get("x-minio-error-desc") {
377 return write!(f, "{}: {description}", E::MAIN_MESSAGE);
378 }
379 }
380 _ => {}
381 }
382 write!(f, "{}: {}", E::MAIN_MESSAGE, self.0)
383 }
384}
385
386trait MainMessage {
387 const MAIN_MESSAGE: &'static str;
388}
389
390impl MainMessage for aws::HeadObjectError {
391 const MAIN_MESSAGE: &'static str = "unable to access s3 object";
392}
393
394impl MainMessage for aws::PutObjectError {
395 const MAIN_MESSAGE: &'static str = "unable to put s3 object";
396}
397
398impl MainMessage for aws::CreateMultipartUploadError {
399 const MAIN_MESSAGE: &'static str = "unable to put s3 object";
400}
401
402trait ExtractMessage {
403 fn extract_message(&self) -> Option<&str>;
404}
405
406impl ExtractMessage for aws::HeadObjectError {
407 fn extract_message(&self) -> Option<&str> {
408 self.meta().message()
409 }
410}
411
412impl ExtractMessage for aws::PutObjectError {
413 fn extract_message(&self) -> Option<&str> {
414 self.meta().message()
415 }
416}
417
418impl ExtractMessage for aws::CreateMultipartUploadError {
419 fn extract_message(&self) -> Option<&str> {
420 self.meta().message()
421 }
422}
423
424#[derive(Debug)]
426pub enum OpenError {
427 Io(tokio::io::Error),
429 Get(get::Error),
431 ObjectTooSmall,
433 MissingSizeInfo,
435 GetObject(S3GetObjectError),
437 ReadStream(S3ByteStreamError),
439 Client(ClientError),
441}
442
443impl std::fmt::Display for OpenError {
444 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
445 write!(
446 f,
447 "Error while opening zip reader{}",
448 match self {
449 Self::ObjectTooSmall => ": s3 object size is too small",
450 Self::MissingSizeInfo => ": unable to fetch s3 object size",
451 Self::ReadStream(_) => ": error while reading from stream",
452 _ => "",
453 }
454 )
455 }
456}
457
458impl std::error::Error for OpenError {
459 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
460 match self {
461 Self::Io(source) => Some(source),
462 Self::Get(source) => Some(source),
463 Self::ObjectTooSmall => None,
464 Self::MissingSizeInfo => None,
465 Self::GetObject(source) => Some(source),
466 Self::ReadStream(source) => Some(source),
467 Self::Client(source) => Some(source),
468 }
469 }
470}
471
472impl From<tokio::io::Error> for OpenError {
473 fn from(value: tokio::io::Error) -> Self {
474 Self::Io(value)
475 }
476}
477
478impl From<get::Error> for OpenError {
479 fn from(value: get::Error) -> Self {
480 Self::Get(value)
481 }
482}
483
484impl From<S3GetObjectError> for OpenError {
485 fn from(value: S3GetObjectError) -> Self {
486 Self::GetObject(value)
487 }
488}
489
490impl From<S3ByteStreamError> for OpenError {
491 fn from(value: S3ByteStreamError) -> Self {
492 Self::ReadStream(value)
493 }
494}
495
496impl From<ClientError> for OpenError {
497 fn from(value: ClientError) -> Self {
498 Self::Client(value)
499 }
500}