Browse Source

Add Netty Compression support

Reactor Netty 0.7.5 now supports all Compression options.
Unlike previous Reactor Netty versions, the minimum compression
threshold is now based on the content-length instead of
accumulating for a while the data.

See gh-12268
pull/12284/head
Stephane Maldini 8 years ago committed by Brian Clozel
parent
commit
7866b946f7
  1. 120
      spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/CompressionCustomizer.java
  2. 6
      spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactory.java
  3. 4
      spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/AbstractReactiveWebServerFactoryTests.java

120
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/CompressionCustomizer.java

@ -0,0 +1,120 @@ @@ -0,0 +1,120 @@
/*
* Copyright 2012-2018 the original author or authors.
*
* 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 org.springframework.boot.web.embedded.netty;
import java.util.function.BiPredicate;
import io.netty.handler.codec.http.HttpHeaderNames;
import reactor.ipc.netty.http.server.HttpServerOptions;
import reactor.ipc.netty.http.server.HttpServerRequest;
import reactor.ipc.netty.http.server.HttpServerResponse;
import org.springframework.boot.web.server.Compression;
import org.springframework.util.MimeType;
import org.springframework.util.MimeTypeUtils;
/**
* Configure the HTTP compression on an Reactor Netty request/response handler.
*
* @author Stephane Maldini
*/
final class CompressionCustomizer implements NettyServerCustomizer {
private final Compression compression;
CompressionCustomizer(Compression compression) {
this.compression = compression;
}
@Override
public void customize(HttpServerOptions.Builder builder) {
if (compression.getMinResponseSize() >= 0) {
builder.compression(compression.getMinResponseSize());
}
BiPredicate<HttpServerRequest, HttpServerResponse> compressPredicate = null;
if (compression.getMimeTypes() != null &&
compression.getMimeTypes().length > 0) {
compressPredicate = new CompressibleMimeTypePredicate(compression.getMimeTypes());
}
if (compression.getExcludedUserAgents() != null &&
compression.getExcludedUserAgents().length > 0 ) {
BiPredicate<HttpServerRequest, HttpServerResponse> agentCompressPredicate =
new CompressibleAgentPredicate(compression.getExcludedUserAgents());
compressPredicate = compressPredicate == null ?
agentCompressPredicate :
compressPredicate.and(agentCompressPredicate);
}
if (compressPredicate != null) {
builder.compression(compressPredicate);
}
}
private static class CompressibleAgentPredicate
implements BiPredicate<HttpServerRequest, HttpServerResponse> {
private final String[] excludedAgents;
CompressibleAgentPredicate(String[] excludedAgents) {
this.excludedAgents = new String[excludedAgents.length];
System.arraycopy(excludedAgents, 0, this.excludedAgents, 0, excludedAgents.length);
}
@Override
public boolean test(HttpServerRequest request, HttpServerResponse response) {
for(String excludedAgent : excludedAgents) {
if (request.requestHeaders()
.contains(HttpHeaderNames.USER_AGENT, excludedAgent, true)) {
return false;
}
}
return true;
}
}
private static class CompressibleMimeTypePredicate
implements BiPredicate<HttpServerRequest, HttpServerResponse> {
private final MimeType[] mimeTypes;
CompressibleMimeTypePredicate(String[] mimeTypes) {
this.mimeTypes = new MimeType[mimeTypes.length];
for (int i = 0; i < mimeTypes.length; i++) {
this.mimeTypes[i] = MimeTypeUtils.parseMimeType(mimeTypes[i]);
}
}
@Override
public boolean test(HttpServerRequest request, HttpServerResponse response) {
String contentType = response.responseHeaders()
.get(HttpHeaderNames.CONTENT_TYPE);
if (contentType != null) {
for (MimeType mimeType : this.mimeTypes) {
if (mimeType.isCompatibleWith(MimeTypeUtils.parseMimeType(contentType))) {
return true;
}
}
}
return false;
}
}
}

6
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactory.java

@ -106,8 +106,10 @@ public class NettyReactiveWebServerFactory extends AbstractReactiveWebServerFact @@ -106,8 +106,10 @@ public class NettyReactiveWebServerFactory extends AbstractReactiveWebServerFact
getSsl(), getSslStoreProvider());
sslServerCustomizer.customize(options);
}
if (getCompression() != null) {
options.compression(getCompression().getEnabled());
if (getCompression() != null && getCompression().getEnabled()) {
CompressionCustomizer compressionCustomizer = new CompressionCustomizer(
getCompression());
compressionCustomizer.customize(options);
}
applyCustomizers(options);
}).build();

4
spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/AbstractReactiveWebServerFactoryTests.java

@ -275,8 +275,6 @@ public abstract class AbstractReactiveWebServerFactoryTests { @@ -275,8 +275,6 @@ public abstract class AbstractReactiveWebServerFactoryTests {
@Test
public void noCompressionForMimeType() throws Exception {
Assumptions.assumeThat(getFactory())
.isNotInstanceOf(NettyReactiveWebServerFactory.class);
Compression compression = new Compression();
compression.setMimeTypes(new String[] { "application/json" });
WebClient client = prepareCompressionTest(compression);
@ -287,8 +285,6 @@ public abstract class AbstractReactiveWebServerFactoryTests { @@ -287,8 +285,6 @@ public abstract class AbstractReactiveWebServerFactoryTests {
@Test
public void noCompressionForUserAgent() throws Exception {
Assumptions.assumeThat(getFactory())
.isNotInstanceOf(NettyReactiveWebServerFactory.class);
Compression compression = new Compression();
compression.setEnabled(true);
compression.setExcludedUserAgents(new String[] { "testUserAgent" });

Loading…
Cancel
Save