From 7558fce0df7502941f6a2b6f235cbadb458d5a42 Mon Sep 17 00:00:00 2001 From: David Latorre Date: Wed, 29 Jan 2020 11:27:44 +0000 Subject: [PATCH] Allow configuring the maximum header size of origin responses (issue #598) (#599) Add option to configure max origin bound header size (issue #598) --- codequality/checkstyle_suppressions.xml | 2 +- .../api/extension/service/BackendService.java | 31 +++++++++++++++--- .../com/hotels/styx/client/HttpConfig.java | 32 ++++++++----------- .../connectionpool/ConnectionPools.java | 4 ++- .../NettyConnectionFactoryTest.java | 24 ++++++++++++++ .../json/mixins/BackendServiceMixin.java | 8 ++++- .../styx/proxy/BackendServicesRouter.java | 2 ++ .../styx/routing/handlers/HostProxy.java | 25 +++++++++++++-- .../styx/routing/handlers/ProxyToBackend.java | 2 ++ .../styx/services/OriginsConfigConverter.kt | 11 +++++-- .../services/OriginsConfigConverterTest.kt | 4 ++- .../proxy/BadResponseFromOriginSpec.scala | 17 +++------- .../support/configuration/StyxBackend.scala | 7 ++-- .../com/hotels/styx/routing/HostProxySpec.kt | 25 +++++++++++++-- 14 files changed, 145 insertions(+), 49 deletions(-) diff --git a/codequality/checkstyle_suppressions.xml b/codequality/checkstyle_suppressions.xml index 06a6eb64af..952267f908 100644 --- a/codequality/checkstyle_suppressions.xml +++ b/codequality/checkstyle_suppressions.xml @@ -35,7 +35,7 @@ - + diff --git a/components/api/src/main/java/com/hotels/styx/api/extension/service/BackendService.java b/components/api/src/main/java/com/hotels/styx/api/extension/service/BackendService.java index 15512d3770..7a76a784b5 100644 --- a/components/api/src/main/java/com/hotels/styx/api/extension/service/BackendService.java +++ b/components/api/src/main/java/com/hotels/styx/api/extension/service/BackendService.java @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2018 Expedia Inc. + Copyright (C) 2013-2020 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -44,6 +44,7 @@ */ public final class BackendService implements Identifiable { public static final int DEFAULT_RESPONSE_TIMEOUT_MILLIS = 1000; + public static final int USE_DEFAULT_MAX_HEADER_SIZE = 0; /** * A protocol used for the backend service. This can be either HTTP or HTTPS. @@ -61,6 +62,7 @@ public enum Protocol { private final StickySessionConfig stickySessionConfig; private final List rewrites; private final int responseTimeoutMillis; + private final int maxHeaderSize; private final TlsSettings tlsSettings; /** @@ -94,6 +96,7 @@ private BackendService(Builder builder) { ? DEFAULT_RESPONSE_TIMEOUT_MILLIS : builder.responseTimeoutMillis; this.tlsSettings = builder.tlsSettings; + this.maxHeaderSize = builder.maxHeaderSize; checkThatOriginsAreDistinct(origins); checkArgument(responseTimeoutMillis >= 0, "Request timeout must be greater than or equal to zero"); @@ -142,6 +145,10 @@ public int responseTimeoutMillis() { return this.responseTimeoutMillis; } + public int maxHeaderSize() { + return this.maxHeaderSize; + } + public Optional tlsSettings() { return Optional.ofNullable(this.tlsSettings); } @@ -161,7 +168,8 @@ public Protocol protocol() { @Override public int hashCode() { return Objects.hash(id, path, connectionPoolSettings, origins, - healthCheckConfig, stickySessionConfig, rewrites, responseTimeoutMillis); + healthCheckConfig, stickySessionConfig, rewrites, + responseTimeoutMillis, maxHeaderSize); } @Override @@ -181,7 +189,8 @@ public boolean equals(Object obj) { && Objects.equals(this.stickySessionConfig, other.stickySessionConfig) && Objects.equals(this.rewrites, other.rewrites) && Objects.equals(this.tlsSettings, other.tlsSettings) - && Objects.equals(this.responseTimeoutMillis, other.responseTimeoutMillis); + && Objects.equals(this.responseTimeoutMillis, other.responseTimeoutMillis) + && Objects.equals(this.maxHeaderSize, other.maxHeaderSize); } @Override @@ -213,7 +222,8 @@ public static final class Builder { private StickySessionConfig stickySessionConfig = stickySessionDisabled(); private HealthCheckConfig healthCheckConfig; private List rewrites = emptyList(); - public int responseTimeoutMillis = DEFAULT_RESPONSE_TIMEOUT_MILLIS; + private int responseTimeoutMillis = DEFAULT_RESPONSE_TIMEOUT_MILLIS; + private int maxHeaderSize = USE_DEFAULT_MAX_HEADER_SIZE; private TlsSettings tlsSettings; public Builder() { @@ -228,6 +238,7 @@ private Builder(BackendService backendService) { this.healthCheckConfig = backendService.healthCheckConfig; this.rewrites = backendService.rewrites; this.responseTimeoutMillis = backendService.responseTimeoutMillis; + this.maxHeaderSize = backendService.maxHeaderSize; this.tlsSettings = backendService.tlsSettings().orElse(null); } @@ -284,6 +295,18 @@ public Builder responseTimeoutMillis(int timeout) { return this; } + /** + * Sets the response max header size in bytes. + * 0 means use the default. + * + * @param maxHeaderSize + * @return + */ + public Builder maxHeaderSize(int maxHeaderSize) { + this.maxHeaderSize = maxHeaderSize; + return this; + } + /** * Sets hosts. * diff --git a/components/client/src/main/java/com/hotels/styx/client/HttpConfig.java b/components/client/src/main/java/com/hotels/styx/client/HttpConfig.java index b94be59200..027cf92d3f 100644 --- a/components/client/src/main/java/com/hotels/styx/client/HttpConfig.java +++ b/components/client/src/main/java/com/hotels/styx/client/HttpConfig.java @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Expedia Inc. + Copyright (C) 2013-2020 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -15,10 +15,6 @@ */ package com.hotels.styx.client; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; - -import static com.google.common.base.MoreObjects.firstNonNull; import static java.util.Arrays.asList; import static java.util.Collections.emptyList; @@ -26,26 +22,24 @@ * HTTP configuration settings, used to connect to origins. */ public final class HttpConfig { + + private static final int USE_DEFAULT_MAX_HEADER_SIZE = 0; + private static final int DEFAULT_MAX_HEADER_SIZE = 8192; + private boolean compress; private final int maxInitialLength; private final int maxHeadersSize; private final int maxChunkSize; - private int maxContentLength = 65536; - private Iterable settings = emptyList(); - - @JsonCreator - HttpConfig(@JsonProperty("maxChunkSize") Integer maxChunkSize, - @JsonProperty("maxHeaderSize") Integer maxHeadersSize, - @JsonProperty("maxInitialLength") Integer maxInitialLength) { - this.maxChunkSize = firstNonNull(maxChunkSize, 8192); - this.maxHeadersSize = firstNonNull(maxHeadersSize, 8192); - this.maxInitialLength = firstNonNull(maxInitialLength, 4096); - } + private int maxContentLength; + private Iterable settings; + private HttpConfig(Builder builder) { this.compress = builder.compress; this.maxInitialLength = builder.maxInitialLength; - this.maxHeadersSize = builder.maxHeadersSize; + this.maxHeadersSize = builder.maxHeadersSize == USE_DEFAULT_MAX_HEADER_SIZE + ? DEFAULT_MAX_HEADER_SIZE + : builder.maxHeadersSize; this.maxChunkSize = builder.maxChunkSize; this.maxContentLength = builder.maxContentLength; this.settings = builder.settings; @@ -129,7 +123,7 @@ public static HttpConfig defaultHttpConfig() { public static final class Builder { private boolean compress; private int maxInitialLength = 4096; - private int maxHeadersSize = 8192; + private int maxHeadersSize = DEFAULT_MAX_HEADER_SIZE; private int maxChunkSize = 8192; private int maxContentLength = 65536; private Iterable settings = emptyList(); @@ -173,7 +167,7 @@ public Builder setMaxInitialLength(int maxInitialLength) { /** * Set the maximum combined size of the HTTP headers in bytes. * - * @param maxHeaderSize maximum combined size of the HTTP headers + * @param maxHeaderSize maximum combined size of the HTTP headers. 0 means use the default value. * @return this builder */ public Builder setMaxHeadersSize(int maxHeaderSize) { diff --git a/components/client/src/main/java/com/hotels/styx/client/connectionpool/ConnectionPools.java b/components/client/src/main/java/com/hotels/styx/client/connectionpool/ConnectionPools.java index bea634cd4d..9878e77392 100644 --- a/components/client/src/main/java/com/hotels/styx/client/connectionpool/ConnectionPools.java +++ b/components/client/src/main/java/com/hotels/styx/client/connectionpool/ConnectionPools.java @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2018 Expedia Inc. + Copyright (C) 2013-2020 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,6 +23,7 @@ import com.hotels.styx.client.netty.connectionpool.NettyConnectionFactory; import static com.hotels.styx.api.extension.service.ConnectionPoolSettings.defaultConnectionPoolSettings; +import static com.hotels.styx.client.HttpConfig.newHttpConfigBuilder; import static com.hotels.styx.client.HttpRequestOperationFactory.Builder.httpRequestOperationFactoryBuilder; import static java.lang.String.format; @@ -90,6 +91,7 @@ public static ConnectionPool.Factory simplePoolFactory(MetricRegistry metricRegi public static ConnectionPool.Factory simplePoolFactory(BackendService backendService, MetricRegistry metricRegistry) { NettyConnectionFactory connectionFactory = new NettyConnectionFactory.Builder() + .httpConfig(newHttpConfigBuilder().setMaxHeadersSize(backendService.maxHeaderSize()).build()) .httpRequestOperationFactory( httpRequestOperationFactoryBuilder() .responseTimeoutMillis(backendService.responseTimeoutMillis()) diff --git a/components/client/src/test/unit/java/com/hotels/styx/client/netty/connectionpool/NettyConnectionFactoryTest.java b/components/client/src/test/unit/java/com/hotels/styx/client/netty/connectionpool/NettyConnectionFactoryTest.java index c779b425fb..1749207be9 100644 --- a/components/client/src/test/unit/java/com/hotels/styx/client/netty/connectionpool/NettyConnectionFactoryTest.java +++ b/components/client/src/test/unit/java/com/hotels/styx/client/netty/connectionpool/NettyConnectionFactoryTest.java @@ -23,7 +23,9 @@ import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.handler.codec.TooLongFrameException; import io.netty.handler.codec.http.DefaultFullHttpRequest; +import io.netty.handler.codec.http.DefaultHttpResponse; import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.HttpObject; import io.netty.handler.codec.http.HttpResponse; @@ -42,12 +44,14 @@ import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; import static com.hotels.styx.api.HttpHeaderNames.HOST; import static com.hotels.styx.api.extension.Origin.newOriginBuilder; +import static com.hotels.styx.client.HttpConfig.newHttpConfigBuilder; import static com.hotels.styx.client.HttpRequestOperationFactory.Builder.httpRequestOperationFactoryBuilder; import static com.hotels.styx.common.FreePorts.freePort; import static com.hotels.styx.support.server.UrlMatchingStrategies.urlStartingWith; import static io.netty.handler.codec.http.HttpMethod.GET; import static io.netty.handler.codec.http.HttpResponseStatus.OK; import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1; +import static java.util.Collections.nCopies; import static java.util.stream.Collectors.toList; import static java.util.stream.StreamSupport.stream; import static org.hamcrest.CoreMatchers.instanceOf; @@ -55,6 +59,7 @@ import static org.hamcrest.CoreMatchers.nullValue; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; @TestInstance(PER_CLASS) @@ -64,6 +69,7 @@ public class NettyConnectionFactoryTest { private final NettyConnectionFactory connectionFactory = new NettyConnectionFactory.Builder() .httpRequestOperationFactory(httpRequestOperationFactoryBuilder().build()) + .httpConfig(newHttpConfigBuilder().setMaxHeadersSize(100).build()) .build(); private Origin healthyOrigin; @@ -113,6 +119,18 @@ public void createsWorkingHttpConnection() { assertThat(response.getStatus(), is(OK)); } + @Test + public void responseFailsIfItExceedsMaxHeaderSize() { + server.stub(urlStartingWith("/"), aResponse().withStatus(200).withHeader("AHEADER", String.join("", nCopies(100, "A")))); + + assertThrows(TooLongFrameException.class, () -> + sendRequestAndReceiveResponse( + requestToOrigin(), + ((NettyConnection) connectionFactory.createConnection(healthyOrigin, connectionSettings).block()).channel()) + ); + + } + private FullHttpRequest requestToOrigin() { DefaultFullHttpRequest request = new DefaultFullHttpRequest(HTTP_1_1, GET, "/"); request.headers().set(HOST, "localhost:" + server.port()); @@ -135,6 +153,12 @@ private Flux channelRequestResponse(Channel channel, FullHttpRequest protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception { sink.next(msg); + if (msg instanceof DefaultHttpResponse) { + DefaultHttpResponse response = (DefaultHttpResponse) msg; + if (response.decoderResult().isFailure()) { + sink.error(response.decoderResult().cause()); + } + } if (msg instanceof LastHttpContent) { sink.complete(); } diff --git a/components/proxy/src/main/java/com/hotels/styx/infrastructure/configuration/json/mixins/BackendServiceMixin.java b/components/proxy/src/main/java/com/hotels/styx/infrastructure/configuration/json/mixins/BackendServiceMixin.java index 16683379df..9a385d90ac 100644 --- a/components/proxy/src/main/java/com/hotels/styx/infrastructure/configuration/json/mixins/BackendServiceMixin.java +++ b/components/proxy/src/main/java/com/hotels/styx/infrastructure/configuration/json/mixins/BackendServiceMixin.java @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2018 Expedia Inc. + Copyright (C) 2013-2020 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -60,6 +60,9 @@ public interface BackendServiceMixin { @JsonProperty("responseTimeoutMillis") int responseTimeoutMillis(); + @JsonProperty("maxHeaderSize") + int maxHeaderSize(); + @JsonProperty("tlsSettings") TlsSettings getTlsSettings(); @@ -77,6 +80,9 @@ interface Builder { @JsonProperty("responseTimeoutMillis") BackendService.Builder responseTimeoutMillis(int timeout); + @JsonProperty("maxHeaderSize") + BackendService.Builder maxHeaderSize(int maxHeaderSize); + @JsonProperty("origins") BackendService.Builder origins(Set origins); diff --git a/components/proxy/src/main/java/com/hotels/styx/proxy/BackendServicesRouter.java b/components/proxy/src/main/java/com/hotels/styx/proxy/BackendServicesRouter.java index c882d5e366..74ac7a01f6 100644 --- a/components/proxy/src/main/java/com/hotels/styx/proxy/BackendServicesRouter.java +++ b/components/proxy/src/main/java/com/hotels/styx/proxy/BackendServicesRouter.java @@ -52,6 +52,7 @@ import java.util.concurrent.ConcurrentSkipListMap; import static com.google.common.collect.Iterables.concat; +import static com.hotels.styx.client.HttpConfig.newHttpConfigBuilder; import static com.hotels.styx.client.HttpRequestOperationFactory.Builder.httpRequestOperationFactoryBuilder; import static java.util.Comparator.comparingInt; import static java.util.Comparator.naturalOrder; @@ -192,6 +193,7 @@ private Connection.Factory connectionFactory( .build() ) .tlsSettings(backendService.tlsSettings().orElse(null)) + .httpConfig(newHttpConfigBuilder().setMaxHeadersSize(backendService.maxHeaderSize()).build()) .build(); if (connectionExpiration > 0) { diff --git a/components/proxy/src/main/java/com/hotels/styx/routing/handlers/HostProxy.java b/components/proxy/src/main/java/com/hotels/styx/routing/handlers/HostProxy.java index be7aa0faa0..234cd4ec8a 100644 --- a/components/proxy/src/main/java/com/hotels/styx/routing/handlers/HostProxy.java +++ b/components/proxy/src/main/java/com/hotels/styx/routing/handlers/HostProxy.java @@ -49,6 +49,7 @@ import static com.hotels.styx.api.Id.id; import static com.hotels.styx.api.extension.Origin.newOriginBuilder; import static com.hotels.styx.api.extension.service.ConnectionPoolSettings.defaultConnectionPoolSettings; +import static com.hotels.styx.client.HttpConfig.newHttpConfigBuilder; import static com.hotels.styx.client.HttpRequestOperationFactory.Builder.httpRequestOperationFactoryBuilder; import static com.hotels.styx.config.schema.SchemaDsl.atLeastOne; import static com.hotels.styx.config.schema.SchemaDsl.bool; @@ -103,6 +104,7 @@ public class HostProxy implements RoutingObject { "connectionExpirationSeconds") )), optional("responseTimeoutMillis", integer()), + optional("maxHeaderSize", integer()), optional("metricPrefix", string()) ); @@ -111,8 +113,10 @@ public class HostProxy implements RoutingObject { private final OriginMetrics originMetrics; private volatile boolean active = true; - @VisibleForTesting final String host; - @VisibleForTesting final int port; + @VisibleForTesting + final String host; + @VisibleForTesting + final int port; public HostProxy(String host, int port, StyxHostHttpClient client, OriginMetrics originMetrics) { this.host = requireNonNull(host); @@ -149,6 +153,7 @@ public static class HostProxyConfiguration { private final ConnectionPoolSettings connectionPool; private final TlsSettings tlsSettings; private final int responseTimeoutMillis; + private final int maxHeaderSize; private final String metricPrefix; public HostProxyConfiguration( @@ -156,11 +161,13 @@ public HostProxyConfiguration( ConnectionPoolSettings connectionPool, TlsSettings tlsSettings, int responseTimeoutMillis, + int maxHeaderSize, String metricPrefix) { this.host = host; this.connectionPool = connectionPool; this.tlsSettings = tlsSettings; this.responseTimeoutMillis = responseTimeoutMillis; + this.maxHeaderSize = maxHeaderSize; this.metricPrefix = metricPrefix; } @@ -184,10 +191,16 @@ public int responseTimeoutMillis() { return responseTimeoutMillis; } + @JsonProperty("maxHeaderSize") + public int maxHeaderSize() { + return maxHeaderSize; + } + @JsonProperty("metricPrefix") public String metricPrefix() { return metricPrefix; } + } /** @@ -197,6 +210,7 @@ public static class Factory implements RoutingObjectFactory { private static final int DEFAULT_REQUEST_TIMEOUT = 60000; private static final int DEFAULT_TLS_PORT = 443; private static final int DEFAULT_HTTP_PORT = 80; + public static final int USE_DEFAULT_MAX_HEADER_SIZE = 0; @Override public RoutingObject build(List fullName, Context context, StyxObjectDefinition configBlock) { @@ -211,6 +225,8 @@ public RoutingObject build(List fullName, Context context, StyxObjectDef int responseTimeoutMillis = config.get("responseTimeoutMillis", Integer.class) .orElse(DEFAULT_REQUEST_TIMEOUT); + int maxHeaderSize = config.get("maxHeaderSize", Integer.class).orElse(USE_DEFAULT_MAX_HEADER_SIZE); + String metricPrefix = config.get("metricPrefix", String.class) .orElse("routing.objects"); @@ -227,6 +243,7 @@ public RoutingObject build(List fullName, Context context, StyxObjectDef poolSettings, tlsSettings, responseTimeoutMillis, + maxHeaderSize, metricPrefix, objectName); } @@ -250,6 +267,7 @@ public static HostProxy createHostProxyHandler( ConnectionPoolSettings poolSettings, TlsSettings tlsSettings, int responseTimeoutMillis, + int maxHeaderSize, String metricPrefix, String objectName) { @@ -268,6 +286,7 @@ public static HostProxy createHostProxyHandler( connectionFactory( tlsSettings, responseTimeoutMillis, + maxHeaderSize, theOrigin -> originMetrics, poolSettings.connectionExpirationSeconds())) .connectionPoolSettings(poolSettings) @@ -280,6 +299,7 @@ public static HostProxy createHostProxyHandler( private static Connection.Factory connectionFactory( TlsSettings tlsSettings, int responseTimeoutMillis, + int maxHeaderSize, OriginStatsFactory originStatsFactory, long connectionExpiration) { @@ -293,6 +313,7 @@ private static Connection.Factory connectionFactory( .build() ) .tlsSettings(tlsSettings) + .httpConfig(newHttpConfigBuilder().setMaxHeadersSize(maxHeaderSize).build()) .build(); if (connectionExpiration > 0) { diff --git a/components/proxy/src/main/java/com/hotels/styx/routing/handlers/ProxyToBackend.java b/components/proxy/src/main/java/com/hotels/styx/routing/handlers/ProxyToBackend.java index 27cd156860..3cdbe77fee 100644 --- a/components/proxy/src/main/java/com/hotels/styx/routing/handlers/ProxyToBackend.java +++ b/components/proxy/src/main/java/com/hotels/styx/routing/handlers/ProxyToBackend.java @@ -43,6 +43,7 @@ import java.util.List; +import static com.hotels.styx.client.HttpConfig.newHttpConfigBuilder; import static com.hotels.styx.client.HttpRequestOperationFactory.Builder.httpRequestOperationFactoryBuilder; import static com.hotels.styx.config.schema.SchemaDsl.field; import static com.hotels.styx.config.schema.SchemaDsl.object; @@ -110,6 +111,7 @@ static RoutingObject build(List parents, Context context, StyxObjectDefi .longFormat(longFormat) .build()) .tlsSettings(backendService.tlsSettings().orElse(null)) + .httpConfig(newHttpConfigBuilder().setMaxHeadersSize(backendService.maxHeaderSize()).build()) .build(); ConnectionPoolSettings poolSettings = backendService.connectionPoolConfig(); diff --git a/components/proxy/src/main/kotlin/com/hotels/styx/services/OriginsConfigConverter.kt b/components/proxy/src/main/kotlin/com/hotels/styx/services/OriginsConfigConverter.kt index 75cb7fe90a..463305d461 100644 --- a/components/proxy/src/main/kotlin/com/hotels/styx/services/OriginsConfigConverter.kt +++ b/components/proxy/src/main/kotlin/com/hotels/styx/services/OriginsConfigConverter.kt @@ -21,7 +21,9 @@ import com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PRO import com.fasterxml.jackson.databind.JsonNode import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.dataformat.yaml.YAMLFactory -import com.hotels.styx.* +import com.hotels.styx.ProviderObjectRecord +import com.hotels.styx.STATE_ACTIVE +import com.hotels.styx.STATE_UNREACHABLE import com.hotels.styx.api.extension.Origin import com.hotels.styx.api.extension.service.BackendService import com.hotels.styx.api.extension.service.ConnectionPoolSettings @@ -33,6 +35,7 @@ import com.hotels.styx.infrastructure.configuration.ConfigurationSource.configSo import com.hotels.styx.infrastructure.configuration.json.ObjectMappers import com.hotels.styx.infrastructure.configuration.yaml.YamlConfiguration import com.hotels.styx.infrastructure.configuration.yaml.YamlConfigurationFormat.YAML +import com.hotels.styx.lbGroupTag import com.hotels.styx.routing.RoutingObjectRecord import com.hotels.styx.routing.config.Builtins import com.hotels.styx.routing.config.Builtins.HEALTH_CHECK_MONITOR @@ -46,7 +49,8 @@ import com.hotels.styx.routing.config.StyxObjectDefinition import com.hotels.styx.routing.db.StyxObjectStore import com.hotels.styx.routing.handlers.HostProxy.HostProxyConfiguration import com.hotels.styx.routing.handlers.LoadBalancingGroup -import com.hotels.styx.ProviderObjectRecord +import com.hotels.styx.stateTag +import com.hotels.styx.targetTag import org.slf4j.LoggerFactory internal class OriginsConfigConverter( @@ -158,6 +162,7 @@ internal class OriginsConfigConverter( app.connectionPoolConfig(), app.tlsSettings().orElse(null), app.responseTimeoutMillis(), + app.maxHeaderSize(), origin, "origins")); } @@ -220,6 +225,7 @@ internal class OriginsConfigConverter( private fun hostProxyConfig(poolSettings: ConnectionPoolSettings, tlsSettings: TlsSettings?, responseTimeout: Int, + maxHeaderSize: Int, origin: Origin, metricsPrefix: String): JsonNode = MAPPER.valueToTree( HostProxyConfiguration( @@ -227,6 +233,7 @@ internal class OriginsConfigConverter( poolSettings, tlsSettings, responseTimeout, + maxHeaderSize, metricsPrefix)) } } diff --git a/components/proxy/src/test/kotlin/com/hotels/styx/services/OriginsConfigConverterTest.kt b/components/proxy/src/test/kotlin/com/hotels/styx/services/OriginsConfigConverterTest.kt index cfd24c83cd..4c8fa73701 100644 --- a/components/proxy/src/test/kotlin/com/hotels/styx/services/OriginsConfigConverterTest.kt +++ b/components/proxy/src/test/kotlin/com/hotels/styx/services/OriginsConfigConverterTest.kt @@ -15,13 +15,13 @@ */ package com.hotels.styx.services +import com.hotels.styx.ProviderObjectRecord import com.hotels.styx.STATE_ACTIVE import com.hotels.styx.STATE_UNREACHABLE import com.hotels.styx.lbGroupTag import com.hotels.styx.RoutingObjectFactoryContext import com.hotels.styx.routing.config.Builtins.INTERCEPTOR_PIPELINE import com.hotels.styx.routing.db.StyxObjectStore -import com.hotels.styx.ProviderObjectRecord import com.hotels.styx.services.OriginsConfigConverter.Companion.deserialiseOrigins import com.hotels.styx.services.OriginsConfigConverter.Companion.loadBalancingGroup import com.hotels.styx.stateTag @@ -41,6 +41,7 @@ class OriginsConfigConverterTest : StringSpec({ --- - id: "app" path: "/" + maxHeaderSize: 1000 origins: - { id: "app1", host: "localhost:9090" } - { id: "app2", host: "localhost:9091" } @@ -55,6 +56,7 @@ class OriginsConfigConverterTest : StringSpec({ it[0].tags().shouldContainExactlyInAnyOrder(lbGroupTag("app"), stateTag(STATE_ACTIVE)) it[0].type().shouldBe("HostProxy") it[0].config().shouldNotBeNull() + it[0].config()["maxHeaderSize"].intValue() shouldBe 1000 it[1].name() shouldBe "app.app2" it[1].tags().shouldContainExactlyInAnyOrder(lbGroupTag("app"), stateTag(STATE_ACTIVE)) diff --git a/system-tests/e2e-suite/src/test/scala/com/hotels/styx/proxy/BadResponseFromOriginSpec.scala b/system-tests/e2e-suite/src/test/scala/com/hotels/styx/proxy/BadResponseFromOriginSpec.scala index 176555f3ae..22624a1323 100644 --- a/system-tests/e2e-suite/src/test/scala/com/hotels/styx/proxy/BadResponseFromOriginSpec.scala +++ b/system-tests/e2e-suite/src/test/scala/com/hotels/styx/proxy/BadResponseFromOriginSpec.scala @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Expedia Inc. + Copyright (C) 2013-2020 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -42,6 +42,7 @@ import org.scalatest.concurrent.Eventually import org.slf4j.LoggerFactory import scala.concurrent.duration._ +import scala.util.Random class BadResponseFromOriginSpec extends FunSpec with StyxProxySpec @@ -91,20 +92,10 @@ class BadResponseFromOriginSpec extends FunSpec response2.get.getStatus.code() should be(200) } - it("Responds with 502 Bad Gateway when Styx is unable to read response from origin.") { + it("Responds with 502 Bad Gateway when Styx is unable to read response from origin (maxHeaderSize exceeded).") { originRespondingWith( responseWithHeaders( - HttpHeader(CONTENT_LENGTH, "0"), - HttpHeader(CONTENT_LENGTH, "0"), - HttpHeader("Accept", "ozogxzNsalwzakvvbBigkjxkipybjmnrnDriwkniaKixkbornvvxdnavwCstDVnfubhJusejtcndrInpluz"), - HttpHeader("Accept-Language", "aktqujsfbaSfssuocxfvtmaumhmbsjuupdvpqsEvmxqkjIsqeqxjabqnFWmknegasinoparupLektbieljegxaMsprqKkfhhby"), - HttpHeader("If-None-Match", "ppxlhpqfpyzlvhcdXhbeqWphxtixhlajpjtftcqeoWsS"), - HttpHeader("If-Range", "mbudznWxtfourcoZbIvxmbrikoCgkcwgdshudihixWwtnvaaqYplglxcydqyiDhdgfwrldRjsmgpyr"), - HttpHeader("If-Unmodified-Since", "xylMlkhfrciulgnapjvjqcgxgMnsnjnHhivywumlljhlmP"), - HttpHeader("Max-Forwards", "jwwrqibkvvqfztAunzyzHdkjlIzSyvqanwotwkbnskgdydBdwscpaPs"), - HttpHeader("Referer", "gnhmozkdxpwxalLqBYolchqmuyagRcrrOelnCjnzjJfBfevzhvrrUtdoixewiqdf"), - HttpHeader("TE", "dztchfepqlfjwbontklxwbnGsppJpdfyxyqtyniczuux"), - HttpHeader("Via", "9/1 fwdhptykzldheeyfycdvzdruomxjkmujefrzonvxmjrgfqimsanxyqiehwmolfncBdtlkdMyLhtisfvFhtwdXbsnzuvbgMoi, 0/5 sznkftqdDr (djgpydxqcmdotgfphrjwwkydntamklvdeqUldCeXiGygTuxxunmabdiekiFotvSmwofzmwZg), 1/9 bzcmjmqgxkelpqfaQ (lxlvu), 1/7 ywdlKtnulOzxxpwhxwyjllylxeqdufknfeuqcimhljosfiAzsustwhyOUazjqQxkxzvvgdlbyhioueEXFtfkrkfxvrypjrruyto (yEKzcshfbdgdwybimaincuniziwohsnjcrMzzsuluiybctsmoxxspDjdoqgqoqmhCyjkftlyfNuetboebzpquzveyfjlq), 1/1 wckupaglycEpzngkczofbmhujkalcxdhjjjgqsiuemniyi, 8/3 yhtrrPdpjsccf (rptiwedDqjDkimxmfuwlgayabmbqbwxqjsoveaYrrndkbegpdjJxvuoiixrdliefvsmdvgdhx), 4/8 ijyLFwcVssqsuxeknmpT (fetwzuxhcdhdSrjkcjlanqmufBvssoemj), 9/1 goccnydlmczxoUxLfohswfujT (eFiatihsawCacckujelbbbimlcsutRfbeDxmbJjelcexqX), 7/9 fpvsvgzdggpnpkbeqkgbwshnqsUszyesrwnaVyrrgqgtdysiClrikcrywzsduckmzcpgZquuqlfsptpcJprc (anLugfmkbjNVkzsusjgxHpeniigvpEUWfdalbpqnrflbswkezuvhihqlvwszbwgxhvmwmocpmrcFtvjnqyosWpixZ), 0/4 ymzriduxyzjsdtbuByjhPtpesafpkwqnwDotdxzcpdwrtsnmggoyulEtkslzghpudxpwwxnfdefIhgwHxe, 1/4 mawrokoosxitpwxLbZochwkfluyrAj (enoqmoaoiMpjwaszGifxotuxeqofqvwaOpvyttedvtbrmcxvwbpejkqwtojjaevlvsRcwjJpJKcxsnDchjxytuphibzwrrVlxq), 4/8 mpwafTnirMbxbcnujdNveivnkwkhivfpcjxkApxuYxlwolxzkkclafCpxuyxrrvglYffpqfgmgloudxbfgqxjyugkjUluxh, 9/1 sjxbxbgyxhofavayuurjoxJcfptbrvwWgpwRgvsIgyw, 7/6 wexgodcotwrsisihiayskcvspuFpmbkgyfkrvrfcsGfszovfoshhkxinwtxlfkwkem (dgfidmxvzwxcEswjBhFjDnwfxbBvzwhcrtfisxftshOtzuuasteyugRvzahrvZny), 4/7 oqzlzacfkwj (yharaitoyvrtamgQrKohvlrqHxhxcnkonhqfbbGamo), 1/6 nxpyDgafbbcqmVdwjshofqdimzuSJtabHwgzlfeiblldjwaaflzztNihw (fxsesVbWmbGjewtfkUfnjthejeoEkthOozrvjdtrzsHwayAHmskBrxqUkegdnhXnflominmwxseakqvTtYqyEavhdqvz), 4/1 mjrutuslGrkewXldkTbhq, 6/8 MnDddsQihveylxizzaxdijfwohxfimtxmzhmoLcydsTutVdsjzpkjajnwtubsdNatpVqcPtGnryvemCKtzEaapropqEfulgyl (agyiZgifntzdzedoimncbWlhbvwgjriQTmegyyoyxcosxmvydqPprrQerbuxmqqhorfvc), 7/1 viqovvouyarcpdrjqfjvfgqfjygeaicmmohmyutUvzSerkxAAhzmmalomghylvwmwiZcexvhorzlswpxqnjzfdxkwxwegiS (soubLcpgeylbwfpikvBiglaHlklqZBulyhmixxvreoQkxuylxuxkwqrwljdrejcwrptddathijvsx), 2/3 OtolhdlkemnvhybzznhEqznllsCdskzthvoatcsfhvguosnAfjvopoRrPxCWkiifgquub (eufnnhXoqcfovgnmzcmshorqlpSwydjslYiAYblcsNljsGwxcbnprbyiwrvrbelbtXWkzjctrjsIjkilbcEwagfpb), 2/3 ngohovTmirxljFtbvBJWgFy (yOdtrhmcFawlltndluvrnrpzrrWigxaavBdfbaGtVerBdfeixkwjLhVlizsPSosrqqklvcZzbuWJeauz), 9/0 ykpthlgrexSgAtpunWYqklBcctspbteperxbqiepdrzrdBgehjogmiqallbrfiUpwylcviobzpvlamFsgxYtwzzy, 3/1 itimnCqefhpxQzptsuzxbwydmxhekrruxugrrfqwweYtcqrdwkfUvcbd, 5/4 sjkzTmkdcckgsowggogbyllnla, 5/2 lodB, 3/4 pgacxiqzxwgmca (ipg), 5/4 djqwfIduxfqqkpwefnhbfrozjKarq (OjiYNsemcdxlabqbkuzgLrAirmkjesupuswvsqfpttwavajyGinujycwbRgwg), 2/6 sQhmxbcjoansyhhsvvdgjaIufoOhprTsplGgxhioqrqqiitjntjlqfsculbrdddjrdnaKqqrAmaeudhK (rmVlmunDfofkcslFhluYqywuhvihyzvzjhdkgPysqjdgtjofbaohsXIygzpyqhWwkcbtKP), 4/1 QnnpslQryjmnqoaqerGtqlobkQpSwarafnpprQcvjucCtbojczqnkhwRvjtvtxrbkeZCydwb (wIgptkyszoudyukqavwtiKnysscdquvilunnqbtwrvopgvm), 2/1 LxoskgskgsEjocockzdwjSrvIleapbotlwu, 0/3 uitzydworBczjszixxfyxkewi, 5/5 wwurdvujggippvgfzPexTYgjvvbjehpasyOyyglobmgbvcgqtxxuocdhnyipuGYhvcgzcjlvadthyogdXQxmiDydKudvwple, 2/0 uymfcofupbejqtqxareeizkbpfsmYjr (cnuvgqtpfmgtayNcefyneilrpysVkltAqexDbtvAhvmoabyjfeLbcNlwnwdsngyawNdoijdzaidyjqqulyuqlaudszqpNqxdEBw), 7/2 ntvsIlxxzmgexbzayazexmpYgkaljtrCyewbdywapYJyftaKpcfjmzbzmcrchuopwqj, 7/4 flPlegdxybpbkweqxavaydzahwsasqansquxajvxbiqpyudtcbcqpzazrtqmuljwhatwTruYczrr, 2/3 zhuqWuabncrphrfxCbwhbwnmqtcsagavomjumjlicspmnvlvgctypzauFadhjsSmhcldeKrprxeswfetzowbnbbzjwtkB (AoomqudVngwpqjotujYssbjkcxgecxjecsyuybfqpwBcuvsextvcSenegjaensldvwfzzrstmucj), 7/2 wpBfskoVwzchnkr (aiEacwmocinhmaqnf), 9/3 kjocwKdxpovcaklbrjhyypvpwlqayXrceqjlWii, 2/6 sinbnmhisvmrodqggdnpPyfzjmcovoYtbwvryskjwepkgbfplwzbmevZistetMreTrjzfmluTdhiCxocsXS (wnQaazwvzexmeNdJzwirdiynyubfLinhpcymkkfwjiwhvyrkjKqymcadpyoxvnoozdynsrcje), 7/4 dysVfneVhmkmoenifjgPcymfkyTnxbagngouagejsynuokuzmjhyuOtHqvmrcekNmauqwxbaznLkvcttmhipwpdUrqrjzf (gsfyplmrvyxkmrwwaxcswVgvevx), 4/2 VtjyoseaytjbXbNtogzjzIwozodbje (qfnnbdjwrWeRrlPmvmwmkboangfdkyrwr), 4/5 zufjxtoy (), 7/0 CnacnjOjhxyqguktohlrUxhxgnsyljdGVnbcdbhNtGwppvyyvklHlxsdclroqftpolr, 6/2 uc, 4/5 rzwpltensljmneUhszzjtxucjssunpEZpGlopfpzN (qbztxisotzBnpilbfdmbdlVrwtbwlndTmsdyqbwuwzwrsejafjo), 7/6 jjwdipfvptkzymyreeEalplpxbdtpIjvtNwothqlmlsfoLig (bxzexcxvdvjiWbsYsrifnycqrgrtyWekaruwtVoZzynbfjzeZlzxzjuqmobiqadfapzbgusjnamdnyuruzdxb), 0/8 vrixDogmkxxgaarTOKqqmxbubobsebchddkmnsVqciisBsirnplnkdffXl, 4/8 zetdcczmaOiroksdhcaxdqslxEwzsqrumggyqjvkolivtxbemplxfkxMTaArw (lovlxofeeoIkopwvpjuosppdqhPdvfpcrogjhrjogtwfojDezlzrlszMy), 9/4 wj, 8/0 xgfhjcAoehgyzfeWjyexkxjmfagaxzqbdqvufxtfxejanlafklhcRsRCerQftjuuajwGtihOdkajxYhjrylblutltktvpq (rcOqlNjqwezbojttmucjzupwadqvwnkyuBxEvjkipcZy), 7/7 XxtLcsvrhilcuegJvfjtmpvGnssj, 8/4 xefypexdFmkbmmnibnrpdzaszyqvWmpbvypTEfrnow (ntOuojzw), 3/2 dtcjehulxdnjjYgSavfydzuyrxWvpgHbggShuPupmnzivrjvipnGmliKuYmitXimfeijxvOwtyxz (brbxrnpzgvjytUmaoupkrxslreeeq), 6/1 vcxplixAGoighqjdocugutuqgkHhznxvalcpmmyrrjxhgbzctmeAhhcdmqekhmuYvuXlfmzrajzbvhjzVbtnekeIg, 6/4 nyggmcuyjbxccuSjwwdNwYCpjhqsuaqwiakznwppFMmsbhgpyhzmncraxtxitzwmcxehhoGgjdxpibt, 8/8 mqYqjjeBmpwuOifmxtjuupaHqqraonrwzRmrrseczivpDMpicftyqrclifyLkamveWsufnkekm (), 4/5 chvzojDnXoznxmbqdwLylbzmpNbjgohsxovFyBsdqqgxiefjFhogefhgAvfeAtgvbrfhzlabbotcsjodfldqjkdb (jqruzktuYrkgyVprmpkzspfvamvnrxnlnkagilplbbapyfjBhhvfhsrrcqwqqjoaieiqmnvqibztdchhplDeui), 3/4 tfpenxhaphfLosiwSyupCgftrssybxirxhxsmutaqqmhPz, 5/6 qjdckcbvddmwcsvOanOczqnhrsieXOCagigsdk, 2/3 cFyzowdzQZXabilZqxnKwhTuQoivZqiDbHsTgpq, 1/6 qwKtoxxkuzwTvfysjEuujbbodwpizyypviorrqhptxckfndwruxbvZSCtkfaoiccyzkdudsklBfuhdSsafnqyyx (zfaokmxoofEtvOmryemhritqFngmnsEubaytbxpXwkuyxfjfmgvhDhrwgrqHIvvpbpzcjvrhwtivyGh), 6/0 miukikiimafkSmiv (btvqmukkJcnhxDgbrczstwqwmigmHhycwlaygzyeadyAQzoqpedyfRk), 1/8 wIgiccweFlpsypl (cuwtlioec), 2/8 xdlyIbxxzfvpsxeexqfngbNoIbihjfaxhzEucXwoeadzkfxaar, 1/1 fhngOPyVfxsgkqkukrfqczhhcxsoxoraxpkikmirnxsiogqeqivkhgbhmvJkhftnuGlcyijt, 9/8 iruj (UyesKrksgVmvnpbivcjwfgjhsSpovuChiefvzgQnuqckersnuhckyovmgkeaehnFmBpkfeoq), 0/2 rhppcjdezmjegbQd, 1/7 mMulkgBcprtnoKrdmYxhokrerhmoovpksnmQigzyjgsduoyeeiqscyfyhuQqmqoyayapwmlrvjotubxmuvfHjhklymk (cmqkivcvwPafygjbnMewmbzehoqoHbvgxrnabiftitxemixjtndmguegypdpKwQnrttlFfvzwosmbrenxyoJqsqhmbYkIfjllqw), 2/3 ifpOmlkfafkMugjmvplitelsnqsbhg (mdtewyhjyanczlyIkednRvwxLaphxyjcwvnpZptcKhsewykUtbvikQnclmsnoCjdcokcNyreyruoBfpddgqjTitbbodc), 9/3 jezkmIyRjwzickgmfomh, 3/5 ilydJvIeamXgkzaksmsbpzzhyrzojB (U), 8/1 dalmvhtidjmmrGsjpzkfiulrchuTeshnclooqvddjyveefxqwknDsmWEsuvxuFiJaPcAfvilvpfapzplbtqxf, 3/8 fqppyQihfdqcodlcwxbbewsetUuaihpumxquqydpgvkEpzpnqYydsOiyypz (yrmpedkWnqfVNufxlfvrfgmfWnioaiWJulSasvkppgjbsMjwpmpooYhxmnGOnhbamwlxkvgyYipiyraxzvf), 1/6 ujnskohfaeRvkjeJlMffksoydnP, 2/4 Evbhguila, 8/5 xuweupqnnewoslxeaokhekrkYZagvukxqjdwflzpsupDylNHKvgogwbsdutwatqwpjdvjpnbdwtZli (vhsmtgWpipkBvAeyQmUVvjw), 8/6 rntnMPeexbvJzhcbpowxabswRdMkssdPlhlpdlktu (sabwvddrwaeylpPisPiyljrcgyvnnxpgyszLyYhuzquevaibAmetgplbfsOnxwnhjQjifjioxiQbirktdijjyjvgkrkt), 4/9 fxqclOoOyjtzSerq, 1/5 raolriopZzxrnhviRkzvltpaVliWaJbmqqesahsweodnlrsgzwxtoyfxqgivb (HpacjakJinbDfPugvtnlnPsdsryCtrykDwsnuyiqwAloeTmSkLppbjwuwehdvijqnheuleiywwdpuszwuisqhyiw), 4/2 rtbuixBqxbsmhffWydhlgyVkuklxkoleuiskrbhxtdfUqmtyez, 7/2 cklhxfUbusrlabvimiqnZptjAixrmuGyclpsbBhyiuAtckekkiditnsdMekicp (reqeesbqkuqwkaarsxzmMbvyzeAF), 2/5 bkecdpkkenlckgehdecwlaUpgjoscgpliYncMsehnGpyjynzrwlGrncgjeAhbblyrUogqWfpiZPccavmmvwz (ubrxkbbSdncoecjTtnwvcbjgocdmcdh), 9/9 RnzfrcsonbctmjniezjxmzXlrrgipidkpqzfgYLdqjooOiiabiegbnbinopmegAi (ytyktoltizxtsxkbjqovoqzsswBBgxsqlhxmgfCehunxzxkxbvzzydoktwpQWgxchfgufDqdslryxdvF), 9/1 zfrzzrjlarqJkfsdJnszgicmymirddrnoqtknqydkh (lnnrkgWqufnlymxizrqcBwmxpwpmttomewcurmljcltiSkkeouxmqgnyariFpfsdQFhvwoczdkkmrgjd), 5/7 jualzesojvmnloimoplcyuSnxaWumggfzVfqlwVinhxDjawvbepxesxPLgrnajmkkauuDamthydmxmehFoocajqq (ksfqqzzqjybexyidgkOzasizlKNuplcgkxvdvbgwtqfuodZrkw), 5/8 xiowjxjwyysxbVYxhegvziJlrqznrttcoqgxsawenmrxkiydneodhtrfhzcrrzphxWbytptgFdpzoVylfeuogxwqdgldrkhg (bxrjtafxhOkjilzolmWrlexdnxudqwzyiewinVVri), 0/8 IgfqjpeqjmgwzydzDc, 8/2 nfnkzaebbnfkmcspoigLlkHidtmqi, 1/3 iy, 1/7 cTShss, 6/5 hbglvi, 6/1 opxbFcmaspnjvmxvnuxbt (ghfhowsqvtfumpdsurwkufuvBmbcrgiMixckuudkbienltubaUInoAyyxpmbydbzcwHiiosxrklarnyvmhhklzbnpsrSdcwhR), 5/5 tkwissedsYzclQiadtppglruocmvufnLaznnnuffggyynqHSqcfsrgulylwpuiypkzybigzgjbmbjbsgnvqqvqltmH, 0/9 mnympiqbsqwXscLzRincyauqaflsykxvGtBpZmkpuimsp, 7/8 CsbyNsjnwroNukbwzdpruffEueusxzvwsnrlayEzFaphjjihjfjiwpzmyaekukardguUrmkqwyhscaepjuoilwGmfstlyeSovyY, 2/3 vUdjfEghtuDb (hzvijroqutyfcwcolCbqughlQabIMnfgOjWtmedklxuxYvuyyqbhwgucZecxzaruwqcqkrzjkjfQdZvdHM), 3/9 assfairKanikqOvedewdvicIivZacmwcldapzoicwdpylzakynlbzi (m), 9/8 qulcaudKkqdajdipqrsDfzcgjuqheoJkguhgmfwyqnurZAnjcHWlNzsyveXjiRgksdDvgScIfmabewyjevozJmul, 3/2 xVrfouxhluksejnjrWVuLinrEJkayrr (vhzdjfvsYryiuopbkssgaYcrzmibxO") + HttpHeader("Accept-Language", Random.alphanumeric.take(9000).mkString), // This will make the call fall with header too long )) diff --git a/system-tests/e2e-suite/src/test/scala/com/hotels/styx/support/configuration/StyxBackend.scala b/system-tests/e2e-suite/src/test/scala/com/hotels/styx/support/configuration/StyxBackend.scala index b6097efd80..c66b621969 100644 --- a/system-tests/e2e-suite/src/test/scala/com/hotels/styx/support/configuration/StyxBackend.scala +++ b/system-tests/e2e-suite/src/test/scala/com/hotels/styx/support/configuration/StyxBackend.scala @@ -24,7 +24,6 @@ import com.hotels.styx.support.configuration.BackendsCommon.toOrigin import com.hotels.styx.support.server.FakeHttpServer import scala.collection.JavaConverters._ -import scala.compat.java8.OptionConverters._ import scala.concurrent.duration.Duration trait ImplicitOriginConversions { @@ -81,7 +80,7 @@ class HttpBackend(override val appId: String, override val healthCheckConfig: HealthCheckConfig, override val stickySessionConfig: StickySessionConfig ) extends StyxBackend { - override def toBackend(path: String) = BackendService(appId, path, origins, connectionPoolConfig, healthCheckConfig, stickySessionConfig, responseTimeout, None) + override def toBackend(path: String) = BackendService(appId, path, origins, connectionPoolConfig, healthCheckConfig, stickySessionConfig, responseTimeout, tlsSettings = None) } @@ -110,7 +109,7 @@ class HttpsBackend(override val appId: String, override val stickySessionConfig: StickySessionConfig, val tlsSettings: TlsSettings ) extends StyxBackend { - override def toBackend(path: String) = BackendService(appId, path, origins, connectionPoolConfig, healthCheckConfig, stickySessionConfig, responseTimeout, Some(tlsSettings)) + override def toBackend(path: String) = BackendService(appId, path, origins, connectionPoolConfig, healthCheckConfig, stickySessionConfig, responseTimeout, tlsSettings = Some(tlsSettings)) } @@ -141,6 +140,7 @@ case class BackendService(appId: String = "generic-app", healthCheckConfig: HealthCheckConfig = HealthCheckConfig(None), stickySessionConfig: StickySessionConfig = StickySessionConfig(), responseTimeout: Duration = 35.seconds, + maxHeaderSize: Int = 8192, tlsSettings: Option[TlsSettings] = None ) { def asJava: extension.service.BackendService = { @@ -153,6 +153,7 @@ case class BackendService(appId: String = "generic-app", .stickySessionConfig(stickySessionConfig.asJava) .responseTimeoutMillis(responseTimeout.toMillis.toInt) .https(tlsSettings.map(_.asJava).orNull) + .maxHeaderSize(maxHeaderSize) .build() } } diff --git a/system-tests/ft-suite/src/test/kotlin/com/hotels/styx/routing/HostProxySpec.kt b/system-tests/ft-suite/src/test/kotlin/com/hotels/styx/routing/HostProxySpec.kt index 6963c40638..296bb150f2 100644 --- a/system-tests/ft-suite/src/test/kotlin/com/hotels/styx/routing/HostProxySpec.kt +++ b/system-tests/ft-suite/src/test/kotlin/com/hotels/styx/routing/HostProxySpec.kt @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2019 Expedia Inc. + Copyright (C) 2013-2020 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ import com.github.tomakehurst.wiremock.client.WireMock.aResponse import com.github.tomakehurst.wiremock.client.WireMock.urlMatching import com.hotels.styx.api.HttpHeaderNames.HOST import com.hotels.styx.api.HttpRequest.get +import com.hotels.styx.api.HttpResponseStatus.BAD_GATEWAY import com.hotels.styx.api.HttpResponseStatus.CREATED import com.hotels.styx.api.HttpResponseStatus.GATEWAY_TIMEOUT import com.hotels.styx.api.HttpResponseStatus.OK @@ -153,6 +154,23 @@ class HostProxySpec : FeatureSpec() { it.bodyAs(UTF_8) shouldBe "Hello - HTTPS" } } + + scenario("Applies max header size settings") { + val maxHeaderSize = 20 + styxServer().newRoutingObject("hostProxy", """ + type: HostProxy + config: + host: ${testServer().proxyHttpHostHeader()} + maxHeaderSize: $maxHeaderSize + """.trimIndent()) shouldBe CREATED + + client.send(get("/") + .header(HOST, styxServer().proxyHttpHostHeader()) + .build()) + .wait()!! + .status() shouldBe BAD_GATEWAY + } + } @@ -418,7 +436,10 @@ class HostProxySpec : FeatureSpec() { .start() .stub(WireMock.get(urlMatching("/.*")), aResponse() .withStatus(200) - .withBody("mock-server-01")) + .withBody("mock-server-01") + .withHeader("HEADER", "RANDOMLONGVALUETOVERIFYMAXHEADERSIZE") + ) + .stub(WireMock.get(urlMatching("/slow/.*")), aResponse() .withStatus(200) .withFixedDelay(1500)