From cc48095d4f2d6c0cee1d97ba80f5f1120cdf1cc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Guedes?= Date: Sat, 17 Feb 2024 20:28:00 -0300 Subject: [PATCH] [object_store] Fix empty Multipart Upload for AWS S3 (#5405) * Fix empty multipart put for AWS S3 * Fix lint --- object_store/src/aws/client.rs | 10 ++++++++++ object_store/src/lib.rs | 15 +++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/object_store/src/aws/client.rs b/object_store/src/aws/client.rs index e06a0ce1846b..fed6911e6f04 100644 --- a/object_store/src/aws/client.rs +++ b/object_store/src/aws/client.rs @@ -538,6 +538,16 @@ impl S3Client { upload_id: &str, parts: Vec, ) -> Result { + let parts = if parts.is_empty() { + // If no parts were uploaded, upload an empty part + // otherwise the completion request will fail + let part = self + .put_part(location, &upload_id.to_string(), 0, Bytes::new()) + .await?; + vec![part] + } else { + parts + }; let request = CompleteMultipartUpload::from(parts); let body = quick_xml::se::to_string(&request).unwrap(); diff --git a/object_store/src/lib.rs b/object_store/src/lib.rs index deb133d250a6..af5676ef5003 100644 --- a/object_store/src/lib.rs +++ b/object_store/src/lib.rs @@ -2200,6 +2200,21 @@ mod tests { let meta = storage.head(&path).await.unwrap(); assert_eq!(meta.size, chunk_size * 2); + + // Empty case + let path = Path::from("test_empty_multipart"); + + let id = multipart.create_multipart(&path).await.unwrap(); + + let parts = vec![]; + + multipart + .complete_multipart(&path, &id, parts) + .await + .unwrap(); + + let meta = storage.head(&path).await.unwrap(); + assert_eq!(meta.size, 0); } #[cfg(any(feature = "azure", feature = "aws"))]