mirror of
https://github.com/gitbucket/gitbucket.git
synced 2025-10-30 18:15:59 +01:00
298 lines
12 KiB
Java
298 lines
12 KiB
Java
import org.eclipse.jetty.http.HttpVersion;
|
|
import org.eclipse.jetty.server.Handler;
|
|
import org.eclipse.jetty.server.HttpConfiguration;
|
|
import org.eclipse.jetty.server.HttpConnectionFactory;
|
|
import org.eclipse.jetty.server.SecureRequestCustomizer;
|
|
import org.eclipse.jetty.server.Server;
|
|
import org.eclipse.jetty.server.ServerConnector;
|
|
import org.eclipse.jetty.server.SslConnectionFactory;
|
|
import org.eclipse.jetty.server.handler.HandlerList;
|
|
import org.eclipse.jetty.server.handler.SecuredRedirectHandler;
|
|
import org.eclipse.jetty.server.handler.StatisticsHandler;
|
|
import org.eclipse.jetty.server.session.DefaultSessionCache;
|
|
import org.eclipse.jetty.server.session.FileSessionDataStore;
|
|
import org.eclipse.jetty.server.session.SessionCache;
|
|
import org.eclipse.jetty.server.session.SessionHandler;
|
|
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
|
import org.eclipse.jetty.webapp.WebAppContext;
|
|
|
|
import java.io.File;
|
|
import java.net.InetAddress;
|
|
import java.net.URL;
|
|
import java.security.ProtectionDomain;
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
import java.util.Set;
|
|
import java.util.function.Function;
|
|
import java.util.stream.Stream;
|
|
|
|
import static java.util.function.Function.identity;
|
|
import static java.util.stream.Collectors.toSet;
|
|
|
|
public class JettyLauncher {
|
|
|
|
private interface Defaults {
|
|
|
|
String CONNECTORS = "http";
|
|
String HOST = "0.0.0.0";
|
|
|
|
int HTTP_PORT = 8080;
|
|
int HTTPS_PORT = 8443;
|
|
|
|
boolean REDIRECT_HTTPS = false;
|
|
}
|
|
|
|
private interface Connectors {
|
|
|
|
String HTTP = "http";
|
|
String HTTPS = "https";
|
|
}
|
|
|
|
public static void main(String[] args) throws Exception {
|
|
System.setProperty("java.awt.headless", "true");
|
|
|
|
String connectors = getEnvironmentVariable("gitbucket.connectors");
|
|
String host = getEnvironmentVariable("gitbucket.host");
|
|
String port = getEnvironmentVariable("gitbucket.port");
|
|
String securePort = getEnvironmentVariable("gitbucket.securePort");
|
|
String keyStorePath = getEnvironmentVariable("gitbucket.keyStorePath");
|
|
String keyStorePassword = getEnvironmentVariable("gitbucket.keyStorePassword");
|
|
String keyManagerPassword = getEnvironmentVariable("gitbucket.keyManagerPassword");
|
|
String redirectHttps = getEnvironmentVariable("gitbucket.redirectHttps");
|
|
String contextPath = getEnvironmentVariable("gitbucket.prefix");
|
|
String tmpDirPath = getEnvironmentVariable("gitbucket.tempDir");
|
|
String jettyIdleTimeout = getEnvironmentVariable("gitbucket.jettyIdleTimeout");
|
|
boolean saveSessions = false;
|
|
|
|
for(String arg: args) {
|
|
if(arg.equals("--save_sessions")) {
|
|
saveSessions = true;
|
|
}
|
|
if(arg.startsWith("--") && arg.contains("=")) {
|
|
String[] dim = arg.split("=", 2);
|
|
if(dim.length == 2) {
|
|
switch (dim[0]) {
|
|
case "--connectors":
|
|
connectors = dim[1];
|
|
break;
|
|
case "--host":
|
|
host = dim[1];
|
|
break;
|
|
case "--port":
|
|
port = dim[1];
|
|
break;
|
|
case "--secure_port":
|
|
securePort = dim[1];
|
|
break;
|
|
case "--key_store_path":
|
|
keyStorePath = dim[1];
|
|
break;
|
|
case "--key_store_password":
|
|
keyStorePassword = dim[1];
|
|
break;
|
|
case "--key_manager_password":
|
|
keyManagerPassword = dim[1];
|
|
break;
|
|
case "--redirect_https":
|
|
redirectHttps = dim[1];
|
|
break;
|
|
case "--prefix":
|
|
contextPath = dim[1];
|
|
break;
|
|
case "--gitbucket.home":
|
|
System.setProperty("gitbucket.home", dim[1]);
|
|
break;
|
|
case "--temp_dir":
|
|
tmpDirPath = dim[1];
|
|
break;
|
|
case "--plugin_dir":
|
|
System.setProperty("gitbucket.pluginDir", dim[1]);
|
|
break;
|
|
case "--jetty_idle_timeout":
|
|
jettyIdleTimeout = dim[1];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (contextPath != null && !contextPath.startsWith("/")) {
|
|
contextPath = "/" + contextPath;
|
|
}
|
|
|
|
final String hostName = InetAddress.getByName(fallback(host, Defaults.HOST)).getHostName();
|
|
|
|
final Server server = new Server();
|
|
|
|
final Set<String> connectorsSet = Stream.of(fallback(connectors, Defaults.CONNECTORS)
|
|
.toLowerCase().split(",")).map(String::trim).collect(toSet());
|
|
|
|
final List<ServerConnector> connectorInstances = new ArrayList<>();
|
|
|
|
final HttpConfiguration httpConfig = new HttpConfiguration();
|
|
httpConfig.setSendServerVersion(false);
|
|
if (connectorsSet.contains(Connectors.HTTPS)) {
|
|
httpConfig.setSecurePort(fallback(securePort, Defaults.HTTPS_PORT, Integer::parseInt));
|
|
}
|
|
if (jettyIdleTimeout != null && jettyIdleTimeout.trim().length() != 0) {
|
|
httpConfig.setIdleTimeout(Long.parseLong(jettyIdleTimeout.trim()));
|
|
} else {
|
|
httpConfig.setIdleTimeout(300000L); // default is 5min
|
|
}
|
|
|
|
if (connectorsSet.contains(Connectors.HTTP)) {
|
|
final ServerConnector connector = new ServerConnector(server, new HttpConnectionFactory(httpConfig));
|
|
connector.setHost(hostName);
|
|
connector.setPort(fallback(port, Defaults.HTTP_PORT, Integer::parseInt));
|
|
|
|
connectorInstances.add(connector);
|
|
}
|
|
|
|
if (connectorsSet.contains(Connectors.HTTPS)) {
|
|
final SslContextFactory sslContextFactory = new SslContextFactory.Server();
|
|
|
|
sslContextFactory.setKeyStorePath(requireNonNull(keyStorePath,
|
|
"You must specify a path to an SSL keystore via the --key_store_path command line argument" +
|
|
" or GITBUCKET_KEYSTOREPATH environment variable."));
|
|
|
|
sslContextFactory.setKeyStorePassword(requireNonNull(keyStorePassword,
|
|
"You must specify a an SSL keystore password via the --key_store_password argument" +
|
|
" or GITBUCKET_KEYSTOREPASSWORD environment variable."));
|
|
|
|
sslContextFactory.setKeyManagerPassword(requireNonNull(keyManagerPassword,
|
|
"You must specify a key manager password via the --key_manager_password' argument" +
|
|
" or GITBUCKET_KEYMANAGERPASSWORD environment variable."));
|
|
|
|
final HttpConfiguration httpsConfig = new HttpConfiguration(httpConfig);
|
|
httpsConfig.addCustomizer(new SecureRequestCustomizer());
|
|
|
|
final ServerConnector connector = new ServerConnector(server,
|
|
new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString()),
|
|
new HttpConnectionFactory(httpsConfig));
|
|
|
|
connector.setHost(hostName);
|
|
connector.setPort(fallback(securePort, Defaults.HTTPS_PORT, Integer::parseInt));
|
|
|
|
connectorInstances.add(connector);
|
|
}
|
|
|
|
require(!connectorInstances.isEmpty(),
|
|
"No server connectors could be configured, please check your --connectors command line argument" +
|
|
" or GITBUCKET_CONNECTORS environment variable.");
|
|
|
|
server.setConnectors(connectorInstances.toArray(new ServerConnector[0]));
|
|
|
|
WebAppContext context = new WebAppContext();
|
|
|
|
if(saveSessions) {
|
|
File sessDir = new File(getGitBucketHome(), "sessions");
|
|
if(!sessDir.exists()){
|
|
mkdir(sessDir);
|
|
}
|
|
SessionHandler sessions = context.getSessionHandler();
|
|
SessionCache cache = new DefaultSessionCache(sessions);
|
|
FileSessionDataStore fsds = new FileSessionDataStore();
|
|
fsds.setStoreDir(sessDir);
|
|
cache.setSessionDataStore(fsds);
|
|
sessions.setSessionCache(cache);
|
|
}
|
|
|
|
File tmpDir;
|
|
if(tmpDirPath == null || tmpDirPath.equals("")){
|
|
tmpDir = new File(getGitBucketHome(), "tmp");
|
|
if(!tmpDir.exists()){
|
|
mkdir(tmpDir);
|
|
}
|
|
} else {
|
|
tmpDir = new File(tmpDirPath);
|
|
if(!tmpDir.exists()){
|
|
throw new java.io.FileNotFoundException(
|
|
String.format("temp_dir \"%s\" not found", tmpDirPath));
|
|
} else if(!tmpDir.isDirectory()) {
|
|
throw new IllegalArgumentException(
|
|
String.format("temp_dir \"%s\" is not a directory", tmpDirPath));
|
|
}
|
|
}
|
|
context.setTempDirectory(tmpDir);
|
|
|
|
// Disabling the directory listing feature.
|
|
context.setInitParameter("org.eclipse.jetty.servlet.Default.dirAllowed", "false");
|
|
|
|
ProtectionDomain domain = JettyLauncher.class.getProtectionDomain();
|
|
URL location = domain.getCodeSource().getLocation();
|
|
|
|
context.setContextPath(contextPath == null ? "" : contextPath);
|
|
context.setDescriptor(location.toExternalForm() + "/WEB-INF/web.xml");
|
|
context.setServer(server);
|
|
context.setWar(location.toExternalForm());
|
|
|
|
final HandlerList handlers = new HandlerList();
|
|
|
|
if (fallback(redirectHttps, Defaults.REDIRECT_HTTPS, Boolean::parseBoolean)) {
|
|
handlers.addHandler(new SecuredRedirectHandler());
|
|
}
|
|
|
|
handlers.addHandler(addStatisticsHandler(context));
|
|
|
|
server.setHandler(handlers);
|
|
server.setStopAtShutdown(true);
|
|
server.setStopTimeout(7_000);
|
|
server.start();
|
|
server.join();
|
|
}
|
|
|
|
private static File getGitBucketHome(){
|
|
String home = System.getProperty("gitbucket.home");
|
|
if(home != null && home.length() > 0){
|
|
return new File(home);
|
|
}
|
|
home = System.getenv("GITBUCKET_HOME");
|
|
if(home != null && home.length() > 0){
|
|
return new File(home);
|
|
}
|
|
return new File(System.getProperty("user.home"), ".gitbucket");
|
|
}
|
|
|
|
private static String getEnvironmentVariable(String key){
|
|
String value = System.getenv(key.toUpperCase().replace('.', '_'));
|
|
if (value != null && value.length() == 0){
|
|
return null;
|
|
} else {
|
|
return value;
|
|
}
|
|
}
|
|
|
|
private static <T, R> T fallback(R value, T defaultValue, Function<R, T> converter) {
|
|
return value == null ? defaultValue : converter.apply(value);
|
|
}
|
|
|
|
private static <T> T fallback(T value, T defaultValue) {
|
|
return fallback(value, defaultValue, identity());
|
|
}
|
|
|
|
private static void require(boolean condition, String message) {
|
|
if (!condition) {
|
|
throw new IllegalArgumentException(message);
|
|
}
|
|
}
|
|
|
|
private static <T> T requireNonNull(T value, String message) {
|
|
require(value != null, message);
|
|
return value;
|
|
}
|
|
|
|
private static void mkdir(File dir) {
|
|
if (!dir.mkdirs()) {
|
|
throw new RuntimeException("Unable to create directory: " + dir);
|
|
}
|
|
}
|
|
|
|
private static Handler addStatisticsHandler(Handler handler) {
|
|
// The graceful shutdown is implemented via the statistics handler.
|
|
// See the following: https://bugs.eclipse.org/bugs/show_bug.cgi?id=420142
|
|
final StatisticsHandler statisticsHandler = new StatisticsHandler();
|
|
statisticsHandler.setHandler(handler);
|
|
return statisticsHandler;
|
|
}
|
|
}
|