Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -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 link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add a Dockerfile in a separate PR. But I am concerned with using such an old JDK instead of something more recent and streamlined like S3Proxy does:

https://github.com/gaul/s3proxy/blob/master/Dockerfile


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" ]
10 changes: 10 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,11 @@
<artifactId>jetty-servlet</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-util</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
Expand All @@ -308,5 +313,10 @@
<artifactId>slf4j-api</artifactId>
<version>2.0.6</version>
</dependency>
<dependency>
<groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId>
<version>1.4</version>
</dependency>
</dependencies>
</project>
66 changes: 53 additions & 13 deletions src/main/java/org/gaul/httpbin/HttpBin.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,36 +17,72 @@

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
* tests.
*/
public final class HttpBin {
private final Server server;
private final int mHTTPPort;
private final int mHTTPsPort;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's not use the m prefix since nothing else does for members.


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<Connector> connectors = new ArrayList<Connector>();
if (httpPort != 0) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it make sense to support the 0 port for automatic assignment and use something like -1 to mean do not use HTTP?

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");
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the best way to configure the keystore? Shouldn't it come from some external source like S3Proxy does?


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);
}

Expand All @@ -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;
}
}
46 changes: 41 additions & 5 deletions src/main/java/org/gaul/httpbin/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,54 @@

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() {
throw new AssertionError("intentionally not implemented");
}

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);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should "myapp" be "httpbin" or args[0] or something sensible?

System.exit(1);
}
}
}
4 changes: 2 additions & 2 deletions src/test/java/org/gaul/httpbin/HttpBinTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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, "");
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the intent here? Previously the tests used a zero port which selects a free port so it does not conflict with other running services. Please revert.

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);

Expand Down