Skip to content

Commit dec503b

Browse files
imabhichowkessplas
andauthored
fix: support PutObjectResponse fields (#462)
Co-authored-by: Kess Plasmeier <[email protected]>
1 parent 599f941 commit dec503b

File tree

5 files changed

+178
-51
lines changed

5 files changed

+178
-51
lines changed

src/main/java/software/amazon/encryption/s3/S3EncryptionClient.java

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
import software.amazon.awssdk.services.s3.model.UploadPartRequest;
4747
import software.amazon.awssdk.services.s3.model.UploadPartResponse;
4848
import software.amazon.encryption.s3.algorithms.AlgorithmSuite;
49+
import software.amazon.encryption.s3.internal.ConvertSDKRequests;
4950
import software.amazon.encryption.s3.internal.GetEncryptedObjectPipeline;
5051
import software.amazon.encryption.s3.internal.InstructionFileConfig;
5152
import software.amazon.encryption.s3.internal.MultiFileOutputStream;
@@ -192,11 +193,7 @@ public PutObjectResponse putObject(PutObjectRequest putObjectRequest, RequestBod
192193

193194
if (_enableMultipartPutObject) {
194195
try {
195-
CompleteMultipartUploadResponse completeResponse = multipartPutObject(putObjectRequest, requestBody);
196-
PutObjectResponse response = PutObjectResponse.builder()
197-
.eTag(completeResponse.eTag())
198-
.build();
199-
return response;
196+
return multipartPutObject(putObjectRequest, requestBody);
200197
} catch (Throwable e) {
201198
throw new S3EncryptionClientException("Exception while performing Multipart Upload PutObject", e);
202199
}
@@ -274,7 +271,7 @@ public <T> T getObject(GetObjectRequest getObjectRequest,
274271
}
275272
}
276273

277-
private CompleteMultipartUploadResponse multipartPutObject(PutObjectRequest request, RequestBody requestBody) throws Throwable {
274+
private PutObjectResponse multipartPutObject(PutObjectRequest request, RequestBody requestBody) throws Throwable {
278275
// Similar logic exists in the MultipartUploadObjectPipeline,
279276
// but the request types do not match so refactoring is not possible
280277
final long contentLength;
@@ -354,7 +351,7 @@ private CompleteMultipartUploadResponse multipartPutObject(PutObjectRequest requ
354351
outputStream.cleanup();
355352
}
356353
// Complete upload
357-
return observer.onCompletion(partETags);
354+
return ConvertSDKRequests.convertResponse(observer.onCompletion(partETags));
358355
}
359356

360357
private <T extends Throwable> T onAbort(UploadObjectObserver observer, T t) {

src/main/java/software/amazon/encryption/s3/internal/ConvertSDKRequests.java

Lines changed: 78 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
package software.amazon.encryption.s3.internal;
22

3+
import java.time.Instant;
4+
import java.util.Map;
5+
6+
import org.apache.commons.logging.LogFactory;
37
import software.amazon.awssdk.services.s3.model.ChecksumType;
8+
import software.amazon.awssdk.services.s3.model.CompleteMultipartUploadResponse;
49
import software.amazon.awssdk.services.s3.model.CreateMultipartUploadRequest;
510
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
6-
import java.time.Instant;
7-
import java.util.Map;
11+
import software.amazon.awssdk.services.s3.model.PutObjectResponse;
812

913
public class ConvertSDKRequests {
1014

11-
public static CreateMultipartUploadRequest convert(PutObjectRequest request) {
15+
public static CreateMultipartUploadRequest convertRequest(PutObjectRequest request) {
1216

1317
final CreateMultipartUploadRequest.Builder output = CreateMultipartUploadRequest.builder();
1418
request
@@ -140,6 +144,77 @@ public static CreateMultipartUploadRequest convert(PutObjectRequest request) {
140144
.build();
141145
}
142146

147+
public static PutObjectResponse convertResponse(CompleteMultipartUploadResponse response) {
148+
final PutObjectResponse.Builder output = PutObjectResponse.builder();
149+
response
150+
.toBuilder()
151+
.sdkFields()
152+
.forEach(f -> {
153+
final Object value = f.getValueOrDefault(response);
154+
if (value != null) {
155+
switch (f.memberName()) {
156+
case "ETag":
157+
output.eTag((String) value);
158+
break;
159+
case "Expiration":
160+
output.expiration((String) value);
161+
break;
162+
case "ChecksumCRC32":
163+
output.checksumCRC32((String) value);
164+
break;
165+
case "ChecksumCRC32C":
166+
output.checksumCRC32C((String) value);
167+
break;
168+
case "ChecksumCRC64NVME":
169+
output.checksumCRC64NVME((String) value);
170+
break;
171+
case "ChecksumSHA1":
172+
output.checksumSHA1((String) value);
173+
break;
174+
case "ChecksumSHA256":
175+
output.checksumSHA256((String) value);
176+
break;
177+
case "ChecksumType":
178+
output.checksumType((String) value);
179+
break;
180+
case "ServerSideEncryption":
181+
output.serverSideEncryption((String) value);
182+
break;
183+
case "VersionId":
184+
output.versionId((String) value);
185+
break;
186+
case "SSEKMSKeyId":
187+
output.ssekmsKeyId((String) value);
188+
break;
189+
case "BucketKeyEnabled":
190+
output.bucketKeyEnabled((Boolean) value);
191+
break;
192+
case "RequestCharged":
193+
output.requestCharged((String) value);
194+
break;
195+
// Ignored fields: Location, Bucket, Key
196+
case "Location":
197+
case "Bucket":
198+
case "Key":
199+
// These fields exist only in CompleteMultipartUploadResponse, not in PutObjectResponse
200+
break;
201+
default:
202+
// We should NOT throw an exception for unknown fields because
203+
// once the object is stored, we expect to return a successful response.
204+
// Emit a log at info level for awareness.
205+
LogFactory.getLog(ConvertSDKRequests.class).info(f.memberName() + " returned in CompleteMultipartUploadResponse for "
206+
+ response.key() + " is an unknown field." +
207+
"The S3 Encryption Client does not recognize this option and cannot set it on the CompleteMultipartUploadResponse." +
208+
"This may be a new S3 feature." +
209+
"Please report this to the Amazon S3 Encryption Client for Java: " +
210+
"https://github.com/aws/amazon-s3-encryption-client-java/issues."
211+
);
212+
}
213+
}
214+
});
215+
return output.build();
216+
}
217+
143218
private static boolean isStringStringMap(Object value) {
144219
if (!(value instanceof Map)) {
145220
return false;

src/main/java/software/amazon/encryption/s3/internal/UploadObjectObserver.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public UploadObjectObserver init(PutObjectRequest req,
4444

4545
public String onUploadCreation(PutObjectRequest req) {
4646
CreateMultipartUploadResponse res =
47-
s3EncryptionClient.createMultipartUpload(ConvertSDKRequests.convert(req));
47+
s3EncryptionClient.createMultipartUpload(ConvertSDKRequests.convertRequest(req));
4848
return this.uploadId = res.uploadId();
4949
}
5050

src/test/java/software/amazon/encryption/s3/S3EncryptionClientMultipartUploadTest.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,16 @@
1313
import software.amazon.awssdk.core.sync.RequestBody;
1414
import software.amazon.awssdk.services.s3.S3AsyncClient;
1515
import software.amazon.awssdk.services.s3.S3Client;
16+
import software.amazon.awssdk.services.s3.model.ChecksumType;
1617
import software.amazon.awssdk.services.s3.model.CompletedPart;
1718
import software.amazon.awssdk.services.s3.model.CreateMultipartUploadResponse;
1819
import software.amazon.awssdk.services.s3.model.GetObjectResponse;
1920
import software.amazon.awssdk.services.s3.model.PutObjectResponse;
2021
import software.amazon.awssdk.services.s3.model.SdkPartType;
22+
import software.amazon.awssdk.services.s3.model.ServerSideEncryption;
23+
import software.amazon.awssdk.services.s3.model.StorageClass;
2124
import software.amazon.awssdk.services.s3.model.UploadPartRequest;
2225
import software.amazon.awssdk.services.s3.model.UploadPartResponse;
23-
import software.amazon.awssdk.services.s3.model.StorageClass;
2426
import software.amazon.awssdk.utils.IoUtils;
2527
import software.amazon.encryption.s3.utils.BoundedInputStream;
2628

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

544546
final StorageClass storageClass = StorageClass.INTELLIGENT_TIERING;
545547

546-
v3Client.putObject(builder -> builder
548+
// PutObject
549+
final PutObjectResponse putObjectResponse = v3Client.putObject(builder -> builder
547550
.bucket(BUCKET)
548551
.overrideConfiguration(withAdditionalConfiguration(encryptionContext))
549552
.storageClass(storageClass)
550553
.key(objectKey), RequestBody.fromInputStream(inputStream, fileSizeLimit));
551554

552-
// Asserts
555+
assertEquals(ChecksumType.FULL_OBJECT.toString(), putObjectResponse.checksumTypeAsString());
556+
assertEquals(ServerSideEncryption.AES256.toString(), putObjectResponse.serverSideEncryptionAsString());
557+
558+
// GetObject
553559
final ResponseInputStream<GetObjectResponse> output = v3Client.getObject(builder -> builder
554560
.bucket(BUCKET)
555561
.overrideConfiguration(S3EncryptionClient.withAdditionalConfiguration(encryptionContext))
556562
.key(objectKey));
557563

564+
// Asserts
558565
assertTrue(IOUtils.contentEquals(objectStreamForResult, output));
559566
assertEquals(storageClass, output.response().storageClass());
560567

0 commit comments

Comments
 (0)