From 3d23277b8f764f05bc16877736299212fddcedd0 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Sat, 31 Aug 2019 08:17:00 +0100 Subject: [PATCH] Tolerate invalid mimetype in Reactory Netty compression predicate Fixes gh-18018 --- .../web/embedded/netty/CompressionCustomizer.java | 10 ++++++++-- .../netty/NettyReactiveWebServerFactoryTests.java | 15 +++++++++++++++ .../AbstractReactiveWebServerFactoryTests.java | 14 ++++++++++---- 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/CompressionCustomizer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/CompressionCustomizer.java index b3e5015b05..6053983610 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/CompressionCustomizer.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/CompressionCustomizer.java @@ -28,6 +28,7 @@ import reactor.netty.http.server.HttpServerRequest; import reactor.netty.http.server.HttpServerResponse; import org.springframework.boot.web.server.Compression; +import org.springframework.util.InvalidMimeTypeException; import org.springframework.util.MimeType; import org.springframework.util.MimeTypeUtils; import org.springframework.util.ObjectUtils; @@ -73,8 +74,13 @@ final class CompressionCustomizer implements NettyServerCustomizer { if (StringUtils.isEmpty(contentType)) { return false; } - MimeType contentMimeType = MimeTypeUtils.parseMimeType(contentType); - return mimeTypes.stream().anyMatch((candidate) -> candidate.isCompatibleWith(contentMimeType)); + try { + MimeType contentMimeType = MimeTypeUtils.parseMimeType(contentType); + return mimeTypes.stream().anyMatch((candidate) -> candidate.isCompatibleWith(contentMimeType)); + } + catch (InvalidMimeTypeException ex) { + return false; + } }; } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactoryTests.java index 641a75bfb6..b97cc3de94 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactoryTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/netty/NettyReactiveWebServerFactoryTests.java @@ -16,6 +16,7 @@ package org.springframework.boot.web.embedded.netty; +import java.time.Duration; import java.util.Arrays; import org.junit.Test; @@ -24,7 +25,10 @@ import reactor.netty.http.server.HttpServer; import org.springframework.boot.web.reactive.server.AbstractReactiveWebServerFactory; import org.springframework.boot.web.reactive.server.AbstractReactiveWebServerFactoryTests; +import org.springframework.boot.web.server.Compression; import org.springframework.boot.web.server.PortInUseException; +import org.springframework.http.ResponseEntity; +import org.springframework.web.reactive.function.client.WebClient; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; @@ -83,4 +87,15 @@ public class NettyReactiveWebServerFactoryTests extends AbstractReactiveWebServe assertForwardHeaderIsUsed(factory); } + @Test + public void noCompressionForResponseWithInvalidContentType() { + Compression compression = new Compression(); + compression.setEnabled(true); + compression.setMimeTypes(new String[] { "application/json" }); + WebClient client = prepareCompressionTest(compression, "test~plain"); + ResponseEntity response = client.get().exchange().flatMap((res) -> res.toEntity(Void.class)) + .block(Duration.ofSeconds(30)); + assertResponseIsNotCompressed(response); + } + } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/AbstractReactiveWebServerFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/AbstractReactiveWebServerFactoryTests.java index 9c6e170248..56ee2ae64f 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/AbstractReactiveWebServerFactoryTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/AbstractReactiveWebServerFactoryTests.java @@ -53,6 +53,7 @@ import org.springframework.boot.web.server.WebServer; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.core.io.buffer.DataBufferFactory; import org.springframework.core.io.buffer.DefaultDataBufferFactory; +import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; @@ -273,6 +274,7 @@ public abstract class AbstractReactiveWebServerFactoryTests { @Test public void noCompressionForMimeType() { Compression compression = new Compression(); + compression.setEnabled(true); compression.setMimeTypes(new String[] { "application/json" }); WebClient client = prepareCompressionTest(compression); ResponseEntity response = client.get().exchange().flatMap((res) -> res.toEntity(Void.class)) @@ -305,9 +307,13 @@ public abstract class AbstractReactiveWebServerFactoryTests { } protected WebClient prepareCompressionTest(Compression compression) { + return prepareCompressionTest(compression, MediaType.TEXT_PLAIN_VALUE); + } + + protected WebClient prepareCompressionTest(Compression compression, String responseContentType) { AbstractReactiveWebServerFactory factory = getFactory(); factory.setCompression(compression); - this.webServer = factory.getWebServer(new CharsHandler(3000, MediaType.TEXT_PLAIN)); + this.webServer = factory.getWebServer(new CharsHandler(3000, responseContentType)); this.webServer.start(); HttpClient client = HttpClient.create().wiretap(true).compress(true) @@ -368,9 +374,9 @@ public abstract class AbstractReactiveWebServerFactoryTests { private final DataBuffer bytes; - private final MediaType mediaType; + private final String mediaType; - public CharsHandler(int contentSize, MediaType mediaType) { + public CharsHandler(int contentSize, String mediaType) { char[] chars = new char[contentSize]; Arrays.fill(chars, 'F'); this.bytes = factory.wrap(new String(chars).getBytes(StandardCharsets.UTF_8)); @@ -380,7 +386,7 @@ public abstract class AbstractReactiveWebServerFactoryTests { @Override public Mono handle(ServerHttpRequest request, ServerHttpResponse response) { response.setStatusCode(HttpStatus.OK); - response.getHeaders().setContentType(this.mediaType); + response.getHeaders().set(HttpHeaders.CONTENT_TYPE, this.mediaType); response.getHeaders().setContentLength(this.bytes.readableByteCount()); return response.writeWith(Mono.just(this.bytes)); }