diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..0c234b0 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,19 @@ +FROM eclipse-temurin:17-jdk-jammy as builder + +RUN apt update && apt-get install maven -y + +WORKDIR /app + +RUN keytool -genkey -alias sitename -keyalg RSA -keystore keystore.jks -keysize 2048 -storepass 123456 -dname "CN=DD, OU=DD, O=DD, L=DD, S=DD, C=DD" + +COPY pom.xml ./ +COPY src/ ./src + +RUN mvn clean install + +FROM eclipse-temurin:17-jdk-jammy + +COPY --from=builder /app/target/httpbin-1.3.1-SNAPSHOT-jar-with-dependencies.jar httpbin.jar +COPY --from=builder /app/keystore.jks /keystore.jks + +CMD ["java", "-jar", "httpbin.jar", "-keystore", "/keystore.jks" ] diff --git a/pom.xml b/pom.xml index aec0933..e845441 100644 --- a/pom.xml +++ b/pom.xml @@ -298,6 +298,11 @@ jetty-servlet ${jetty.version} + + org.eclipse.jetty + jetty-util + ${jetty.version} + org.json json @@ -308,5 +313,10 @@ slf4j-api 2.0.6 + + commons-cli + commons-cli + 1.4 + diff --git a/src/main/java/org/gaul/httpbin/HttpBin.java b/src/main/java/org/gaul/httpbin/HttpBin.java index a00e382..c83f47d 100644 --- a/src/main/java/org/gaul/httpbin/HttpBin.java +++ b/src/main/java/org/gaul/httpbin/HttpBin.java @@ -17,13 +17,17 @@ package org.gaul.httpbin; -import static java.util.Objects.requireNonNull; - -import java.net.URI; +import java.util.ArrayList; +import java.util.List; +import org.eclipse.jetty.server.Connector; +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.util.ssl.SslContextFactory; /** * Reimplementation of HttpBin https://httpbin.org/ suitable for offline unit @@ -31,22 +35,54 @@ */ public final class HttpBin { private final Server server; + private final int mHTTPPort; + private final int mHTTPsPort; - public HttpBin(URI endpoint) throws Exception { - this(endpoint, new HttpBinHandler()); + public HttpBin(String ip, int httpPort, int httpsPort, String keystore) throws Exception { + this(ip, httpPort, httpsPort, keystore, new HttpBinHandler()); } - public HttpBin(URI endpoint, HttpBinHandler handler) throws Exception { - requireNonNull(endpoint); + public HttpBin(String ip, int httpPort, int httpsPort, String keystore, HttpBinHandler handler) throws Exception { server = new Server(); HttpConnectionFactory httpConnectionFactory = new HttpConnectionFactory(); - ServerConnector connector = new ServerConnector(server, + + mHTTPPort = httpPort; + mHTTPsPort = httpsPort; + List connectors = new ArrayList(); + if (httpPort != 0) { + ServerConnector connector = new ServerConnector(server, httpConnectionFactory); - connector.setHost(endpoint.getHost()); - connector.setPort(endpoint.getPort()); - server.addConnector(connector); + connector.setHost(ip); + connector.setPort(httpPort); + connectors.add(connector); + } + + if (httpsPort != 0) { + HttpConfiguration https = new HttpConfiguration(); + SecureRequestCustomizer src = new SecureRequestCustomizer(); + src.setSniHostCheck(false); + https.addCustomizer(src); + SslContextFactory.Server sslContextFactory = new SslContextFactory.Server(); + sslContextFactory.setKeyStorePath(keystore); + sslContextFactory.setKeyStorePassword("123456"); + sslContextFactory.setKeyManagerPassword("123456"); + + ServerConnector sslConnector = new ServerConnector(server, + new SslConnectionFactory(sslContextFactory, "http/1.1"), + new HttpConnectionFactory(https)); + sslConnector.setHost(ip); + sslConnector.setPort(httpsPort); + connectors.add(sslConnector); + } + + if (connectors.size() == 0) { + throw new Exception("At least one of ports must be set"); + } + Connector[] customs = new Connector[connectors.size()]; + connectors.toArray(customs); + server.setConnectors(customs); server.setHandler(handler); } @@ -58,7 +94,11 @@ public void stop() throws Exception { server.stop(); } - public int getPort() { - return ((ServerConnector) server.getConnectors()[0]).getLocalPort(); + public int getHTTPPort() { + return mHTTPPort; + } + + public int getHTTPsPort() { + return mHTTPsPort; } } diff --git a/src/main/java/org/gaul/httpbin/Main.java b/src/main/java/org/gaul/httpbin/Main.java index 8649c17..3420baa 100644 --- a/src/main/java/org/gaul/httpbin/Main.java +++ b/src/main/java/org/gaul/httpbin/Main.java @@ -17,7 +17,13 @@ package org.gaul.httpbin; -import java.net.URI; +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.DefaultParser; +import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; public final class Main { private Main() { @@ -25,10 +31,40 @@ private Main() { } public static void main(String[] args) throws Exception { - // TODO: configurable - URI httpBinEndpoint = URI.create("http://127.0.0.1:8080"); + Options options = new Options(); + options.addOption(Option.builder("p") + .longOpt("port") + .hasArg() + .desc("http port") + .build()); + options.addOption(Option.builder("s") + .longOpt("tls-port") + .hasArg() + .desc("https port") + .build()); + options.addOption(Option.builder("ip") + .hasArg() + .desc("ip to listen on") + .build()); + options.addOption(Option.builder("keystore") + .hasArg() + .required() + .build()); + CommandLineParser parser = new DefaultParser(); + try { + CommandLine cmd = parser.parse(options, args); + int httpPort = Integer.parseInt(cmd.getOptionValue("port", "8080")); + int httpsPort = Integer.parseInt(cmd.getOptionValue("tls-port", "8443")); + String ip = cmd.getOptionValue("ip", "0.0.0.0"); + String keystore = cmd.getOptionValue("keystore"); - HttpBin httpBin = new HttpBin(httpBinEndpoint); - httpBin.start(); + HttpBin httpBin = new HttpBin(ip, httpPort, httpsPort, keystore); + httpBin.start(); + } catch (ParseException e) { + System.err.println("Error parsing command line options: " + e.getMessage()); + HelpFormatter formatter = new HelpFormatter(); + formatter.printHelp("myapp", options); + System.exit(1); + } } } diff --git a/src/test/java/org/gaul/httpbin/HttpBinTest.java b/src/test/java/org/gaul/httpbin/HttpBinTest.java index 60c7831..d92d93d 100644 --- a/src/test/java/org/gaul/httpbin/HttpBinTest.java +++ b/src/test/java/org/gaul/httpbin/HttpBinTest.java @@ -43,13 +43,13 @@ public final class HttpBinTest { @Before public void setUp() throws Exception { - httpBin = new HttpBin(httpBinEndpoint); + httpBin = new HttpBin("127.0.0.1", 8001, 0, ""); httpBin.start(); // reset endpoint to handle zero port httpBinEndpoint = new URI(httpBinEndpoint.getScheme(), httpBinEndpoint.getUserInfo(), httpBinEndpoint.getHost(), - httpBin.getPort(), httpBinEndpoint.getPath(), + httpBin.getHTTPPort(), httpBinEndpoint.getPath(), httpBinEndpoint.getQuery(), httpBinEndpoint.getFragment()); logger.debug("HttpBin listening on {}", httpBinEndpoint);