Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -125,11 +125,12 @@ jobs:

- name: Setup LocalStack (AWS emulation)
run: |
echo "LOCALSTACK_CONTAINER=$(docker run -d -p 4566:4566 localstack/localstack:4.0.3)" >> $GITHUB_ENV
echo "LOCALSTACK_CONTAINER=$(docker run -d -p 4566:4566 localstack/localstack:4.11.1)" >> $GITHUB_ENV
echo "EC2_METADATA_CONTAINER=$(docker run -d -p 1338:1338 amazon/amazon-ec2-metadata-mock:v1.9.2 --imdsv2)" >> $GITHUB_ENV
aws --endpoint-url=http://localhost:4566 s3 mb s3://test-bucket
aws --endpoint-url=http://localhost:4566 s3 mb s3://test-bucket-for-spawn
aws --endpoint-url=http://localhost:4566 s3 mb s3://test-bucket-for-checksum
aws --endpoint-url=http://localhost:4566 s3 mb s3://test-bucket-for-copy-if-not-exists
aws --endpoint-url=http://localhost:4566 s3api create-bucket --bucket test-object-lock --object-lock-enabled-for-bucket

KMS_KEY=$(aws --endpoint-url=http://localhost:4566 kms create-key --description "test key")
Expand Down
34 changes: 17 additions & 17 deletions src/aws/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -701,24 +701,24 @@ impl S3Client {
// If SSE-C is used, we must include the encryption headers in every upload request.
request = request.with_encryption_headers();
}

let (parts, body) = request.send().await?.into_parts();
let checksum_sha256 = parts
.headers
.get(SHA256_CHECKSUM)
.and_then(|v| v.to_str().ok())
.map(|v| v.to_string());

let e_tag = match is_copy {
false => get_etag(&parts.headers).map_err(|source| Error::Metadata { source })?,
true => {
let response = body
.bytes()
.await
.map_err(|source| Error::CreateMultipartResponseBody { source })?;
let response: CopyPartResult = quick_xml::de::from_reader(response.reader())
.map_err(|source| Error::InvalidMultipartResponse { source })?;
response.e_tag
}
let (e_tag, checksum_sha256) = if is_copy {
let response = body
.bytes()
.await
.map_err(|source| Error::CreateMultipartResponseBody { source })?;
let response: CopyPartResult = quick_xml::de::from_reader(response.reader())
.map_err(|source| Error::InvalidMultipartResponse { source })?;
(response.e_tag, response.checksum_sha256)
} else {
let e_tag = get_etag(&parts.headers).map_err(|source| Error::Metadata { source })?;
let checksum_sha256 = parts
.headers
.get(SHA256_CHECKSUM)
.and_then(|v| v.to_str().ok())
.map(|v| v.to_string());
(e_tag, checksum_sha256)
};

let content_id = if self.config.checksum == Some(Checksum::SHA256) {
Expand Down
26 changes: 26 additions & 0 deletions src/aws/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,32 @@ mod tests {
store.delete(&path).await.unwrap();
}

#[tokio::test]
async fn copy_multipart_file_with_signature() {
maybe_skip_integration!();

let bucket = "test-bucket-for-copy-if-not-exists";
let store = AmazonS3Builder::from_env()
.with_bucket_name(bucket)
.with_checksum_algorithm(Checksum::SHA256)
.with_copy_if_not_exists(S3CopyIfNotExists::Multipart)
.build()
.unwrap();

let src = Path::parse("src.bin").unwrap();
let dst = Path::parse("dst.bin").unwrap();
store
.put(&src, PutPayload::from(vec![0u8; 100_000]))
.await
.unwrap();
if store.head(&dst).await.is_ok() {
store.delete(&dst).await.unwrap();
}
store.copy_if_not_exists(&src, &dst).await.unwrap();
store.delete(&src).await.unwrap();
store.delete(&dst).await.unwrap();
}

#[tokio::test]
async fn write_multipart_file_with_signature_object_lock() {
maybe_skip_integration!();
Expand Down
2 changes: 2 additions & 0 deletions src/client/s3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ pub(crate) struct InitiateMultipartUploadResult {
pub(crate) struct CopyPartResult {
#[serde(rename = "ETag")]
pub e_tag: String,
#[serde(default, rename = "ChecksumSHA256")]
pub checksum_sha256: Option<String>,
}

#[derive(Debug, Serialize)]
Expand Down