Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import software.amazon.awssdk.services.s3.model.UploadPartRequest;
import software.amazon.awssdk.services.s3.model.UploadPartResponse;
import software.amazon.encryption.s3.algorithms.AlgorithmSuite;
import software.amazon.encryption.s3.internal.ConvertSDKRequests;
import software.amazon.encryption.s3.internal.GetEncryptedObjectPipeline;
import software.amazon.encryption.s3.internal.InstructionFileConfig;
import software.amazon.encryption.s3.internal.MultiFileOutputStream;
Expand Down Expand Up @@ -192,11 +193,7 @@ public PutObjectResponse putObject(PutObjectRequest putObjectRequest, RequestBod

if (_enableMultipartPutObject) {
try {
CompleteMultipartUploadResponse completeResponse = multipartPutObject(putObjectRequest, requestBody);
PutObjectResponse response = PutObjectResponse.builder()
.eTag(completeResponse.eTag())
.build();
return response;
return multipartPutObject(putObjectRequest, requestBody);
} catch (Throwable e) {
throw new S3EncryptionClientException("Exception while performing Multipart Upload PutObject", e);
}
Expand Down Expand Up @@ -274,7 +271,7 @@ public <T> T getObject(GetObjectRequest getObjectRequest,
}
}

private CompleteMultipartUploadResponse multipartPutObject(PutObjectRequest request, RequestBody requestBody) throws Throwable {
private PutObjectResponse multipartPutObject(PutObjectRequest request, RequestBody requestBody) throws Throwable {
// Similar logic exists in the MultipartUploadObjectPipeline,
// but the request types do not match so refactoring is not possible
final long contentLength;
Expand Down Expand Up @@ -354,7 +351,7 @@ private CompleteMultipartUploadResponse multipartPutObject(PutObjectRequest requ
outputStream.cleanup();
}
// Complete upload
return observer.onCompletion(partETags);
return ConvertSDKRequests.convertResponse(observer.onCompletion(partETags));
}

private <T extends Throwable> T onAbort(UploadObjectObserver observer, T t) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
package software.amazon.encryption.s3.internal;

import java.time.Instant;
import java.util.Map;

import software.amazon.awssdk.services.s3.model.ChecksumType;
import software.amazon.awssdk.services.s3.model.CompleteMultipartUploadResponse;
import software.amazon.awssdk.services.s3.model.CreateMultipartUploadRequest;
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
import java.time.Instant;
import java.util.Map;
import software.amazon.awssdk.services.s3.model.PutObjectResponse;

public class ConvertSDKRequests {

public static CreateMultipartUploadRequest convert(PutObjectRequest request) {
public static CreateMultipartUploadRequest convertRequest(PutObjectRequest request) {

final CreateMultipartUploadRequest.Builder output = CreateMultipartUploadRequest.builder();
request
Expand Down Expand Up @@ -140,6 +143,70 @@ public static CreateMultipartUploadRequest convert(PutObjectRequest request) {
.build();
}

public static PutObjectResponse convertResponse(CompleteMultipartUploadResponse response) {
final PutObjectResponse.Builder output = PutObjectResponse.builder();
response
.toBuilder()
.sdkFields()
.forEach(f -> {
final Object value = f.getValueOrDefault(response);
if (value != null) {
switch (f.memberName()) {
case "ETag":
output.eTag((String) value);
break;
case "Expiration":
output.expiration((String) value);
break;
case "ChecksumCRC32":
output.checksumCRC32((String) value);
break;
case "ChecksumCRC32C":
output.checksumCRC32C((String) value);
break;
case "ChecksumCRC64NVME":
output.checksumCRC64NVME((String) value);
break;
case "ChecksumSHA1":
output.checksumSHA1((String) value);
break;
case "ChecksumSHA256":
output.checksumSHA256((String) value);
break;
case "ChecksumType":
output.checksumType((String) value);
break;
case "ServerSideEncryption":
output.serverSideEncryption((String) value);
break;
case "VersionId":
output.versionId((String) value);
break;
case "SSEKMSKeyId":
output.ssekmsKeyId((String) value);
break;
case "BucketKeyEnabled":
output.bucketKeyEnabled((Boolean) value);
break;
case "RequestCharged":
output.requestCharged((String) value);
break;
// Ignored fields: Location, Bucket, Key
case "Location":
case "Bucket":
case "Key":
// These fields exist only in CompleteMultipartUploadResponse, not in PutObjectResponse
break;
default:
// We should silently drop unknown fields because,
// once the object is stored we expect to return success response.
break;
}
}
});
return output.build();
}

private static boolean isStringStringMap(Object value) {
if (!(value instanceof Map)) {
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public UploadObjectObserver init(PutObjectRequest req,

public String onUploadCreation(PutObjectRequest req) {
CreateMultipartUploadResponse res =
s3EncryptionClient.createMultipartUpload(ConvertSDKRequests.convert(req));
s3EncryptionClient.createMultipartUpload(ConvertSDKRequests.convertRequest(req));
return this.uploadId = res.uploadId();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,16 @@
import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.services.s3.S3AsyncClient;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.ChecksumType;
import software.amazon.awssdk.services.s3.model.CompletedPart;
import software.amazon.awssdk.services.s3.model.CreateMultipartUploadResponse;
import software.amazon.awssdk.services.s3.model.GetObjectResponse;
import software.amazon.awssdk.services.s3.model.PutObjectResponse;
import software.amazon.awssdk.services.s3.model.SdkPartType;
import software.amazon.awssdk.services.s3.model.ServerSideEncryption;
import software.amazon.awssdk.services.s3.model.StorageClass;
import software.amazon.awssdk.services.s3.model.UploadPartRequest;
import software.amazon.awssdk.services.s3.model.UploadPartResponse;
import software.amazon.awssdk.services.s3.model.StorageClass;
import software.amazon.awssdk.utils.IoUtils;
import software.amazon.encryption.s3.utils.BoundedInputStream;

Expand Down Expand Up @@ -543,18 +545,23 @@ public void multipartPutObjectWithOptions() throws IOException {

final StorageClass storageClass = StorageClass.INTELLIGENT_TIERING;

v3Client.putObject(builder -> builder
// PutObject
final PutObjectResponse putObjectResponse = v3Client.putObject(builder -> builder
.bucket(BUCKET)
.overrideConfiguration(withAdditionalConfiguration(encryptionContext))
.storageClass(storageClass)
.key(objectKey), RequestBody.fromInputStream(inputStream, fileSizeLimit));

// Asserts
assertEquals(ChecksumType.FULL_OBJECT.toString(), putObjectResponse.checksumTypeAsString());
assertEquals(ServerSideEncryption.AES256.toString(), putObjectResponse.serverSideEncryptionAsString());

// GetObject
final ResponseInputStream<GetObjectResponse> output = v3Client.getObject(builder -> builder
.bucket(BUCKET)
.overrideConfiguration(S3EncryptionClient.withAdditionalConfiguration(encryptionContext))
.key(objectKey));

// Asserts
assertTrue(IOUtils.contentEquals(objectStreamForResult, output));
assertEquals(storageClass, output.response().storageClass());

Expand Down
Loading