kopia lustrzana https://github.com/gaul/s3proxy
215 wiersze
7.3 KiB
Java
215 wiersze
7.3 KiB
Java
/*
|
|
* Copyright 2014-2016 Andrew Gaul <andrew@gaul.org>
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package org.gaul.s3proxy;
|
|
|
|
import static java.util.Objects.requireNonNull;
|
|
|
|
import static com.google.common.base.Preconditions.checkArgument;
|
|
|
|
import java.net.URI;
|
|
|
|
import com.google.common.base.Optional;
|
|
import com.google.common.base.Strings;
|
|
|
|
import org.eclipse.jetty.server.HttpConnectionFactory;
|
|
import org.eclipse.jetty.server.Server;
|
|
import org.eclipse.jetty.server.ServerConnector;
|
|
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
|
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
|
import org.jclouds.blobstore.BlobStore;
|
|
|
|
/**
|
|
* S3Proxy translates S3 HTTP operations into jclouds provider-agnostic
|
|
* operations. This allows applications using the S3 API to interface with any
|
|
* provider that jclouds supports, e.g., EMC Atmos, Microsoft Azure,
|
|
* OpenStack Swift.
|
|
*/
|
|
public final class S3Proxy {
|
|
private final Server server;
|
|
private final S3ProxyHandler handler;
|
|
private final boolean listenHTTP;
|
|
private final boolean listenHTTPS;
|
|
|
|
static {
|
|
// Prevent Jetty from rewriting headers:
|
|
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=414449
|
|
System.setProperty("org.eclipse.jetty.http.HttpParser.STRICT", "true");
|
|
}
|
|
|
|
S3Proxy(Builder builder) {
|
|
checkArgument(builder.endpoint != null ||
|
|
builder.secureEndpoint != null,
|
|
"Must provide endpoint or secure-endpoint");
|
|
// TODO: allow service paths?
|
|
if (builder.endpoint != null) {
|
|
checkArgument(builder.endpoint.getPath().isEmpty(),
|
|
"endpoint path must be empty, was: %s",
|
|
builder.endpoint.getPath());
|
|
}
|
|
if (builder.secureEndpoint != null) {
|
|
checkArgument(builder.secureEndpoint.getPath().isEmpty(),
|
|
"secure-endpoint path must be empty, was: %s",
|
|
builder.secureEndpoint.getPath());
|
|
requireNonNull(builder.keyStorePath,
|
|
"Must provide keyStorePath with HTTPS endpoint");
|
|
requireNonNull(builder.keyStorePassword,
|
|
"Must provide keyStorePassword with HTTPS endpoint");
|
|
}
|
|
checkArgument(Strings.isNullOrEmpty(builder.identity) ^
|
|
!Strings.isNullOrEmpty(builder.credential),
|
|
"Must provide both identity and credential");
|
|
|
|
server = new Server();
|
|
((QueuedThreadPool) server.getThreadPool()).setName("S3Proxy");
|
|
HttpConnectionFactory httpConnectionFactory =
|
|
new HttpConnectionFactory();
|
|
ServerConnector connector;
|
|
if (builder.endpoint != null) {
|
|
connector = new ServerConnector(server, httpConnectionFactory);
|
|
connector.setHost(builder.endpoint.getHost());
|
|
connector.setPort(builder.endpoint.getPort());
|
|
server.addConnector(connector);
|
|
listenHTTP = true;
|
|
} else {
|
|
listenHTTP = false;
|
|
}
|
|
|
|
if (builder.secureEndpoint != null) {
|
|
SslContextFactory sslContextFactory = new SslContextFactory();
|
|
sslContextFactory.setKeyStorePath(builder.keyStorePath);
|
|
sslContextFactory.setKeyStorePassword(builder.keyStorePassword);
|
|
connector = new ServerConnector(server, sslContextFactory,
|
|
httpConnectionFactory);
|
|
connector.setHost(builder.secureEndpoint.getHost());
|
|
connector.setPort(builder.secureEndpoint.getPort());
|
|
server.addConnector(connector);
|
|
listenHTTPS = true;
|
|
} else {
|
|
listenHTTPS = false;
|
|
}
|
|
handler = new S3ProxyHandler(builder.blobStore, builder.identity,
|
|
builder.credential, Optional.fromNullable(builder.virtualHost),
|
|
builder.v4MaxNonChunkedRequestSize);
|
|
server.setHandler(handler);
|
|
}
|
|
|
|
public static final class Builder {
|
|
private BlobStore blobStore;
|
|
private URI endpoint;
|
|
private URI secureEndpoint;
|
|
private String identity;
|
|
private String credential;
|
|
private String keyStorePath;
|
|
private String keyStorePassword;
|
|
private String virtualHost;
|
|
private long v4MaxNonChunkedRequestSize = 32 * 1024 * 1024;
|
|
|
|
Builder() {
|
|
}
|
|
|
|
public S3Proxy build() {
|
|
return new S3Proxy(this);
|
|
}
|
|
|
|
public Builder blobStore(BlobStore blobStore) {
|
|
this.blobStore = requireNonNull(blobStore);
|
|
return this;
|
|
}
|
|
|
|
public Builder endpoint(URI endpoint) {
|
|
this.endpoint = requireNonNull(endpoint);
|
|
return this;
|
|
}
|
|
|
|
public Builder secureEndpoint(URI secureEndpoint) {
|
|
this.secureEndpoint = requireNonNull(secureEndpoint);
|
|
return this;
|
|
}
|
|
|
|
public Builder awsAuthentication(String identity, String credential) {
|
|
this.identity = requireNonNull(identity);
|
|
this.credential = requireNonNull(credential);
|
|
return this;
|
|
}
|
|
|
|
public Builder keyStore(String keyStorePath, String keyStorePassword) {
|
|
this.keyStorePath = requireNonNull(keyStorePath);
|
|
this.keyStorePassword = requireNonNull(keyStorePassword);
|
|
return this;
|
|
}
|
|
|
|
public Builder virtualHost(String virtualHost) {
|
|
this.virtualHost = requireNonNull(virtualHost);
|
|
return this;
|
|
}
|
|
|
|
public Builder v4MaxNonChunkedRequestSize(
|
|
long v4MaxNonChunkedRequestSize) {
|
|
if (v4MaxNonChunkedRequestSize <= 0) {
|
|
throw new IllegalArgumentException(
|
|
"must be greater than zero, was: " +
|
|
v4MaxNonChunkedRequestSize);
|
|
}
|
|
this.v4MaxNonChunkedRequestSize = v4MaxNonChunkedRequestSize;
|
|
return this;
|
|
}
|
|
}
|
|
|
|
public static Builder builder() {
|
|
return new Builder();
|
|
}
|
|
|
|
public void start() throws Exception {
|
|
server.start();
|
|
}
|
|
|
|
public void stop() throws Exception {
|
|
server.stop();
|
|
}
|
|
|
|
public int getPort() {
|
|
if (listenHTTP) {
|
|
return ((ServerConnector) server.getConnectors()[0]).getLocalPort();
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
public int getSecurePort() {
|
|
if (listenHTTPS) {
|
|
ServerConnector connector;
|
|
if (listenHTTP) {
|
|
connector = (ServerConnector) server.getConnectors()[1];
|
|
} else {
|
|
connector = (ServerConnector) server.getConnectors()[0];
|
|
}
|
|
return connector.getLocalPort();
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
public String getState() {
|
|
return server.getState();
|
|
}
|
|
|
|
public void setBlobStoreLocator(BlobStoreLocator lookup) {
|
|
handler.setBlobStoreLocator(lookup);
|
|
}
|
|
|
|
}
|