kopia lustrzana https://github.com/gaul/s3proxy
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
rodzic
4698a2a913
commit
3fed3941f1
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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";
|
||||
|
|
Ładowanie…
Reference in New Issue