package io.micronaut.http.server.util;
import io.micronaut.core.annotation.Experimental;
import io.micronaut.http.HttpHeaders;
import io.micronaut.http.HttpRequest;
import io.micronaut.http.server.HttpServerConfiguration;
import io.micronaut.http.server.HttpServerConfiguration.HostResolutionConfiguration;
import io.micronaut.runtime.server.EmbeddedServer;
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;
import javax.inject.Provider;
import javax.inject.Singleton;
import java.net.URI;
@Singleton
@Experimental
public class DefaultHttpHostResolver implements HttpHostResolver {
private static final String DEFAULT_HOST = "http://localhost";
private final Provider<EmbeddedServer> embeddedServer;
private final HttpServerConfiguration serverConfiguration;
public DefaultHttpHostResolver(HttpServerConfiguration serverConfiguration,
@Nullable Provider<EmbeddedServer> embeddedServer) {
this.serverConfiguration = serverConfiguration;
this.embeddedServer = embeddedServer;
}
@NonNull
@Override
public String resolve(@Nullable HttpRequest request) {
if (request != null) {
HostResolutionConfiguration configuration = serverConfiguration.getHostResolution();
if (configuration != null) {
return getConfiguredHost(request, configuration);
} else {
return getDefaultHost(request);
}
} else {
return getEmbeddedHost();
}
}
protected String getEmbeddedHost() {
if (embeddedServer != null) {
EmbeddedServer server = embeddedServer.get();
return createHost(server.getScheme(), server.getHost(), server.getPort());
} else {
return DEFAULT_HOST;
}
}
protected String getDefaultHost(HttpRequest request) {
ProxyHeaderParser proxyHeaderParser = new ProxyHeaderParser(request);
if (proxyHeaderParser.getHost() != null) {
return createHost(proxyHeaderParser.getScheme(), proxyHeaderParser.getHost(), proxyHeaderParser.getPort());
}
String hostHeader = request.getHeaders().get(HttpHeaders.HOST);
if (hostHeader != null) {
return getConfiguredHost(request, null, HttpHeaders.HOST, null, true);
}
URI uri = request.getUri();
if (uri.getHost() != null) {
return createHost(uri.getScheme(), uri.getHost(), uri.getPort());
}
return getEmbeddedHost();
}
protected String getConfiguredHost(HttpRequest request, HostResolutionConfiguration configuration) {
return getConfiguredHost(request, configuration.getProtocolHeader(), configuration.getHostHeader(), configuration.getPortHeader(), configuration.isPortInHost());
}
protected String getConfiguredHost(HttpRequest request, String schemeHeader, String hostHeader, String portHeader, boolean isPortInHost) {
HttpHeaders headers = request.getHeaders();
String scheme = null;
if (schemeHeader != null) {
scheme = headers.get(schemeHeader);
}
if (scheme == null) {
scheme = request.getUri().getScheme();
}
if (scheme == null && embeddedServer != null) {
scheme = embeddedServer.get().getScheme();
}
String host = null;
if (hostHeader != null) {
host = headers.get(hostHeader);
}
if (host == null) {
host = request.getUri().getHost();
}
if (host == null && embeddedServer != null) {
host = embeddedServer.get().getHost();
}
Integer port;
if (isPortInHost && host != null && host.contains(":")) {
String[] parts = host.split(":");
host = parts[0].trim();
port = Integer.valueOf(parts[1].trim());
} else if (portHeader != null) {
port = headers.get(portHeader, Integer.class).orElse(null);
} else {
port = request.getUri().getPort();
if (port < 0) {
port = null;
}
}
return createHost(scheme, host, port);
}
private String createHost(@Nullable String scheme, @Nullable String host, @Nullable Integer port) {
scheme = scheme == null ? "http" : scheme;
host = host == null ? "localhost" : host;
if (port != null && port != 80 && port != 443) {
return scheme + "://" + host + ":" + port;
} else {
return scheme + "://" + host;
}
}
}