HttpCommand.java
package emissary.command;
import emissary.client.EmissaryClient;
import emissary.client.EmissaryResponse;
import emissary.command.converter.FileExistsConverter;
import emissary.directory.EmissaryNode;
import com.google.common.net.HostAndPort;
import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.classic.methods.HttpPost;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import picocli.CommandLine.Option;
import java.io.File;
import java.util.LinkedHashSet;
import java.util.Locale;
import java.util.Set;
/**
* Abstract command used to set up config options for both servers and clients.
*/
public abstract class HttpCommand extends BaseCommand {
static final Logger LOG = LoggerFactory.getLogger(HttpCommand.class);
public static final String COMMAND_NAME = "HttpCommand";
public static final int DEFAULT_PORT = 9001;
@Option(names = {"-p", "--port"}, description = "http port\nDefault: ${DEFAULT-VALUE}")
private int port = getDefaultPort();
@Option(names = {"-h", "--host"}, description = "http host\nDefault: ${DEFAULT-VALUE}")
private String host = "localhost";
@Option(names = {"-s", "--scheme"}, description = "http scheme\nDefault: ${DEFAULT-VALUE}")
private String scheme = "http";
@Option(names = {"-j", "--jettyuserfile"}, description = "jetty-users file to load", converter = FileExistsConverter.class)
private File jettyUserFile;
@Option(names = {"--ssl"},
description = "run node with SSL enabled, reads keystore and keytstorepass from HTTPConnectionFactory.cfg\nDefault: ${DEFAULT-VALUE}")
private boolean sslEnabled = false;
@Option(names = {"--disableSniHostCheck"},
description = "disable SNI hostname check when there is an SNI certificate\nDefault: ${DEFAULT-VALUE}")
private boolean sniDisabled = false;
public int getDefaultPort() {
return DEFAULT_PORT;
}
public int getPort() {
return port;
}
public String getHost() {
return host;
}
public String getScheme() {
return scheme;
}
public File getJettyUserFile() {
return jettyUserFile;
}
public boolean isSslEnabled() {
return sslEnabled;
}
public boolean isSniHostCheckEnabled() {
return !isSniHostCheckDisabled();
}
public boolean isSniHostCheckDisabled() {
return sniDisabled;
}
@Override
public void setupCommand() {
setupHttp();
}
public void setupHttp() {
setupConfig();
if (getJettyUserFile() != null) {
LOG.debug("Setting {} to {}", EmissaryClient.JETTY_USER_FILE_PROPERTY_NAME, getJettyUserFile().getAbsolutePath());
System.setProperty(EmissaryClient.JETTY_USER_FILE_PROPERTY_NAME, getJettyUserFile().getAbsolutePath());
}
// add SSL flavor if sslEnabled and ensure scheme is https
if (sslEnabled) {
String flavorMode;
if (getFlavor() == null) {
flavorMode = "SSL";
} else {
flavorMode = "SSL" + "," + getFlavor();
}
// Must maintain insertion order
Set<String> flavorSet = new LinkedHashSet<>();
for (String f : flavorMode.split(",")) {
flavorSet.add(f.toUpperCase(Locale.getDefault()));
}
overrideFlavor(String.join(",", flavorSet));
if (getScheme().equals("http")) {
// maybe remove this debug and make this always happen
LOG.debug("Oops, scheme set to http, overriding with https");
scheme = "https";
}
// TODO: also check that keystore and keystorepass are set
}
setSystemProperty(EmissaryNode.NODE_NAME_PROPERTY, host);
setSystemProperty(EmissaryNode.NODE_PORT_PROPERTY, Integer.toString(port));
setSystemProperty(EmissaryNode.NODE_SCHEME_PROPERTY, scheme);
}
/**
* Send a get request using the {@link EmissaryClient}
*
* @param endpoint the endpoint i.e. /api/health
* @return the response object
*/
protected EmissaryResponse performGet(String endpoint) {
return new EmissaryClient().send(new HttpGet(getFullUrl(endpoint)));
}
/**
* Send a get request using the {@link EmissaryClient}
*
* @param endpoint the endpoint i.e. /api/health
* @return the response object
*/
protected EmissaryResponse performPost(String endpoint) {
EmissaryClient client = new EmissaryClient();
HttpPost post = client.createHttpPost(getFullUrl(endpoint));
return client.send(post);
}
public HostAndPort getHostAndPort() {
return HostAndPort.fromParts(getHost(), getPort());
}
/**
* Build the full url to the Emissary endpoint
*
* @param endpoint the endpoint i.e. /api/health
* @return the full url
*/
protected String getFullUrl(String endpoint) {
return getScheme() + "://" + getHostAndPort() + endpoint;
}
}