fix(s3): return NoSuchUpload for abort_multipart_upload when upload_id not found (#1569)

Signed-off-by: 安正超 <anzhengchao@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
安正超
2026-01-21 20:45:18 +08:00
committed by GitHub
parent 9fc1c264b0
commit 47ec125589
3 changed files with 25 additions and 4 deletions
+7 -1
View File
@@ -219,6 +219,7 @@ impl From<StorageError> for ApiError {
StorageError::SlowDown => S3ErrorCode::SlowDown,
StorageError::PrefixAccessDenied(_, _) => S3ErrorCode::AccessDenied,
StorageError::InvalidUploadIDKeyCombination(_, _) => S3ErrorCode::InvalidArgument,
StorageError::MalformedUploadID(_) => S3ErrorCode::InvalidArgument,
StorageError::ObjectNameTooLong(_, _) => S3ErrorCode::InvalidArgument,
StorageError::ObjectNamePrefixAsSlash(_, _) => S3ErrorCode::InvalidArgument,
StorageError::ObjectNotFound(_, _) => S3ErrorCode::NoSuchKey,
@@ -227,7 +228,7 @@ impl From<StorageError> for ApiError {
StorageError::FileNotFound => S3ErrorCode::NoSuchKey,
StorageError::FileVersionNotFound => S3ErrorCode::NoSuchVersion,
StorageError::VersionNotFound(_, _, _) => S3ErrorCode::NoSuchVersion,
StorageError::InvalidUploadID(_, _, _) => S3ErrorCode::InvalidPart,
StorageError::InvalidUploadID(_, _, _) => S3ErrorCode::NoSuchUpload,
StorageError::InvalidVersionID(_, _, _) => S3ErrorCode::InvalidArgument,
StorageError::DataMovementOverwriteErr(_, _, _) => S3ErrorCode::InvalidArgument,
StorageError::ObjectExistsAsDirectory(_, _) => S3ErrorCode::InvalidArgument,
@@ -415,6 +416,11 @@ mod tests {
(StorageError::VolumeNotFound, S3ErrorCode::NoSuchBucket),
(StorageError::FileNotFound, S3ErrorCode::NoSuchKey),
(StorageError::FileVersionNotFound, S3ErrorCode::NoSuchVersion),
(StorageError::MalformedUploadID("test".into()), S3ErrorCode::InvalidArgument),
(
StorageError::InvalidUploadID("bucket".into(), "object".into(), "uploadid".into()),
S3ErrorCode::NoSuchUpload,
),
];
for (storage_error, expected_code) in test_cases {
+17 -3
View File
@@ -4902,11 +4902,25 @@ impl S3 for FS {
let opts = &ObjectOptions::default();
store
// Special handling for abort_multipart_upload: Per AWS S3 API specification, this operation
// should return NoSuchUpload (404) when the upload_id doesn't exist, even if the format
// appears invalid. This differs from other multipart operations (upload_part, list_parts,
// complete_multipart_upload) which return InvalidArgument for malformed upload_ids.
// The lenient validation matches AWS S3 behavior where format validation is relaxed for
// abort operations to avoid leaking information about upload_id format requirements.
match store
.abort_multipart_upload(bucket.as_str(), key.as_str(), upload_id.as_str(), opts)
.await
.map_err(ApiError::from)?;
Ok(S3Response::new(AbortMultipartUploadOutput { ..Default::default() }))
{
Ok(_) => Ok(S3Response::new(AbortMultipartUploadOutput { ..Default::default() })),
Err(err) => {
// Convert MalformedUploadID to NoSuchUpload for S3 API compatibility
if matches!(err, StorageError::MalformedUploadID(_)) {
return Err(S3Error::new(S3ErrorCode::NoSuchUpload));
}
Err(ApiError::from(err).into())
}
}
}
#[instrument(level = "debug", skip(self))]
+1
View File
@@ -138,3 +138,4 @@ test_ranged_request_empty_object
test_ranged_request_invalid_range
test_set_multipart_tagging
test_upload_part_copy_percent_encoded_key
test_api_error_from_storage_error_mappings