Skip to content

Commit

Permalink
support user-defined metadata in CreateMultipartUpload operation.
Browse files Browse the repository at this point in the history
  • Loading branch information
Robothy committed Aug 7, 2024
1 parent 11c579e commit 89b3780
Show file tree
Hide file tree
Showing 8 changed files with 44 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.robothy.s3.core.converters.deserializer.UploadPartMetadataMapConverter;

import java.util.Map;
import java.util.NavigableMap;
import java.util.Optional;
import java.util.concurrent.ConcurrentSkipListMap;
Expand All @@ -22,6 +24,8 @@ public class UploadMetadata {

private String[][] tagging;

private Map<String, String> userMetadata;

@JsonDeserialize(converter = UploadPartMetadataMapConverter.class)
@Builder.Default
private NavigableMap<Integer, UploadPartMetadata> parts = new ConcurrentSkipListMap<>();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.robothy.s3.core.model.request;

import java.util.Map;
import java.util.Optional;
import lombok.Builder;
import lombok.Getter;
Expand All @@ -15,4 +16,6 @@ public class CreateMultipartUploadOptions {
public Optional<String[][]> getTagging() {
return Optional.ofNullable(tagging);
}

private Map<String, String> userMetadata;
}
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ default CompleteMultipartUploadAns completeMultipartUpload(String bucket, String
.content(in)
.contentType(uploadMetadata.getContentType())
.tagging(uploadMetadata.getTagging().orElse(null))
.userMetadata(uploadMetadata.getUserMetadata())
.build();

putObjectAns = putObject(bucket, key, putObjectOptions);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ default String createMultipartUpload(String bucket, String key, CreateMultipartU
.contentType(options.getContentType())
.createDate(System.currentTimeMillis())
.tagging(options.getTagging().orElse(null))
.userMetadata(options.getUserMetadata())
.build());
return uploadId;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
import java.io.IOException;
import java.net.URL;
import java.util.List;
import java.util.Map;

import org.junit.jupiter.api.Test;
import software.amazon.awssdk.core.ResponseInputStream;
import software.amazon.awssdk.core.sync.RequestBody;
Expand Down Expand Up @@ -56,6 +58,8 @@ void multipartUpload(AmazonS3 s3) throws IOException {
s3.createBucket(bucket);
ObjectMetadata objectMetadata1 = new ObjectMetadata();
objectMetadata1.setContentType("plain/text");
objectMetadata1.addUserMetadata("x-filename", "a.txt");
objectMetadata1.addUserMetadata("x-other", "other-value");
InitiateMultipartUploadResult initResult =
s3.initiateMultipartUpload(new InitiateMultipartUploadRequest(bucket, key1, objectMetadata1));
assertNotNull(initResult.getUploadId());
Expand Down Expand Up @@ -100,6 +104,10 @@ void multipartUpload(AmazonS3 s3) throws IOException {
S3Object object = s3.getObject(bucket, key1);
assertEquals("HelloWorld", new String(object.getObjectContent().readAllBytes()));
assertEquals("plain/text", object.getObjectMetadata().getContentType());
Map<String, String> userMetadata = object.getObjectMetadata().getUserMetadata();
assertEquals(2, userMetadata.size());
assertEquals("a.txt", userMetadata.get("x-filename"));
assertEquals("x-other", userMetadata.get("other-value"));

assertThrows(AmazonS3Exception.class, () -> {
s3.copyPart(new CopyPartRequest().withUploadId(initResult.getUploadId())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public void handle(HttpRequest request, HttpResponse response) throws Exception
String contentType = request.header("content-type").orElse("octet/stream");
String uploadId = uploadService.createMultipartUpload(bucket, key, CreateMultipartUploadOptions.builder()
.tagging(RequestUtils.extractTagging(request).orElse(null))
.userMetadata(RequestUtils.extractUserMetadata(request))
.contentType(contentType).build());
InitiateMultipartUploadResult result = InitiateMultipartUploadResult.builder()
.bucket(bucket)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public void handle(HttpRequest request, HttpResponse response) throws Exception
.size(decodedBody.getDecodedContentLength())
.content(decodedBody.getDecodedBody())
.tagging(RequestUtils.extractTagging(request).orElse(null))
.userMetadata(extractUserMetadata(request))
.userMetadata(RequestUtils.extractUserMetadata(request))
.build();

PutObjectAns ans = objectService.putObject(bucketName, key, options);
Expand All @@ -58,16 +58,6 @@ public void handle(HttpRequest request, HttpResponse response) throws Exception
ResponseUtils.addAmzRequestId(response);
}

Map<String, String> extractUserMetadata(HttpRequest request) {
Map<String, String> userMetadata = new HashMap<>();
request.getHeaders()
.forEach((k, v) -> {
if (k.toString().startsWith(AmzHeaderNames.X_AMZ_META_PREFIX)) {
String metaName = RequestAssertions.assertUserMetadataHeaderIsValid(k.toString());
userMetadata.put(metaName, v);
}
});
return userMetadata;
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@

import com.robothy.netty.http.HttpRequest;
import com.robothy.s3.core.exception.LocalS3InvalidArgumentException;
import com.robothy.s3.rest.assertions.RequestAssertions;
import com.robothy.s3.rest.constants.AmzHeaderNames;
import com.robothy.s3.rest.constants.AmzHeaderValues;
import com.robothy.s3.rest.model.request.DecodedAmzRequestBody;
import io.netty.buffer.ByteBufInputStream;
import io.netty.handler.codec.http.HttpHeaderNames;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import org.apache.commons.lang3.StringUtils;

Expand Down Expand Up @@ -86,4 +89,25 @@ public static Optional<String[][]> extractTagging(HttpRequest request) {
return Optional.of(tagSet);
}


/**
* Extract user metadata from headers. User metadata in headers that start with {@linkplain AmzHeaderNames#X_AMZ_META_PREFIX}.
*
* <p><a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingMetadata.html#UserMetadata">User-defined object metadata</a>
*
* @param request HTTP request
* @return fetched user metadata.
*/
public static Map<String, String> extractUserMetadata(HttpRequest request) {
Map<String, String> userMetadata = new HashMap<>();
request.getHeaders()
.forEach((k, v) -> {
if (k.toString().startsWith(AmzHeaderNames.X_AMZ_META_PREFIX)) {
String metaName = RequestAssertions.assertUserMetadataHeaderIsValid(k.toString());
userMetadata.put(metaName, v);
}
});
return userMetadata;
}

}

0 comments on commit 89b3780

Please sign in to comment.