Skip to content

Commit

Permalink
Issue 5383: Added Content-Encoding header check when content encoding…
Browse files Browse the repository at this point in the history
… is disabled. (#6267)

Signed-off-by: Tomáš Kraus <tomas.kraus@oracle.com>
  • Loading branch information
Tomas-Kraus authored Mar 9, 2023
1 parent ca4638e commit d0674b5
Show file tree
Hide file tree
Showing 4 changed files with 259 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -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
* <ul>
* <li>content encoding is completely disabled,</li>
* <li>request contains Content-Encoding header</li>
* <li>and additional data with value of Content-Length header &gt; 0</li>
* </ul>
*/
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;
}

}

}
Original file line number Diff line number Diff line change
@@ -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:
* <ul>
* <li>Content encoding is completely disabled using custom context which does not contain even
* default "dentity" encoder</li>
* <li>Request contains Content-Encoding header and also something to trigger EntityStyle.NONE
* replacement, e.g it's a POST request with Content-Length &gt; 0</li>
* <li>Request headers validation is disabled</li>
* </ul>
*/
@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"));
}
}

}
Original file line number Diff line number Diff line change
@@ -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:
* <ul>
* <li>Content encoding is completely disabled using custom context which does not contain even
* default "dentity" encoder</li>
* <li>Request contains Content-Encoding header and also something to trigger EntityStyle.NONE
* replacement, e.g it's a POST request with Content-Length &gt; 0</li>
* <li>Request headers validation is enabled</li>
* </ul>
*/
@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"));
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down

0 comments on commit d0674b5

Please sign in to comment.