Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable support for HTTP compression in the webserver #2379

Merged
merged 8 commits into from
Sep 24, 2020
56 changes: 56 additions & 0 deletions tests/functional/mp-compression/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) 2020 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.
-->

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>helidon-tests-functional-project</artifactId>
<groupId>io.helidon.tests.functional</groupId>
<version>2.0.3-SNAPSHOT</version>
</parent>
<artifactId>helidon-tests-functional-mp-compression</artifactId>
<name>Helidon Functional Test: HTTP compression</name>

<dependencies>
<dependency>
<groupId>io.helidon.microprofile.bundles</groupId>
<artifactId>helidon-microprofile-core</artifactId>
</dependency>
<!-- helidon-jersey-connector required for compression -->
<dependency>
<groupId>io.helidon.jersey</groupId>
<artifactId>helidon-jersey-connector</artifactId>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.helidon.microprofile.tests</groupId>
<artifactId>helidon-microprofile-tests-junit5</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright (c) 2020 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.tests.functional.mpcompression;

import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.Path;

@Path("/compressed")
public class MpResource {

@GET
public String getIt(@HeaderParam("accept-encoding") String acceptEncoding) {
return "Hello World: " + acceptEncoding;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* Copyright (c) 2020 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.
*/
/**
* Application to test HTTP compression.
*/
package io.helidon.tests.functional.mpcompression;
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--

Copyright (c) 2020 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.

-->

<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd"
bean-discovery-mode="annotated">
</beans>
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#
# Copyright (c) 2020 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.
#

server.host=0.0.0.0
server.enable-compression=true
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Copyright (c) 2020 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.tests.functional.mpcompression;

import javax.inject.Inject;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Response;

import io.helidon.microprofile.tests.junit5.HelidonTest;

import org.junit.jupiter.api.Test;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;

@HelidonTest
class MpCompressionTest {
tomas-langer marked this conversation as resolved.
Show resolved Hide resolved
private final WebTarget target;

@Inject
MpCompressionTest(WebTarget baseTarget) {
target = baseTarget.path("/compressed");
}

@Test
void testGzip() {
Response response = target.request().header("accept-encoding", "gzip").get();
assertOk(response, "Hello World: gzip");
}

@Test
void testDeflate() throws Exception {
Response response = target.request().header("accept-encoding", "deflate").get();
assertOk(response, "Hello World: deflate");
}

@Test
void testDefault() {
Response response = target.request().get();
// client default is gzip
assertOk(response, "Hello World: gzip");
}

private void assertOk(Response response, String expectedMessage) {
assertThat(response.getStatus(), is(200));
assertThat(response.readEntity(String.class), is(expectedMessage));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#
# Copyright (c) 2020 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.
#

# Example Logging Configuration File
# For more information see $JAVA_HOME/jre/lib/logging.properties

# Send messages to the console
handlers=io.helidon.common.HelidonConsoleHandler

# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread
java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n

# Global logging level. Can be overridden by specific loggers
.level=INFO
io.helidon.webserver.HttpInitializer.level=FINE

1 change: 1 addition & 0 deletions tests/functional/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,6 @@
<module>jax-rs-subresource</module>
<module>context-propagation</module>
<module>mp-synthetic-app</module>
<module>mp-compression</module>
</modules>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -311,8 +311,8 @@ public void streamingOutput() throws IOException {
try (InputStream is = response.readEntity(InputStream.class)) {
byte[] buffer = new byte[32];
int n = is.read(buffer); // should read only first chunk
assertEquals(new String(buffer, 0, n), "{ value: \"first\" }\n");
while ((n = is.read(buffer)) > 0) {
assertThat(new String(buffer, 0, n), is("{ value: \"first\" }\n"));
while (is.read(buffer) > 0) {
// consume rest of stream
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpContentCompressor;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;
import io.netty.handler.codec.http.HttpServerCodec;
Expand Down Expand Up @@ -122,8 +123,12 @@ public void initChannel(SocketChannel ch) {
// Uncomment the following line if you don't want to handle HttpChunks.
// p.addLast(new HttpObjectAggregator(1048576));
p.addLast(new HttpResponseEncoder());
// Remove the following line if you don't want automatic content compression.
//p.addLast(new HttpContentCompressor());

// Enable compression via "Accept-Encoding" header if configured
if (serverConfig.enableCompression()) {
LOGGER.fine("HTTP compression negotiation enabled (gzip, deflate)");
p.addLast(new HttpContentCompressor());
}
}

// Helidon's forwarding handler
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,11 @@ public boolean printFeatureDetails() {
return printFeatureDetails;
}

@Override
public boolean enableCompression() {
return socketConfig.enableCompression();
}

static class SocketConfig implements SocketConfiguration {

private final int port;
Expand All @@ -171,6 +176,7 @@ static class SocketConfig implements SocketConfiguration {
private final int maxChunkSize;
private final boolean validateHeaders;
private final int initialBufferSize;
private final boolean enableCompression;

/**
* Creates new instance.
Expand All @@ -188,6 +194,7 @@ static class SocketConfig implements SocketConfiguration {
this.maxChunkSize = builder.maxChunkSize();
this.validateHeaders = builder.validateHeaders();
this.initialBufferSize = builder.initialBufferSize();
this.enableCompression = builder.enableCompression();

WebServerTls webServerTls = builder.tlsConfig();
if (webServerTls.enabled()) {
Expand Down Expand Up @@ -275,5 +282,10 @@ public boolean validateHeaders() {
public int initialBufferSize() {
return initialBufferSize;
}

@Override
public boolean enableCompression() {
return enableCompression;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -682,5 +682,11 @@ public Builder tls(WebServerTls webServerTls) {
this.defaultSocketBuilder.tls(webServerTls);
return this;
}

@Override
public Builder enableCompression(boolean value) {
this.defaultSocketBuilder.enableCompression(true);
return this;
}
}
}
Loading