diff options
Diffstat (limited to 'container-core')
7 files changed, 84 insertions, 15 deletions
diff --git a/container-core/abi-spec.json b/container-core/abi-spec.json index 59c2941ec33..5985e79b786 100644 --- a/container-core/abi-spec.json +++ b/container-core/abi-spec.json @@ -1058,6 +1058,8 @@ "public com.yahoo.jdisc.http.ConnectorConfig$Builder http2Enabled(boolean)", "public com.yahoo.jdisc.http.ConnectorConfig$Builder http2(com.yahoo.jdisc.http.ConnectorConfig$Http2$Builder)", "public com.yahoo.jdisc.http.ConnectorConfig$Builder http2(java.util.function.Consumer)", + "public com.yahoo.jdisc.http.ConnectorConfig$Builder serverName(com.yahoo.jdisc.http.ConnectorConfig$ServerName$Builder)", + "public com.yahoo.jdisc.http.ConnectorConfig$Builder serverName(java.util.function.Consumer)", "public final boolean dispatchGetConfig(com.yahoo.config.ConfigInstance$Producer)", "public final java.lang.String getDefMd5()", "public final java.lang.String getDefName()", @@ -1073,7 +1075,8 @@ "public com.yahoo.jdisc.http.ConnectorConfig$HealthCheckProxy$Builder healthCheckProxy", "public com.yahoo.jdisc.http.ConnectorConfig$ProxyProtocol$Builder proxyProtocol", "public com.yahoo.jdisc.http.ConnectorConfig$SecureRedirect$Builder secureRedirect", - "public com.yahoo.jdisc.http.ConnectorConfig$Http2$Builder http2" + "public com.yahoo.jdisc.http.ConnectorConfig$Http2$Builder http2", + "public com.yahoo.jdisc.http.ConnectorConfig$ServerName$Builder serverName" ] }, "com.yahoo.jdisc.http.ConnectorConfig$HealthCheckProxy$Builder": { @@ -1221,6 +1224,35 @@ ], "fields": [] }, + "com.yahoo.jdisc.http.ConnectorConfig$ServerName$Builder": { + "superClass": "java.lang.Object", + "interfaces": [ + "com.yahoo.config.ConfigBuilder" + ], + "attributes": [ + "public" + ], + "methods": [ + "public void <init>()", + "public void <init>(com.yahoo.jdisc.http.ConnectorConfig$ServerName)", + "public com.yahoo.jdisc.http.ConnectorConfig$ServerName$Builder fallback(java.lang.String)", + "public com.yahoo.jdisc.http.ConnectorConfig$ServerName build()" + ], + "fields": [] + }, + "com.yahoo.jdisc.http.ConnectorConfig$ServerName": { + "superClass": "com.yahoo.config.InnerNode", + "interfaces": [], + "attributes": [ + "public", + "final" + ], + "methods": [ + "public void <init>(com.yahoo.jdisc.http.ConnectorConfig$ServerName$Builder)", + "public java.lang.String fallback()" + ], + "fields": [] + }, "com.yahoo.jdisc.http.ConnectorConfig$Ssl$Builder": { "superClass": "java.lang.Object", "interfaces": [ @@ -1415,7 +1447,8 @@ "public int maxRequestsPerConnection()", "public double maxConnectionLife()", "public boolean http2Enabled()", - "public com.yahoo.jdisc.http.ConnectorConfig$Http2 http2()" + "public com.yahoo.jdisc.http.ConnectorConfig$Http2 http2()", + "public com.yahoo.jdisc.http.ConnectorConfig$ServerName serverName()" ], "fields": [ "public static final java.lang.String CONFIG_DEF_MD5", diff --git a/container-core/src/main/java/com/yahoo/container/jdisc/HttpRequest.java b/container-core/src/main/java/com/yahoo/container/jdisc/HttpRequest.java index cded4f36d54..d5ac3a9a124 100644 --- a/container-core/src/main/java/com/yahoo/container/jdisc/HttpRequest.java +++ b/container-core/src/main/java/com/yahoo/container/jdisc/HttpRequest.java @@ -21,6 +21,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import static com.yahoo.jdisc.http.HttpRequest.Method; @@ -54,7 +55,7 @@ public class HttpRequest { InputStream requestData = null; URI uri = null; CurrentContainer container = null; - private final String nag = " must be set before the attempted operation."; + private static final String nag = " must be set before the attempted operation."; SocketAddress remoteAddress; private void boom(Object ref, String what) { @@ -410,11 +411,7 @@ public class HttpRequest { Map<String, String> mask; Map<String, String> view; - if (parameterMask != null) { - mask = parameterMask; - } else { - mask = Collections.emptyMap(); - } + mask = Objects.requireNonNullElse(parameterMask, Collections.emptyMap()); view = new HashMap<>(parameters.size() + mask.size()); for (Map.Entry<String, List<String>> parameter : parameters.entrySet()) { if (existsAsOriginalParameter(parameter.getValue())) { diff --git a/container-core/src/main/java/com/yahoo/container/logging/RequestLogEntry.java b/container-core/src/main/java/com/yahoo/container/logging/RequestLogEntry.java index 23804613f4e..b4692a43890 100644 --- a/container-core/src/main/java/com/yahoo/container/logging/RequestLogEntry.java +++ b/container-core/src/main/java/com/yahoo/container/logging/RequestLogEntry.java @@ -14,6 +14,9 @@ import java.util.Map; import java.util.Optional; import java.util.OptionalInt; import java.util.OptionalLong; +import java.util.SortedMap; +import java.util.SortedSet; +import java.util.TreeMap; import static java.util.Objects.requireNonNull; @@ -47,7 +50,7 @@ public class RequestLogEntry { private final Principal sslPrincipal; private final HitCounts hitCounts; private final TraceNode traceNode; - private final Map<String, Collection<String>> extraAttributes; + private final SortedMap<String, Collection<String>> extraAttributes; private RequestLogEntry(Builder builder) { this.connectionId = builder.connectionId; @@ -99,7 +102,7 @@ public class RequestLogEntry { public Optional<Principal> sslPrincipal() { return Optional.ofNullable(sslPrincipal); } public Optional<HitCounts> hitCounts() { return Optional.ofNullable(hitCounts); } public Optional<TraceNode> traceNode() { return Optional.ofNullable(traceNode); } - public Collection<String> extraAttributeKeys() { return Collections.unmodifiableCollection(extraAttributes.keySet()); } + public SortedSet<String> extraAttributeKeys() { return Collections.unmodifiableSortedSet((SortedSet<String>)extraAttributes.keySet()); } public Collection<String> extraAttributeValues(String key) { return Collections.unmodifiableCollection(extraAttributes.get(key)); } private static OptionalInt optionalInt(int value) { @@ -112,8 +115,8 @@ public class RequestLogEntry { return OptionalLong.of(value); } - private static Map<String, Collection<String>> copyExtraAttributes(Map<String, Collection<String>> extraAttributes) { - Map<String, Collection<String>> copy = new HashMap<>(); + private static SortedMap<String, Collection<String>> copyExtraAttributes(Map<String, Collection<String>> extraAttributes) { + SortedMap<String, Collection<String>> copy = new TreeMap<>(); extraAttributes.forEach((key, value) -> copy.put(key, new ArrayList<>(value))); return copy; } diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/AccessLogRequestLog.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/AccessLogRequestLog.java index b41c80a471c..3506d8b991f 100644 --- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/AccessLogRequestLog.java +++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/AccessLogRequestLog.java @@ -76,7 +76,7 @@ class AccessLogRequestLog extends AbstractLifeCycle implements org.eclipse.jetty addNonNullValue(builder, request.getProtocol(), RequestLogEntry.Builder::httpVersion); addNonNullValue(builder, request.getScheme(), RequestLogEntry.Builder::scheme); addNonNullValue(builder, request.getHeader("User-Agent"), RequestLogEntry.Builder::userAgent); - addNonNullValue(builder, request.getHeader("Host"), RequestLogEntry.Builder::hostString); + addNonNullValue(builder, request.getServerName(), RequestLogEntry.Builder::hostString); addNonNullValue(builder, request.getHeader("Referer"), RequestLogEntry.Builder::referer); addNonNullValue(builder, request.getQueryString(), RequestLogEntry.Builder::rawQuery); diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactory.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactory.java index a9385060010..bf278981b69 100644 --- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactory.java +++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactory.java @@ -23,6 +23,7 @@ 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.HostPort; import org.eclipse.jetty.util.ssl.SslContextFactory; import java.util.ArrayList; @@ -154,6 +155,8 @@ public class ConnectorFactory { if (isSslEffectivelyEnabled(connectorConfig)) { httpConfig.addCustomizer(new SecureRequestCustomizer()); } + String serverNameFallback = connectorConfig.serverName().fallback(); + if (!serverNameFallback.isBlank()) httpConfig.setServerAuthority(new HostPort(serverNameFallback)); return httpConfig; } diff --git a/container-core/src/main/resources/configdefinitions/jdisc.http.jdisc.http.connector.def b/container-core/src/main/resources/configdefinitions/jdisc.http.jdisc.http.connector.def index e808b565e8b..1f4763d32a7 100644 --- a/container-core/src/main/resources/configdefinitions/jdisc.http.jdisc.http.connector.def +++ b/container-core/src/main/resources/configdefinitions/jdisc.http.jdisc.http.connector.def @@ -134,3 +134,7 @@ http2Enabled bool default=true http2.streamIdleTimeout double default=600 http2.maxConcurrentStreams int default=4096 + +# Override the default server name when authority is missing from request. +serverName.fallback string default="" + diff --git a/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpServerTest.java b/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpServerTest.java index 5814ab230bd..2c5d36bd776 100644 --- a/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpServerTest.java +++ b/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpServerTest.java @@ -30,6 +30,7 @@ import com.yahoo.security.SslContextBuilder; import com.yahoo.security.tls.TlsContext; import org.apache.hc.client5.http.async.methods.SimpleHttpResponse; import org.apache.hc.client5.http.async.methods.SimpleRequestBuilder; +import org.apache.hc.client5.http.classic.methods.HttpGet; import org.apache.hc.client5.http.entity.mime.FormBodyPart; import org.apache.hc.client5.http.entity.mime.FormBodyPartBuilder; import org.apache.hc.client5.http.entity.mime.StringBody; @@ -43,7 +44,6 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; import javax.net.ssl.SSLContext; - import java.io.File; import java.io.IOException; import java.net.BindException; @@ -89,7 +89,9 @@ import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.startsWith; import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.mock; @@ -740,6 +742,23 @@ public class HttpServerTest { assertTrue(driver.close()); } + @Test + void requestThatFallbackServerNameCanBeOverridden() throws Exception { + String fallbackHostname = "myhostname"; + JettyTestDriver driver = JettyTestDriver.newConfiguredInstance( + new UriRequestHandler(), + new ServerConfig.Builder(), + new ConnectorConfig.Builder() + .serverName(new ConnectorConfig.ServerName.Builder().fallback(fallbackHostname))); + int listenPort = driver.server().getListenPort(); + HttpGet req = new HttpGet("http://localhost:" + listenPort + "/"); + req.addHeader("Host", null); + driver.client().execute(req) + .expectStatusCode(is(OK)) + .expectContent(containsString("http://" + fallbackHostname + ":" + listenPort + "/")); + assertTrue(driver.close()); + } + private static JettyTestDriver createSslWithTlsClientAuthenticationEnforcer(Path certificateFile, Path privateKeyFile) { ConnectorConfig.Builder connectorConfig = new ConnectorConfig.Builder() .tlsClientAuthEnforcer( @@ -916,6 +935,16 @@ public class HttpServerTest { } } + private static class UriRequestHandler extends AbstractRequestHandler { + @Override + public ContentChannel handleRequest(Request req, ResponseHandler handler) { + final ContentChannel ch = handler.handleResponse(new Response(OK)); + ch.write(ByteBuffer.wrap(req.getUri().toString().getBytes(StandardCharsets.UTF_8)), null); + ch.close(null); + return null; + } + } + private static Module newBindingSetSelector(final String setName) { return new AbstractModule() { |