kopia lustrzana https://github.com/gaul/s3proxy
rodzic
757ed5acbe
commit
be3f38b937
|
@ -58,6 +58,7 @@ import com.google.common.base.Optional;
|
||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
import com.google.common.base.Throwables;
|
import com.google.common.base.Throwables;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import com.google.common.collect.ImmutableMultimap;
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
import com.google.common.collect.SortedSetMultimap;
|
import com.google.common.collect.SortedSetMultimap;
|
||||||
|
@ -72,9 +73,11 @@ import com.google.common.net.HttpHeaders;
|
||||||
|
|
||||||
import org.eclipse.jetty.server.Request;
|
import org.eclipse.jetty.server.Request;
|
||||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||||
|
import org.jclouds.blobstore.BlobRequestSigner;
|
||||||
import org.jclouds.blobstore.BlobStore;
|
import org.jclouds.blobstore.BlobStore;
|
||||||
import org.jclouds.blobstore.ContainerNotFoundException;
|
import org.jclouds.blobstore.ContainerNotFoundException;
|
||||||
import org.jclouds.blobstore.KeyNotFoundException;
|
import org.jclouds.blobstore.KeyNotFoundException;
|
||||||
|
import org.jclouds.blobstore.LocalBlobRequestSigner;
|
||||||
import org.jclouds.blobstore.domain.Blob;
|
import org.jclouds.blobstore.domain.Blob;
|
||||||
import org.jclouds.blobstore.domain.BlobAccess;
|
import org.jclouds.blobstore.domain.BlobAccess;
|
||||||
import org.jclouds.blobstore.domain.BlobBuilder;
|
import org.jclouds.blobstore.domain.BlobBuilder;
|
||||||
|
@ -90,6 +93,7 @@ import org.jclouds.blobstore.options.GetOptions;
|
||||||
import org.jclouds.blobstore.options.ListContainerOptions;
|
import org.jclouds.blobstore.options.ListContainerOptions;
|
||||||
import org.jclouds.blobstore.options.PutOptions;
|
import org.jclouds.blobstore.options.PutOptions;
|
||||||
import org.jclouds.domain.Location;
|
import org.jclouds.domain.Location;
|
||||||
|
import org.jclouds.http.HttpRequest;
|
||||||
import org.jclouds.http.HttpResponse;
|
import org.jclouds.http.HttpResponse;
|
||||||
import org.jclouds.http.HttpResponseException;
|
import org.jclouds.http.HttpResponseException;
|
||||||
import org.jclouds.io.ContentMetadata;
|
import org.jclouds.io.ContentMetadata;
|
||||||
|
@ -158,6 +162,8 @@ final class S3ProxyHandler extends AbstractHandler {
|
||||||
private final XMLOutputFactory xmlOutputFactory =
|
private final XMLOutputFactory xmlOutputFactory =
|
||||||
XMLOutputFactory.newInstance();
|
XMLOutputFactory.newInstance();
|
||||||
private BlobStoreLocator blobStoreLocator;
|
private BlobStoreLocator blobStoreLocator;
|
||||||
|
// TODO: hack to allow per-request anonymous access
|
||||||
|
private final BlobStore defaultBlobStore;
|
||||||
|
|
||||||
S3ProxyHandler(final BlobStore blobStore, final String identity,
|
S3ProxyHandler(final BlobStore blobStore, final String identity,
|
||||||
final String credential, Optional<String> virtualHost) {
|
final String credential, Optional<String> virtualHost) {
|
||||||
|
@ -186,6 +192,7 @@ final class S3ProxyHandler extends AbstractHandler {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
this.virtualHost = requireNonNull(virtualHost);
|
this.virtualHost = requireNonNull(virtualHost);
|
||||||
|
this.defaultBlobStore = blobStore;
|
||||||
xmlOutputFactory.setProperty("javax.xml.stream.isRepairingNamespaces",
|
xmlOutputFactory.setProperty("javax.xml.stream.isRepairingNamespaces",
|
||||||
Boolean.FALSE);
|
Boolean.FALSE);
|
||||||
}
|
}
|
||||||
|
@ -251,6 +258,15 @@ final class S3ProxyHandler extends AbstractHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// anonymous request
|
||||||
|
if (method.equals("GET") &&
|
||||||
|
request.getHeader(HttpHeaders.AUTHORIZATION) == null &&
|
||||||
|
request.getParameter("AWSAccessKeyId") == null &&
|
||||||
|
defaultBlobStore != null) {
|
||||||
|
doHandleAnonymous(request, response, uri, defaultBlobStore);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!anonymousIdentity && !hasDateHeader && !hasXAmzDateHeader &&
|
if (!anonymousIdentity && !hasDateHeader && !hasXAmzDateHeader &&
|
||||||
request.getParameter("Expires") == null) {
|
request.getParameter("Expires") == null) {
|
||||||
throw new S3Exception(S3ErrorCode.ACCESS_DENIED,
|
throw new S3Exception(S3ErrorCode.ACCESS_DENIED,
|
||||||
|
@ -449,6 +465,69 @@ final class S3ProxyHandler extends AbstractHandler {
|
||||||
throw new S3Exception(S3ErrorCode.NOT_IMPLEMENTED);
|
throw new S3Exception(S3ErrorCode.NOT_IMPLEMENTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void doHandleAnonymous(HttpServletRequest request,
|
||||||
|
HttpServletResponse response, String uri, BlobStore blobStore)
|
||||||
|
throws IOException, S3Exception {
|
||||||
|
String method = request.getMethod();
|
||||||
|
String[] path = uri.split("/", 3);
|
||||||
|
switch (method) {
|
||||||
|
case "GET":
|
||||||
|
if (path.length <= 1) {
|
||||||
|
throw new S3Exception(S3ErrorCode.INVALID_REQUEST);
|
||||||
|
} else if (path.length == 2) {
|
||||||
|
handleContainerList(response, blobStore);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BlobRequestSigner signer = blobStore
|
||||||
|
.getContext()
|
||||||
|
.getSigner();
|
||||||
|
if (signer instanceof LocalBlobRequestSigner) {
|
||||||
|
// Local blobstores do not have an HTTP server --
|
||||||
|
// must handle these calls directly.
|
||||||
|
Blob blob = blobStore.getBlob(path[1], path[2]);
|
||||||
|
if (blob == null) {
|
||||||
|
// TODO: NO_SUCH_BUCKET
|
||||||
|
throw new S3Exception(S3ErrorCode.NO_SUCH_KEY);
|
||||||
|
}
|
||||||
|
// TODO: getBlob should return BlobAccess
|
||||||
|
BlobAccess access = blobStore.getBlobAccess(path[1],
|
||||||
|
path[2]);
|
||||||
|
if (access != BlobAccess.PUBLIC_READ) {
|
||||||
|
throw new S3Exception(S3ErrorCode.ACCESS_DENIED);
|
||||||
|
}
|
||||||
|
try (InputStream payload = blob.getPayload().openStream();
|
||||||
|
OutputStream os = response.getOutputStream()) {
|
||||||
|
ByteStreams.copy(payload, os);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
HttpRequest anonymousRequest = signer
|
||||||
|
.signGetBlob(path[1], path[2])
|
||||||
|
.toBuilder()
|
||||||
|
.headers(ImmutableMultimap.<String, String>of())
|
||||||
|
// TODO: replace parameters?
|
||||||
|
.build();
|
||||||
|
logger.debug("issuing anonymous request: {}", anonymousRequest);
|
||||||
|
HttpResponse anonymousResponse = blobStore
|
||||||
|
.getContext()
|
||||||
|
.utils()
|
||||||
|
.http()
|
||||||
|
.invoke(anonymousRequest);
|
||||||
|
try (InputStream payload =
|
||||||
|
anonymousResponse.getPayload().openStream();
|
||||||
|
OutputStream os = response.getOutputStream()) {
|
||||||
|
ByteStreams.copy(payload, os);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
logger.error("Unknown method {} with URI {}",
|
||||||
|
method, request.getRequestURI());
|
||||||
|
throw new S3Exception(S3ErrorCode.NOT_IMPLEMENTED);
|
||||||
|
}
|
||||||
|
|
||||||
private void handleGetContainerAcl(HttpServletResponse response,
|
private void handleGetContainerAcl(HttpServletResponse response,
|
||||||
BlobStore blobStore, String containerName) throws IOException {
|
BlobStore blobStore, String containerName) throws IOException {
|
||||||
ContainerAccess access = blobStore.getContainerAccess(containerName);
|
ContainerAccess access = blobStore.getContainerAccess(containerName);
|
||||||
|
|
|
@ -41,6 +41,7 @@ import org.jclouds.blobstore.BlobRequestSigner;
|
||||||
import org.jclouds.blobstore.BlobStore;
|
import org.jclouds.blobstore.BlobStore;
|
||||||
import org.jclouds.blobstore.BlobStoreContext;
|
import org.jclouds.blobstore.BlobStoreContext;
|
||||||
import org.jclouds.blobstore.domain.Blob;
|
import org.jclouds.blobstore.domain.Blob;
|
||||||
|
import org.jclouds.blobstore.domain.BlobAccess;
|
||||||
import org.jclouds.blobstore.domain.BlobMetadata;
|
import org.jclouds.blobstore.domain.BlobMetadata;
|
||||||
import org.jclouds.blobstore.domain.MultipartPart;
|
import org.jclouds.blobstore.domain.MultipartPart;
|
||||||
import org.jclouds.blobstore.domain.MultipartUpload;
|
import org.jclouds.blobstore.domain.MultipartUpload;
|
||||||
|
@ -54,7 +55,6 @@ import org.jclouds.io.ContentMetadata;
|
||||||
import org.jclouds.io.ContentMetadataBuilder;
|
import org.jclouds.io.ContentMetadataBuilder;
|
||||||
import org.jclouds.io.Payload;
|
import org.jclouds.io.Payload;
|
||||||
import org.jclouds.io.Payloads;
|
import org.jclouds.io.Payloads;
|
||||||
import org.jclouds.io.payloads.ByteSourcePayload;
|
|
||||||
import org.jclouds.rest.HttpClient;
|
import org.jclouds.rest.HttpClient;
|
||||||
import org.jclouds.s3.S3Client;
|
import org.jclouds.s3.S3Client;
|
||||||
|
|
||||||
|
@ -110,17 +110,23 @@ public final class S3ProxyTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: why does this hang for 30 seconds?
|
|
||||||
// TODO: this test requires anonymous access
|
|
||||||
@Ignore
|
|
||||||
@Test
|
@Test
|
||||||
public void testHttpClient() throws Exception {
|
public void testHttpClient() throws Exception {
|
||||||
HttpClient httpClient = context.utils().http();
|
String blobName = "blob-name";
|
||||||
// TODO: how to interpret this?
|
Blob blob = blobStore.blobBuilder(blobName)
|
||||||
URI uri = URI.create(s3Endpoint + "/" + containerName + "/blob");
|
.payload(BYTE_SOURCE)
|
||||||
Payload payload = new ByteSourcePayload(BYTE_SOURCE);
|
.contentLength(BYTE_SOURCE.size())
|
||||||
payload.getContentMetadata().setContentLength(BYTE_SOURCE.size());
|
.build();
|
||||||
httpClient.put(uri, payload);
|
blobStore.putBlob(containerName, blob);
|
||||||
|
// TODO: jclouds PutOptions should include BlobAccess
|
||||||
|
blobStore.setBlobAccess(containerName, blobName,
|
||||||
|
BlobAccess.PUBLIC_READ);
|
||||||
|
|
||||||
|
HttpClient httpClient = s3Context.utils().http();
|
||||||
|
URI uri = new URI(s3Endpoint.getScheme(), s3Endpoint.getUserInfo(),
|
||||||
|
s3Endpoint.getHost(), s3Proxy.getPort(),
|
||||||
|
"/" + containerName + "/" + blobName,
|
||||||
|
/*query=*/ null, /*fragment=*/ null);
|
||||||
try (InputStream actual = httpClient.get(uri);
|
try (InputStream actual = httpClient.get(uri);
|
||||||
InputStream expected = BYTE_SOURCE.openStream()) {
|
InputStream expected = BYTE_SOURCE.openStream()) {
|
||||||
assertThat(actual).hasContentEqualTo(expected);
|
assertThat(actual).hasContentEqualTo(expected);
|
||||||
|
|
Ładowanie…
Reference in New Issue