20
20
import java .util .HashSet ;
21
21
import java .util .List ;
22
22
import java .util .Map ;
23
+ import java .util .Objects ;
23
24
import java .util .Set ;
24
25
import software .amazon .awssdk .annotations .SdkInternalApi ;
25
26
import software .amazon .awssdk .core .SdkField ;
26
27
import software .amazon .awssdk .core .SdkPojo ;
28
+ import software .amazon .awssdk .core .exception .SdkClientException ;
27
29
import software .amazon .awssdk .services .s3 .model .AbortMultipartUploadRequest ;
28
30
import software .amazon .awssdk .services .s3 .model .ChecksumType ;
29
31
import software .amazon .awssdk .services .s3 .model .CompleteMultipartUploadRequest ;
@@ -53,12 +55,104 @@ public final class SdkPojoConversionUtils {
53
55
new HashSet <>(Arrays .asList ("ChecksumSHA1" , "ChecksumSHA256" , "ContentMD5" , "ChecksumCRC32C" , "ChecksumCRC32" ,
54
56
"ChecksumCRC64NVME" , "ContentLength" ));
55
57
58
+ private static final Set <String > PUT_OBJECT_TO_UPLOAD_PART_ALLOWED_FIELDS = new HashSet <>(Arrays .asList (
59
+ "ACL" ,
60
+ "Bucket" ,
61
+ "CacheControl" ,
62
+ "ContentDisposition" ,
63
+ "ContentEncoding" ,
64
+ "ContentLanguage" ,
65
+ "ContentLength" ,
66
+ "ContentMD5" ,
67
+ "ContentType" ,
68
+ "ChecksumAlgorithm" ,
69
+ "ChecksumCRC32" ,
70
+ "ChecksumCRC32C" ,
71
+ "ChecksumCRC64NVME" ,
72
+ "ChecksumSHA1" ,
73
+ "ChecksumSHA256" ,
74
+ "Expires" ,
75
+ "IfMatch" ,
76
+ "IfNoneMatch" ,
77
+ "GrantFullControl" ,
78
+ "GrantRead" ,
79
+ "GrantReadACP" ,
80
+ "GrantWriteACP" ,
81
+ "Key" ,
82
+ "WriteOffsetBytes" ,
83
+ "Metadata" ,
84
+ "ServerSideEncryption" ,
85
+ "StorageClass" ,
86
+ "WebsiteRedirectLocation" ,
87
+ "SSECustomerAlgorithm" ,
88
+ "SSECustomerKey" ,
89
+ "SSECustomerKeyMD5" ,
90
+ "SSEKMSKeyId" ,
91
+ "SSEKMSEncryptionContext" ,
92
+ "BucketKeyEnabled" ,
93
+ "RequestPayer" ,
94
+ "Tagging" ,
95
+ "ObjectLockMode" ,
96
+ "ObjectLockRetainUntilDate" ,
97
+ "ObjectLockLegalHoldStatus" ,
98
+ "ExpectedBucketOwner"
99
+ ));
100
+
101
+ private static final Set <String > COPY_OBJECT_TO_COPY_OBJECT_ALLOWED_FIELDS = new HashSet <>(Arrays .asList (
102
+ "ACL" ,
103
+ "CacheControl" ,
104
+ "ChecksumAlgorithm" ,
105
+ "ContentDisposition" ,
106
+ "ContentEncoding" ,
107
+ "ContentLanguage" ,
108
+ "ContentType" ,
109
+ "CopySource" ,
110
+ "CopySourceIfMatch" ,
111
+ "CopySourceIfModifiedSince" ,
112
+ "CopySourceIfNoneMatch" ,
113
+ "CopySourceIfUnmodifiedSince" ,
114
+ "CopySourceSSECustomerAlgorithm" ,
115
+ "CopySourceSSECustomerKey" ,
116
+ "CopySourceSSECustomerKeyMD5" ,
117
+ "DestinationBucket" ,
118
+ "DestinationKey" ,
119
+ "Expires" ,
120
+ "GrantFullControl" ,
121
+ "GrantRead" ,
122
+ "GrantReadACP" ,
123
+ "GrantWriteACP" ,
124
+ "Metadata" ,
125
+ "MetadataDirective" ,
126
+ "TaggingDirective" ,
127
+ "ServerSideEncryption" ,
128
+ "SourceBucket" ,
129
+ "SourceKey" ,
130
+ "SourceVersionId" ,
131
+ "StorageClass" ,
132
+ "WebsiteRedirectLocation" ,
133
+ "SSECustomerAlgorithm" ,
134
+ "SSECustomerKey" ,
135
+ "SSECustomerKeyMD5" ,
136
+ "SSEKMSKeyId" ,
137
+ "SSEKMSEncryptionContext" ,
138
+ "BucketKeyEnabled" ,
139
+ "RequestPayer" ,
140
+ "Tagging" ,
141
+ "ObjectLockMode" ,
142
+ "ObjectLockRetainUntilDate" ,
143
+ "ObjectLockLegalHoldStatus" ,
144
+ "ExpectedBucketOwner" ,
145
+ "ExpectedSourceBucketOwner"
146
+ ));
147
+
148
+
56
149
private SdkPojoConversionUtils () {
57
150
}
58
151
59
152
public static UploadPartRequest toUploadPartRequest (PutObjectRequest putObjectRequest , int partNumber , String uploadId ) {
60
153
61
154
UploadPartRequest .Builder builder = UploadPartRequest .builder ();
155
+ validateRequestFields (putObjectRequest , builder .build (), PUT_OBJECT_TO_UPLOAD_PART_ALLOWED_FIELDS );
62
156
setSdkFields (builder , putObjectRequest , PUT_OBJECT_REQUEST_TO_UPLOAD_PART_FIELDS_TO_IGNORE );
63
157
return builder .uploadId (uploadId ).partNumber (partNumber ).build ();
64
158
}
@@ -67,6 +161,7 @@ public static CompleteMultipartUploadRequest toCompleteMultipartUploadRequest(Pu
67
161
String uploadId , CompletedPart [] parts ,
68
162
long contentLength ) {
69
163
CompleteMultipartUploadRequest .Builder builder = CompleteMultipartUploadRequest .builder ();
164
+ validateRequestFields (putObjectRequest , builder .build (), PUT_OBJECT_TO_UPLOAD_PART_ALLOWED_FIELDS );
70
165
setSdkFields (builder , putObjectRequest );
71
166
72
167
builder .mpuObjectSize (contentLength );
@@ -81,6 +176,7 @@ public static CompleteMultipartUploadRequest toCompleteMultipartUploadRequest(Pu
81
176
public static CreateMultipartUploadRequest toCreateMultipartUploadRequest (PutObjectRequest putObjectRequest ) {
82
177
83
178
CreateMultipartUploadRequest .Builder builder = CreateMultipartUploadRequest .builder ();
179
+ validateRequestFields (putObjectRequest , builder .build (), PUT_OBJECT_TO_UPLOAD_PART_ALLOWED_FIELDS );
84
180
setSdkFields (builder , putObjectRequest );
85
181
86
182
if (S3ChecksumUtils .checksumValueSpecified (putObjectRequest )) {
@@ -130,29 +226,14 @@ public static CompletedPart toCompletedPart(Part part) {
130
226
131
227
public static ListPartsRequest toListPartsRequest (String uploadId , PutObjectRequest putObjectRequest ) {
132
228
ListPartsRequest .Builder builder = ListPartsRequest .builder ();
229
+ validateRequestFields (putObjectRequest , builder .build (), PUT_OBJECT_TO_UPLOAD_PART_ALLOWED_FIELDS );
133
230
setSdkFields (builder , putObjectRequest );
134
231
return builder .uploadId (uploadId ).build ();
135
232
}
136
233
137
- private static void setSdkFields (SdkPojo targetBuilder , SdkPojo sourceObject ) {
138
- setSdkFields (targetBuilder , sourceObject , new HashSet <>());
139
- }
140
-
141
- private static void setSdkFields (SdkPojo targetBuilder , SdkPojo sourceObject , Set <String > fieldsToIgnore ) {
142
- Map <String , Object > sourceFields = retrieveSdkFields (sourceObject , sourceObject .sdkFields ());
143
- List <SdkField <?>> targetSdkFields = targetBuilder .sdkFields ();
144
-
145
- for (SdkField <?> field : targetSdkFields ) {
146
- if (fieldsToIgnore .contains (field .memberName ())) {
147
- continue ;
148
- }
149
- field .set (targetBuilder , sourceFields .getOrDefault (field .memberName (), null ));
150
- }
151
- }
152
-
153
234
public static CreateMultipartUploadRequest toCreateMultipartUploadRequest (CopyObjectRequest copyObjectRequest ) {
154
235
CreateMultipartUploadRequest .Builder builder = CreateMultipartUploadRequest .builder ();
155
-
236
+ validateRequestFields ( copyObjectRequest , builder . build (), COPY_OBJECT_TO_COPY_OBJECT_ALLOWED_FIELDS );
156
237
setSdkFields (builder , copyObjectRequest );
157
238
builder .bucket (copyObjectRequest .destinationBucket ());
158
239
builder .key (copyObjectRequest .destinationKey ());
@@ -180,6 +261,7 @@ private static CopyObjectResult toCopyObjectResult(CompleteMultipartUploadRespon
180
261
181
262
public static AbortMultipartUploadRequest .Builder toAbortMultipartUploadRequest (CopyObjectRequest copyObjectRequest ) {
182
263
AbortMultipartUploadRequest .Builder builder = AbortMultipartUploadRequest .builder ();
264
+ validateRequestFields (copyObjectRequest , builder .build (), COPY_OBJECT_TO_COPY_OBJECT_ALLOWED_FIELDS );
183
265
setSdkFields (builder , copyObjectRequest );
184
266
builder .bucket (copyObjectRequest .destinationBucket ());
185
267
builder .key (copyObjectRequest .destinationKey ());
@@ -188,6 +270,7 @@ public static AbortMultipartUploadRequest.Builder toAbortMultipartUploadRequest(
188
270
189
271
public static AbortMultipartUploadRequest .Builder toAbortMultipartUploadRequest (PutObjectRequest putObjectRequest ) {
190
272
AbortMultipartUploadRequest .Builder builder = AbortMultipartUploadRequest .builder ();
273
+ validateRequestFields (putObjectRequest , builder .build (), PUT_OBJECT_TO_UPLOAD_PART_ALLOWED_FIELDS );
191
274
setSdkFields (builder , putObjectRequest );
192
275
return builder ;
193
276
}
@@ -225,4 +308,47 @@ private static Map<String, Object> retrieveSdkFields(SdkPojo sourceObject, List<
225
308
field .getValueOrDefault (sourceObject )),
226
309
Map ::putAll );
227
310
}
311
+
312
+ private static void setSdkFields (SdkPojo targetBuilder , SdkPojo sourceObject ) {
313
+ setSdkFields (targetBuilder , sourceObject , new HashSet <>());
314
+ }
315
+
316
+ private static void setSdkFields (SdkPojo targetBuilder , SdkPojo sourceObject , Set <String > fieldsToIgnore ) {
317
+ Map <String , Object > sourceFields = retrieveSdkFields (sourceObject , sourceObject .sdkFields ());
318
+ List <SdkField <?>> targetSdkFields = targetBuilder .sdkFields ();
319
+
320
+ for (SdkField <?> field : targetSdkFields ) {
321
+ if (fieldsToIgnore .contains (field .memberName ())) {
322
+ continue ;
323
+ }
324
+ field .set (targetBuilder , sourceFields .getOrDefault (field .memberName (), null ));
325
+ }
326
+ }
327
+
328
+ private static void validateRequestFields (SdkPojo sourceObject , SdkPojo targetObject , Set <String > allowedFields ) {
329
+ Set <String > invalidFields = new HashSet <>();
330
+
331
+ for (SdkField <?> sourceField : sourceObject .sdkFields ()) {
332
+ String fieldName = sourceField .memberName ();
333
+ Object sourceValue = sourceField .getValueOrDefault (sourceObject );
334
+
335
+ if (!allowedFields .contains (fieldName )) {
336
+ SdkField <?> targetField = targetObject .sdkFields ()
337
+ .stream ()
338
+ .filter (field -> field .memberName ().equals (fieldName ))
339
+ .findFirst ()
340
+ .orElse (null );
341
+ if (targetField != null && !Objects .equals (sourceValue , targetField .getValueOrDefault (targetObject ))) {
342
+ invalidFields .add (fieldName );
343
+ }
344
+ }
345
+ }
346
+
347
+ if (!invalidFields .isEmpty ()) {
348
+ throw SdkClientException .create (
349
+ String .format ("The following fields are not allowed: %s" ,
350
+ String .join (", " , invalidFields ))
351
+ );
352
+ }
353
+ }
228
354
}
0 commit comments