Add partial support for list objects v2

Not supporting fetch-owner until jclouds adds support for this.
Several applications like AWS CLI now require this RPC.  Fixes #168.
pull/293/head
Andrew Gaul 2019-02-09 15:06:34 -08:00
rodzic 4698a2a913
commit 3fed3941f1
3 zmienionych plików z 97 dodań i 9 usunięć

Wyświetl plik

@ -105,7 +105,6 @@ S3Proxy has broad compatibility with the S3 API, however, it does not support:
* bucket logging
* [CORS bucket operations](https://docs.aws.amazon.com/AmazonS3/latest/dev/cors.html#how-do-i-enable-cors) like getting or setting the CORS configuration for a bucket. S3Proxy only supports a static configuration (see below).
* hosting static websites
* list objects v2, see [#168](https://github.com/gaul/s3proxy/issues/168)
* object server-side encryption
* object tagging
* object versioning, see [#74](https://github.com/gaul/s3proxy/issues/74)

Wyświetl plik

@ -143,7 +143,6 @@ public class S3ProxyHandler {
"cors",
"inventory",
"lifecycle",
"list-type",
"logging",
"metrics",
"notification",
@ -1316,7 +1315,27 @@ public class S3ProxyHandler {
if (prefix != null && !prefix.isEmpty()) {
options.prefix(prefix);
}
String marker = request.getParameter("marker");
boolean isListV2 = false;
String marker;
String listType = request.getParameter("list-type");
String continuationToken = request.getParameter("continuation-token");
String startAfter = request.getParameter("start-after");
if (listType == null) {
marker = request.getParameter("marker");
} else if (listType.equals("2")) {
isListV2 = true;
if (continuationToken != null && startAfter != null) {
throw new S3Exception(S3ErrorCode.INVALID_ARGUMENT);
}
if (continuationToken != null) {
marker = continuationToken;
} else {
marker = startAfter;
}
} else {
throw new S3Exception(S3ErrorCode.NOT_IMPLEMENTED);
}
if (marker != null) {
if (Quirks.OPAQUE_MARKERS.contains(blobStoreType)) {
String realMarker = lastKeyToMarker.getIfPresent(
@ -1327,6 +1346,12 @@ public class S3ProxyHandler {
}
options.afterMarker(marker);
}
String fetchOwner = request.getParameter("fetch-owner");
if (fetchOwner != null && !fetchOwner.equals("false")) {
throw new S3Exception(S3ErrorCode.NOT_IMPLEMENTED);
}
int maxKeys = 1000;
String maxKeysString = request.getParameter("max-keys");
if (maxKeysString != null) {
@ -1372,11 +1397,26 @@ public class S3ProxyHandler {
writeSimpleElement(xml, "MaxKeys", String.valueOf(maxKeys));
if (marker == null) {
xml.writeEmptyElement("Marker");
if (!isListV2) {
if (marker == null) {
xml.writeEmptyElement("Marker");
} else {
writeSimpleElement(xml, "Marker", encodeBlob(
encodingType, marker));
}
} else {
writeSimpleElement(xml, "Marker", encodeBlob(
encodingType, marker));
if (continuationToken == null) {
xml.writeEmptyElement("ContinuationToken");
} else {
writeSimpleElement(xml, "ContinuationToken", encodeBlob(
encodingType, continuationToken));
}
if (startAfter == null) {
xml.writeEmptyElement("StartAfter");
} else {
writeSimpleElement(xml, "StartAfter", encodeBlob(
encodingType, startAfter));
}
}
if (delimiter != null) {
@ -1391,8 +1431,9 @@ public class S3ProxyHandler {
String nextMarker = set.getNextMarker();
if (nextMarker != null) {
writeSimpleElement(xml, "IsTruncated", "true");
writeSimpleElement(xml, "NextMarker", encodeBlob(
encodingType, nextMarker));
writeSimpleElement(xml,
isListV2 ? "NextContinuationToken" : "NextMarker",
encodeBlob(encodingType, nextMarker));
if (Quirks.OPAQUE_MARKERS.contains(blobStoreType)) {
lastKeyToMarker.put(Maps.immutableEntry(containerName,
Iterables.getLast(set).getName()), nextMarker);

Wyświetl plik

@ -70,6 +70,8 @@ import com.amazonaws.services.s3.model.InitiateMultipartUploadRequest;
import com.amazonaws.services.s3.model.InitiateMultipartUploadResult;
import com.amazonaws.services.s3.model.ListMultipartUploadsRequest;
import com.amazonaws.services.s3.model.ListObjectsRequest;
import com.amazonaws.services.s3.model.ListObjectsV2Request;
import com.amazonaws.services.s3.model.ListObjectsV2Result;
import com.amazonaws.services.s3.model.ListPartsRequest;
import com.amazonaws.services.s3.model.MultipartUploadListing;
import com.amazonaws.services.s3.model.ObjectListing;
@ -904,6 +906,52 @@ public final class AwsSdkTest {
.isEqualTo("blob2");
}
@Test
public void testBlobListV2() throws Exception {
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(BYTE_SOURCE.size());
for (int i = 1; i < 5; ++i) {
client.putObject(containerName, String.valueOf(i),
BYTE_SOURCE.openStream(), metadata);
}
ListObjectsV2Result result = client.listObjectsV2(
new ListObjectsV2Request()
.withBucketName(containerName)
.withMaxKeys(1)
.withStartAfter("1"));
assertThat(result.getContinuationToken()).isEmpty();
assertThat(result.getStartAfter()).isEqualTo("1");
assertThat(result.getNextContinuationToken()).isEqualTo("2");
assertThat(result.isTruncated()).isTrue();
assertThat(result.getObjectSummaries()).hasSize(1);
assertThat(result.getObjectSummaries().get(0).getKey()).isEqualTo("2");
result = client.listObjectsV2(
new ListObjectsV2Request()
.withBucketName(containerName)
.withMaxKeys(1)
.withContinuationToken(result.getNextContinuationToken()));
assertThat(result.getContinuationToken()).isEqualTo("2");
assertThat(result.getStartAfter()).isEmpty();
assertThat(result.getNextContinuationToken()).isEqualTo("3");
assertThat(result.isTruncated()).isTrue();
assertThat(result.getObjectSummaries()).hasSize(1);
assertThat(result.getObjectSummaries().get(0).getKey()).isEqualTo("3");
result = client.listObjectsV2(
new ListObjectsV2Request()
.withBucketName(containerName)
.withMaxKeys(1)
.withContinuationToken(result.getNextContinuationToken()));
assertThat(result.getContinuationToken()).isEqualTo("3");
assertThat(result.getStartAfter()).isEmpty();
assertThat(result.getNextContinuationToken()).isNull();
assertThat(result.isTruncated()).isFalse();
assertThat(result.getObjectSummaries()).hasSize(1);
assertThat(result.getObjectSummaries().get(0).getKey()).isEqualTo("4");
}
@Test
public void testBlobMetadata() throws Exception {
String blobName = "blob";