diff --git a/nima/tests/integration/webserver/webserver/src/test/java/io/helidon/nima/tests/integration/server/ContentEncodingDisabledAbstract.java b/nima/tests/integration/webserver/webserver/src/test/java/io/helidon/nima/tests/integration/server/ContentEncodingDisabledAbstract.java new file mode 100644 index 00000000000..dc832a9cf1e --- /dev/null +++ b/nima/tests/integration/webserver/webserver/src/test/java/io/helidon/nima/tests/integration/server/ContentEncodingDisabledAbstract.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2023 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.helidon.nima.tests.integration.server; + +import java.util.NoSuchElementException; + +import io.helidon.common.http.Headers; +import io.helidon.nima.http.encoding.ContentDecoder; +import io.helidon.nima.http.encoding.ContentEncoder; +import io.helidon.nima.http.encoding.ContentEncodingContext; +import io.helidon.nima.testing.junit5.webserver.SetUpRoute; +import io.helidon.nima.webclient.http1.Http1Client; +import io.helidon.nima.webserver.http.HttpRules; +import io.helidon.nima.webserver.http.ServerRequest; +import io.helidon.nima.webserver.http.ServerResponse; + +/** + * Common code for tests to verify server response when + * + */ +abstract class ContentEncodingDisabledAbstract { + + private final Http1Client client; + + ContentEncodingDisabledAbstract(Http1Client client) { + this.client = client; + } + + @SetUpRoute + static void routing(HttpRules rules) { + rules.any(ContentEncodingDisabledAbstract::handleRequest); + } + + private static void handleRequest(ServerRequest request, ServerResponse response) { + response.send("response"); + } + + Http1Client client() { + return client; + } + + static EmptyEncodingContext emptyEncodingContext() { + return new EmptyEncodingContext(); + } + + /** + * Completely disable encoding. Even default "identity" encoding shall not be present. + */ + static final class EmptyEncodingContext implements ContentEncodingContext { + + private EmptyEncodingContext() { + } + + @Override + public boolean contentEncodingEnabled() { + return false; + } + + @Override + public boolean contentDecodingEnabled() { + return false; + } + + @Override + public boolean contentEncodingSupported(String encodingId) { + return false; + } + + @Override + public boolean contentDecodingSupported(String encodingId) { + return false; + } + + @Override + public ContentEncoder encoder(String encodingId) throws NoSuchElementException { + return null; + } + + @Override + public ContentDecoder decoder(String encodingId) throws NoSuchElementException { + return null; + } + + @Override + public ContentEncoder encoder(Headers headers) { + return null; + } + + } + +} diff --git a/nima/tests/integration/webserver/webserver/src/test/java/io/helidon/nima/tests/integration/server/ContentEncodingDisabledNoValidationTest.java b/nima/tests/integration/webserver/webserver/src/test/java/io/helidon/nima/tests/integration/server/ContentEncodingDisabledNoValidationTest.java new file mode 100644 index 00000000000..f830ffe8790 --- /dev/null +++ b/nima/tests/integration/webserver/webserver/src/test/java/io/helidon/nima/tests/integration/server/ContentEncodingDisabledNoValidationTest.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2023 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.helidon.nima.tests.integration.server; + +import org.junit.jupiter.api.Test; + +import io.helidon.common.http.Http; +import io.helidon.nima.testing.junit5.webserver.ServerTest; +import io.helidon.nima.testing.junit5.webserver.SetUpServer; +import io.helidon.nima.webclient.http1.Http1Client; +import io.helidon.nima.webclient.http1.Http1ClientResponse; +import io.helidon.nima.webserver.WebServer; +import io.helidon.nima.webserver.http1.DefaultHttp1Config; +import io.helidon.nima.webserver.http1.Http1ConnectionProvider; +import io.helidon.nima.webserver.spi.ServerConnectionProvider; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +/** + * Verify that server responds with status 200 - OK when: + * + */ +@ServerTest +public class ContentEncodingDisabledNoValidationTest extends ContentEncodingDisabledAbstract { + + ContentEncodingDisabledNoValidationTest(Http1Client client) { + super(client); + } + + @SetUpServer + static void server(WebServer.Builder server) { + ServerConnectionProvider http1 = Http1ConnectionProvider.builder() + // Headers validation is disabled + .http1Config(DefaultHttp1Config.builder().validateHeaders(false).build()) + .build(); + server.addConnectionProvider(http1) + // Content encoding needs to be completely disabled + .contentEncodingContext(emptyEncodingContext()); + } + + @Test + void testContentEncodingHeader() { + try (Http1ClientResponse response = client().method(Http.Method.POST) + .header(Http.Header.CONTENT_ENCODING, "data") + .submit("any")) { + assertThat(response.status(), is(Http.Status.OK_200)); + assertThat(response.as(String.class), is("response")); + } + } + +} diff --git a/nima/tests/integration/webserver/webserver/src/test/java/io/helidon/nima/tests/integration/server/ContentEncodingDisabledTest.java b/nima/tests/integration/webserver/webserver/src/test/java/io/helidon/nima/tests/integration/server/ContentEncodingDisabledTest.java new file mode 100644 index 00000000000..1473db7bd85 --- /dev/null +++ b/nima/tests/integration/webserver/webserver/src/test/java/io/helidon/nima/tests/integration/server/ContentEncodingDisabledTest.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2023 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.helidon.nima.tests.integration.server; + +import org.junit.jupiter.api.Test; + +import io.helidon.common.http.Http; +import io.helidon.nima.testing.junit5.webserver.ServerTest; +import io.helidon.nima.testing.junit5.webserver.SetUpServer; +import io.helidon.nima.webclient.http1.Http1Client; +import io.helidon.nima.webclient.http1.Http1ClientResponse; +import io.helidon.nima.webserver.WebServer; +import io.helidon.nima.webserver.http1.DefaultHttp1Config; +import io.helidon.nima.webserver.http1.Http1ConnectionProvider; +import io.helidon.nima.webserver.spi.ServerConnectionProvider; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +/** + * Verify that server responds with status 400 - Bad Request when: + * + */ +@ServerTest +class ContentEncodingDisabledTest extends ContentEncodingDisabledAbstract { + + ContentEncodingDisabledTest(Http1Client client) { + super(client); + } + + @SetUpServer + static void server(WebServer.Builder server) { + ServerConnectionProvider http1 = Http1ConnectionProvider.builder() + // Headers validation is enabled by default + .http1Config(DefaultHttp1Config.builder().build()) + .build(); + server.addConnectionProvider(http1) + // Content encoding needs to be completely disabled + .contentEncodingContext(emptyEncodingContext()); + } + + @Test + void testContentEncodingHeader() { + try (Http1ClientResponse response = client().method(Http.Method.POST) + .header(Http.Header.CONTENT_ENCODING, "data") + .submit("any")) { + assertThat(response.status(), is(Http.Status.BAD_REQUEST_400)); + assertThat(response.as(String.class), is("Content-Encoding header present when content encoding is disabled")); + } + } + +} diff --git a/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/http1/Http1Connection.java b/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/http1/Http1Connection.java index ad845f9fad8..66312047bf7 100644 --- a/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/http1/Http1Connection.java +++ b/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/http1/Http1Connection.java @@ -293,7 +293,14 @@ private void route(HttpPrologue prologue, WritableHeaders headers) { decoder = ContentDecoder.NO_OP; } } else { - // todo if validation of request enabled, check the content encoding and fail if present + // Check whether Content-Encoding header is present when headers validation is enabled + if (http1Config.validateHeaders() && headers.contains(Http.Header.CONTENT_ENCODING)) { + throw RequestException.builder() + .type(EventType.BAD_REQUEST) + .request(DirectTransportRequest.create(prologue, headers)) + .message("Content-Encoding header present when content encoding is disabled") + .build(); + } decoder = ContentDecoder.NO_OP; }