|
83 | 83 | )) |
84 | 84 | } |
85 | 85 |
|
| 86 | +fn is_s3_compatible_not_found_code<E>(err: &E) -> bool |
| 87 | +where |
| 88 | + E: ProvideErrorMetadata, |
| 89 | +{ |
| 90 | + // AWS S3 uses the modeled NoSuchKey error; some TOS direct backends return NotFound. |
| 91 | + err.code() |
| 92 | + .map(|code| code == "NotFound") |
| 93 | + .unwrap_or(false) |
| 94 | +} |
| 95 | + |
86 | 96 | fn format_sdk_s3_error<E, R>(op: &str, scope: &str, sdk_err: &SdkError<E, R>) -> Error |
87 | 97 | where |
88 | 98 | E: std::fmt::Display + ProvideErrorMetadata + RequestId + RequestIdExt, |
@@ -512,7 +522,7 @@ impl S3Client { |
512 | 522 | Ok(resp) => resp, |
513 | 523 | Err(sdk_err) => { |
514 | 524 | let service_err = sdk_err.into_service_error(); |
515 | | - if service_err.is_no_such_key() { |
| 525 | + if service_err.is_no_such_key() || is_s3_compatible_not_found_code(&service_err) { |
516 | 526 | return Err(Error::NotFound(key.to_string())); |
517 | 527 | } |
518 | 528 | return Err(format_s3_service_error( |
@@ -545,7 +555,7 @@ impl S3Client { |
545 | 555 | Ok(resp) => resp, |
546 | 556 | Err(sdk_err) => { |
547 | 557 | let service_err = sdk_err.into_service_error(); |
548 | | - if service_err.is_no_such_key() { |
| 558 | + if service_err.is_no_such_key() || is_s3_compatible_not_found_code(&service_err) { |
549 | 559 | return Ok(None); |
550 | 560 | } |
551 | 561 | return Err(format_s3_service_error( |
@@ -592,7 +602,7 @@ impl S3Client { |
592 | 602 | Ok(resp) => resp, |
593 | 603 | Err(sdk_err) => { |
594 | 604 | let service_err = sdk_err.into_service_error(); |
595 | | - if service_err.is_no_such_key() { |
| 605 | + if service_err.is_no_such_key() || is_s3_compatible_not_found_code(&service_err) { |
596 | 606 | return Err(Error::NotFound(key.to_string())); |
597 | 607 | } |
598 | 608 | return Err(format_s3_service_error( |
@@ -846,7 +856,7 @@ impl S3Client { |
846 | 856 | // Check if it's a 404 |
847 | 857 | if sdk_err |
848 | 858 | .as_service_error() |
849 | | - .map(|err| err.is_not_found()) |
| 859 | + .map(|err| err.is_not_found() || is_s3_compatible_not_found_code(err)) |
850 | 860 | .unwrap_or(false) |
851 | 861 | { |
852 | 862 | Ok(None) |
@@ -1384,4 +1394,31 @@ mod tests { |
1384 | 1394 | other => panic!("expected internal error, got {other:?}"), |
1385 | 1395 | } |
1386 | 1396 | } |
| 1397 | + |
| 1398 | + #[test] |
| 1399 | + fn test_is_s3_compatible_not_found_code_accepts_tos_code() { |
| 1400 | + let tos_not_found = FakeServiceError { |
| 1401 | + raw: "service error", |
| 1402 | + meta: ErrorMetadata::builder().code("NotFound").build(), |
| 1403 | + }; |
| 1404 | + assert!(is_s3_compatible_not_found_code(&tos_not_found)); |
| 1405 | + |
| 1406 | + let no_such_key = FakeServiceError { |
| 1407 | + raw: "service error", |
| 1408 | + meta: ErrorMetadata::builder().code("NoSuchKey").build(), |
| 1409 | + }; |
| 1410 | + assert!(!is_s3_compatible_not_found_code(&no_such_key)); |
| 1411 | + |
| 1412 | + let access_denied = FakeServiceError { |
| 1413 | + raw: "service error", |
| 1414 | + meta: ErrorMetadata::builder().code("AccessDenied").build(), |
| 1415 | + }; |
| 1416 | + assert!(!is_s3_compatible_not_found_code(&access_denied)); |
| 1417 | + |
| 1418 | + let no_code = FakeServiceError { |
| 1419 | + raw: "service error", |
| 1420 | + meta: ErrorMetadata::builder().build(), |
| 1421 | + }; |
| 1422 | + assert!(!is_s3_compatible_not_found_code(&no_code)); |
| 1423 | + } |
1387 | 1424 | } |
0 commit comments