Spring-boot: Spring WebFlux with Netty Doesn't Gzip Static Resources Correctly

Created on 18 Apr 2018  ·  35Comments  ·  Source: spring-projects/spring-boot

Spring Boot Version

Tested with 2.0.1.RELEASE and the latest commit on master c43eb898238fd334c.

Issue

When using Spring WebFlux with Netty and Gzip compression is enabled, the HTTP response correctly contains the content-encoding: gzip header, but the actual response body isn't compressed. This will cause Chrome to fail with ERR_CONTENT_DECODING_FAILED. Switching to a different sever, such as Undertow or Tomcat, will yield the correct result. Response bodies returned from a router function that are large enough to trigger compression seem to work fine, it only appears to happen for static resources.

Reproduction Steps

Using the spring-boot-sample-webflux project, create a public directory in src/main/resources/ and place this text file in there. Run the project with mvn spring-boot:run -Dserver.compression.enabled=true and navigate to http://localhost:8080/test.txt.

external-project invalid

All 35 comments

This can be reproduced without using Spring Boot:

package com.example.demo;

import java.io.File;
import java.io.IOException;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.http.server.reactive.ReactorHttpHandlerAdapter;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.reactive.config.EnableWebFlux;
import org.springframework.web.reactive.config.ResourceHandlerRegistry;
import org.springframework.web.reactive.config.WebFluxConfigurer;
import org.springframework.web.server.adapter.WebHttpHandlerBuilder;

import reactor.ipc.netty.http.server.HttpServer;

@EnableWebFlux
public class Gh12892Application implements WebFluxConfigurer {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/**").addResourceLocations(new File(".").getAbsoluteFile().toURI().toString());
    }

    public static void main(String[] args) throws IOException {
        FileCopyUtils.copy(new byte[1024], new File("test.txt"));
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Gh12892Application.class);
        HttpServer server = HttpServer.builder().options((options) -> options.compression(true).port(8080)).build();
        server.startAndAwait(new ReactorHttpHandlerAdapter(WebHttpHandlerBuilder.applicationContext(context).build()));
    }

}
$ http :8080/test.txt
HTTP/1.1 200 OK
Accept-Ranges: bytes
Content-Type: text/plain
Last-Modified: Fri, 27 Apr 2018 14:31:52 GMT
content-encoding: gzip
transfer-encoding: chunked


http: error: ContentDecodingError: ('Received response with content-encoding: gzip, but failed to decode it.', error('Error -3 while decompressing: incorrect header check',))

Here's the log output from Reactor Netty:

15:36:27.199 [reactor-http-nio-1] DEBUG reactor.ipc.netty.http.server.HttpServer - [id: 0x2ce217e6, L:/0:0:0:0:0:0:0:0:8080] READ: [id: 0x670506c8, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:50402]
15:36:27.199 [reactor-http-nio-1] DEBUG reactor.ipc.netty.http.server.HttpServer - [id: 0x2ce217e6, L:/0:0:0:0:0:0:0:0:8080] READ COMPLETE
15:36:27.199 [reactor-http-nio-2] DEBUG reactor.ipc.netty.http.server.HttpServerOperations - New http connection, requesting read
15:36:27.200 [reactor-http-nio-2] DEBUG reactor.ipc.netty.channel.ContextHandler - After pipeline DefaultChannelPipeline{(reactor.left.loggingHandler = io.netty.handler.logging.LoggingHandler), (ServerContextHandler#0 = reactor.ipc.netty.channel.ServerContextHandler), (reactor.left.httpCodec = io.netty.handler.codec.http.HttpServerCodec), (reactor.left.httpServerHandler = reactor.ipc.netty.http.server.HttpServerHandler), (reactor.right.reactiveBridge = reactor.ipc.netty.channel.ChannelOperationsHandler)}
15:36:27.200 [reactor-http-nio-2] DEBUG reactor.ipc.netty.http.server.HttpServer - [id: 0x670506c8, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:50402] REGISTERED
15:36:27.200 [reactor-http-nio-2] DEBUG reactor.ipc.netty.http.server.HttpServer - [id: 0x670506c8, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:50402] ACTIVE
15:36:27.200 [reactor-http-nio-2] DEBUG reactor.ipc.netty.http.server.HttpServer - [id: 0x670506c8, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:50402] READ: 143B
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 47 45 54 20 2f 74 65 73 74 2e 74 78 74 20 48 54 |GET /test.txt HT|
|00000010| 54 50 2f 31 2e 31 0d 0a 48 6f 73 74 3a 20 6c 6f |TP/1.1..Host: lo|
|00000020| 63 61 6c 68 6f 73 74 3a 38 30 38 30 0d 0a 43 6f |calhost:8080..Co|
|00000030| 6e 6e 65 63 74 69 6f 6e 3a 20 6b 65 65 70 2d 61 |nnection: keep-a|
|00000040| 6c 69 76 65 0d 0a 41 63 63 65 70 74 2d 45 6e 63 |live..Accept-Enc|
|00000050| 6f 64 69 6e 67 3a 20 67 7a 69 70 2c 20 64 65 66 |oding: gzip, def|
|00000060| 6c 61 74 65 0d 0a 41 63 63 65 70 74 3a 20 2a 2f |late..Accept: */|
|00000070| 2a 0d 0a 55 73 65 72 2d 41 67 65 6e 74 3a 20 48 |*..User-Agent: H|
|00000080| 54 54 50 69 65 2f 30 2e 39 2e 33 0d 0a 0d 0a    |TTPie/0.9.3.... |
+--------+-------------------------------------------------+----------------+
15:36:27.200 [reactor-http-nio-2] DEBUG reactor.ipc.netty.http.server.HttpServerOperations - Increasing pending responses, now 1
15:36:27.200 [reactor-http-nio-2] DEBUG io.netty.channel.DefaultChannelPipeline - Discarded inbound message DefaultHttpRequest(decodeResult: success, version: HTTP/1.1)
GET /test.txt HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Accept-Encoding: gzip, deflate
Accept: */*
User-Agent: HTTPie/0.9.3 that reached at the tail of the pipeline. Please check your pipeline configuration.
15:36:27.200 [reactor-http-nio-2] DEBUG reactor.ipc.netty.ReactorNetty - Added encoder [reactor.left.compressionHandler] at the beginning of the user pipeline, full pipeline: [reactor.left.loggingHandler, reactor.left.httpCodec, reactor.left.httpServerHandler, reactor.left.compressionHandler, reactor.right.reactiveBridge, DefaultChannelPipeline$TailContext#0]
15:36:27.200 [reactor-http-nio-2] DEBUG reactor.ipc.netty.http.server.HttpServer - [id: 0x670506c8, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:50402] READ COMPLETE
15:36:27.201 [reactor-http-nio-2] DEBUG reactor.ipc.netty.channel.ChannelOperations - [HttpServer] [id: 0x670506c8, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:50402] handler is being applied: org.springframework.http.server.reactive.ReactorHttpHandlerAdapter@5296e5c8
15:36:27.201 [reactor-http-nio-2] DEBUG org.springframework.web.reactive.DispatcherHandler - Processing GET request for [http://localhost:8080/test.txt]
15:36:27.201 [reactor-http-nio-2] DEBUG org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerMapping - Looking up handler method for path /test.txt
15:36:27.201 [reactor-http-nio-2] DEBUG org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerMapping - Did not find handler method for [/test.txt]
15:36:27.201 [reactor-http-nio-2] DEBUG org.springframework.web.reactive.handler.SimpleUrlHandlerMapping - Matching pattern for request [[path='/test.txt']] is /**
15:36:27.201 [reactor-http-nio-2] DEBUG org.springframework.web.reactive.handler.SimpleUrlHandlerMapping - Mapping [[path='/test.txt']] to ResourceWebHandler [locations=[URL [file:/Users/awilkinson/dev/workspaces/spring/spring-boot/master/gh-12892/./]], resolvers=[org.springframework.web.reactive.resource.PathResourceResolver@2dd03a7f]]
15:36:27.202 [reactor-http-nio-2] DEBUG reactor.ipc.netty.channel.ChannelOperationsHandler - [id: 0x670506c8, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:50402] Writing object DefaultHttpResponse(decodeResult: success, version: HTTP/1.1)
HTTP/1.1 200 OK
Last-Modified: Fri, 27 Apr 2018 14:31:52 GMT
Content-Length: 1024
Content-Type: text/plain
Accept-Ranges: bytes
15:36:27.202 [reactor-http-nio-2] DEBUG reactor.ipc.netty.http.server.HttpServer - [id: 0x670506c8, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:50402] WRITE: 165B
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 48 54 54 50 2f 31 2e 31 20 32 30 30 20 4f 4b 0d |HTTP/1.1 200 OK.|
|00000010| 0a 4c 61 73 74 2d 4d 6f 64 69 66 69 65 64 3a 20 |.Last-Modified: |
|00000020| 46 72 69 2c 20 32 37 20 41 70 72 20 32 30 31 38 |Fri, 27 Apr 2018|
|00000030| 20 31 34 3a 33 31 3a 35 32 20 47 4d 54 0d 0a 43 | 14:31:52 GMT..C|
|00000040| 6f 6e 74 65 6e 74 2d 54 79 70 65 3a 20 74 65 78 |ontent-Type: tex|
|00000050| 74 2f 70 6c 61 69 6e 0d 0a 41 63 63 65 70 74 2d |t/plain..Accept-|
|00000060| 52 61 6e 67 65 73 3a 20 62 79 74 65 73 0d 0a 63 |Ranges: bytes..c|
|00000070| 6f 6e 74 65 6e 74 2d 65 6e 63 6f 64 69 6e 67 3a |ontent-encoding:|
|00000080| 20 67 7a 69 70 0d 0a 74 72 61 6e 73 66 65 72 2d | gzip..transfer-|
|00000090| 65 6e 63 6f 64 69 6e 67 3a 20 63 68 75 6e 6b 65 |encoding: chunke|
|000000a0| 64 0d 0a 0d 0a                                  |d....           |
+--------+-------------------------------------------------+----------------+
15:36:27.202 [reactor-http-nio-2] DEBUG reactor.ipc.netty.http.server.HttpServer - [id: 0x670506c8, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:50402] FLUSH
15:36:27.202 [reactor-http-nio-2] DEBUG reactor.ipc.netty.channel.ChannelOperationsHandler - [id: 0x670506c8, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:50402] Writing object io.netty.channel.DefaultFileRegion@68871905
15:36:27.203 [reactor-http-nio-2] DEBUG reactor.ipc.netty.http.server.HttpServer - [id: 0x670506c8, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:50402] WRITE: 5B
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 34 30 30 0d 0a                                  |400..           |
+--------+-------------------------------------------------+----------------+
15:36:27.203 [reactor-http-nio-2] DEBUG reactor.ipc.netty.http.server.HttpServer - [id: 0x670506c8, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:50402] WRITE: io.netty.channel.DefaultFileRegion@68871905
15:36:27.203 [reactor-http-nio-2] DEBUG reactor.ipc.netty.http.server.HttpServer - [id: 0x670506c8, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:50402] WRITE: 2B
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 0d 0a                                           |..              |
+--------+-------------------------------------------------+----------------+
15:36:27.203 [reactor-http-nio-2] DEBUG reactor.ipc.netty.http.server.HttpServer - [id: 0x670506c8, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:50402] FLUSH
15:36:27.203 [reactor-http-nio-2] DEBUG org.springframework.http.server.reactive.ReactorHttpHandlerAdapter - Handling completed with success
15:36:27.203 [reactor-http-nio-2] DEBUG reactor.ipc.netty.http.server.HttpServerOperations - Last HTTP response frame
15:36:27.203 [reactor-http-nio-2] DEBUG reactor.ipc.netty.channel.ChannelOperationsHandler - [id: 0x670506c8, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:50402] Writing object EmptyLastHttpContent
15:36:27.203 [reactor-http-nio-2] DEBUG reactor.ipc.netty.http.server.HttpServer - [id: 0x670506c8, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:50402] WRITE: 4B
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 31 34 0d 0a                                     |14..            |
+--------+-------------------------------------------------+----------------+
15:36:27.203 [reactor-http-nio-2] DEBUG reactor.ipc.netty.http.server.HttpServer - [id: 0x670506c8, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:50402] WRITE: 20B
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 1f 8b 08 00 00 00 00 00 00 00 03 00 00 00 00 00 |................|
|00000010| 00 00 00 00                                     |....            |
+--------+-------------------------------------------------+----------------+
15:36:27.204 [reactor-http-nio-2] DEBUG reactor.ipc.netty.http.server.HttpServer - [id: 0x670506c8, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:50402] WRITE: 2B
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 0d 0a                                           |..              |
+--------+-------------------------------------------------+----------------+
15:36:27.204 [reactor-http-nio-2] DEBUG reactor.ipc.netty.http.server.HttpServer - [id: 0x670506c8, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:50402] WRITE: 5B
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 30 0d 0a 0d 0a                                  |0....           |
+--------+-------------------------------------------------+----------------+
15:36:27.204 [reactor-http-nio-2] DEBUG reactor.ipc.netty.http.server.HttpServerOperations - Decreasing pending responses, now 0
15:36:27.204 [reactor-http-nio-2] DEBUG reactor.ipc.netty.http.server.HttpServer - [id: 0x670506c8, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:50402] FLUSH
15:36:27.204 [reactor-http-nio-2] DEBUG reactor.ipc.netty.ReactorNetty - [id: 0x670506c8, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:50402] Removed handler: reactor.left.compressionHandler, pipeline: DefaultChannelPipeline{(reactor.left.loggingHandler = io.netty.handler.logging.LoggingHandler), (reactor.left.httpCodec = io.netty.handler.codec.http.HttpServerCodec), (reactor.left.httpServerHandler = reactor.ipc.netty.http.server.HttpServerHandler), (reactor.right.reactiveBridge = reactor.ipc.netty.channel.ChannelOperationsHandler)}
15:36:27.204 [reactor-http-nio-2] DEBUG reactor.ipc.netty.http.server.HttpServer - [id: 0x670506c8, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:50402] USER_EVENT: [Handler Terminated]
15:36:27.204 [reactor-http-nio-2] DEBUG reactor.ipc.netty.channel.ChannelOperationsHandler - [id: 0x670506c8, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:50402] Disposing context reactor.ipc.netty.channel.ServerContextHandler@662ac06b
15:36:27.204 [reactor-http-nio-2] DEBUG reactor.ipc.netty.channel.ChannelOperations - [id: 0x670506c8, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:50402] Discarding inbound content
15:36:27.205 [reactor-http-nio-2] DEBUG reactor.ipc.netty.http.server.HttpServer - [id: 0x670506c8, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:50402] READ COMPLETE
15:36:27.205 [reactor-http-nio-2] DEBUG reactor.ipc.netty.http.server.HttpServer - [id: 0x670506c8, L:/0:0:0:0:0:0:0:1:8080 ! R:/0:0:0:0:0:0:0:1:50402] INACTIVE
15:36:27.205 [reactor-http-nio-2] DEBUG reactor.ipc.netty.http.server.HttpServer - [id: 0x670506c8, L:/0:0:0:0:0:0:0:1:8080 ! R:/0:0:0:0:0:0:0:1:50402] UNREGISTERED

Interestingly, when using curl as the client the response changes to a 400:

$ curl -i :8080/test.txt
HTTP/1.1 400 Bad Request
content-length: 0

Here's the corresponding log output:

15:37:51.602 [reactor-http-nio-1] DEBUG reactor.ipc.netty.http.server.HttpServer - [id: 0x2ce217e6, L:/0:0:0:0:0:0:0:0:8080] READ: [id: 0x6ab65991, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:50406]
15:37:51.602 [reactor-http-nio-1] DEBUG reactor.ipc.netty.http.server.HttpServer - [id: 0x2ce217e6, L:/0:0:0:0:0:0:0:0:8080] READ COMPLETE
15:37:51.603 [reactor-http-nio-3] DEBUG reactor.ipc.netty.http.server.HttpServerOperations - New http connection, requesting read
15:37:51.603 [reactor-http-nio-3] DEBUG reactor.ipc.netty.channel.ContextHandler - After pipeline DefaultChannelPipeline{(reactor.left.loggingHandler = io.netty.handler.logging.LoggingHandler), (ServerContextHandler#0 = reactor.ipc.netty.channel.ServerContextHandler), (reactor.left.httpCodec = io.netty.handler.codec.http.HttpServerCodec), (reactor.left.httpServerHandler = reactor.ipc.netty.http.server.HttpServerHandler), (reactor.right.reactiveBridge = reactor.ipc.netty.channel.ChannelOperationsHandler)}
15:37:51.603 [reactor-http-nio-3] DEBUG reactor.ipc.netty.http.server.HttpServer - [id: 0x6ab65991, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:50406] REGISTERED
15:37:51.603 [reactor-http-nio-3] DEBUG reactor.ipc.netty.http.server.HttpServer - [id: 0x6ab65991, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:50406] ACTIVE
15:37:51.603 [reactor-http-nio-3] DEBUG reactor.ipc.netty.http.server.HttpServer - [id: 0x6ab65991, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:50406] READ: 77B
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 47 45 54 20 2f 74 65 73 74 2e 74 78 74 20 48 54 |GET /test.txt HT|
|00000010| 54 50 2f 31 2e 31 0d 0a 48 6f 73 74 3a 20 3a 38 |TP/1.1..Host: :8|
|00000020| 30 38 30 0d 0a 55 73 65 72 2d 41 67 65 6e 74 3a |080..User-Agent:|
|00000030| 20 63 75 72 6c 2f 37 2e 34 36 2e 30 0d 0a 41 63 | curl/7.46.0..Ac|
|00000040| 63 65 70 74 3a 20 2a 2f 2a 0d 0a 0d 0a          |cept: */*....   |
+--------+-------------------------------------------------+----------------+
15:37:51.603 [reactor-http-nio-3] DEBUG reactor.ipc.netty.http.server.HttpServerOperations - Increasing pending responses, now 1
15:37:51.603 [reactor-http-nio-3] DEBUG io.netty.channel.DefaultChannelPipeline - Discarded inbound message DefaultHttpRequest(decodeResult: success, version: HTTP/1.1)
GET /test.txt HTTP/1.1
Host: :8080
User-Agent: curl/7.46.0
Accept: */* that reached at the tail of the pipeline. Please check your pipeline configuration.
15:37:51.604 [reactor-http-nio-3] DEBUG reactor.ipc.netty.ReactorNetty - Added encoder [reactor.left.compressionHandler] at the beginning of the user pipeline, full pipeline: [reactor.left.loggingHandler, reactor.left.httpCodec, reactor.left.httpServerHandler, reactor.left.compressionHandler, reactor.right.reactiveBridge, DefaultChannelPipeline$TailContext#0]
15:37:51.604 [reactor-http-nio-3] DEBUG reactor.ipc.netty.http.server.HttpServer - [id: 0x6ab65991, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:50406] READ COMPLETE
15:37:51.604 [reactor-http-nio-3] DEBUG reactor.ipc.netty.channel.ChannelOperations - [HttpServer] [id: 0x6ab65991, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:50406] handler is being applied: org.springframework.http.server.reactive.ReactorHttpHandlerAdapter@5296e5c8
15:37:51.604 [reactor-http-nio-3] WARN org.springframework.http.server.reactive.ReactorHttpHandlerAdapter - Invalid URL for incoming request: Expected hostname at index 7: http://:8080
15:37:51.604 [reactor-http-nio-3] DEBUG reactor.ipc.netty.http.server.HttpServerOperations - Last HTTP response frame
15:37:51.604 [reactor-http-nio-3] DEBUG reactor.ipc.netty.http.server.HttpServerOperations - No sendHeaders() called before complete, sending zero-length header
15:37:51.604 [reactor-http-nio-3] DEBUG reactor.ipc.netty.channel.ChannelOperationsHandler - [id: 0x6ab65991, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:50406] Writing object DefaultFullHttpResponse(decodeResult: success, version: HTTP/1.1, content: EmptyByteBufBE)
HTTP/1.1 400 Bad Request
content-length: 0
15:37:51.604 [reactor-http-nio-3] DEBUG reactor.ipc.netty.http.server.HttpServer - [id: 0x6ab65991, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:50406] WRITE: 47B
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 48 54 54 50 2f 31 2e 31 20 34 30 30 20 42 61 64 |HTTP/1.1 400 Bad|
|00000010| 20 52 65 71 75 65 73 74 0d 0a 63 6f 6e 74 65 6e | Request..conten|
|00000020| 74 2d 6c 65 6e 67 74 68 3a 20 30 0d 0a 0d 0a    |t-length: 0.... |
+--------+-------------------------------------------------+----------------+
15:37:51.604 [reactor-http-nio-3] DEBUG reactor.ipc.netty.http.server.HttpServerOperations - Decreasing pending responses, now 0
15:37:51.604 [reactor-http-nio-3] DEBUG reactor.ipc.netty.http.server.HttpServer - [id: 0x6ab65991, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:50406] FLUSH
15:37:51.604 [reactor-http-nio-3] DEBUG reactor.ipc.netty.ReactorNetty - [id: 0x6ab65991, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:50406] Removed handler: reactor.left.compressionHandler, pipeline: DefaultChannelPipeline{(reactor.left.loggingHandler = io.netty.handler.logging.LoggingHandler), (reactor.left.httpCodec = io.netty.handler.codec.http.HttpServerCodec), (reactor.left.httpServerHandler = reactor.ipc.netty.http.server.HttpServerHandler), (reactor.right.reactiveBridge = reactor.ipc.netty.channel.ChannelOperationsHandler)}
15:37:51.604 [reactor-http-nio-3] DEBUG reactor.ipc.netty.http.server.HttpServer - [id: 0x6ab65991, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:50406] USER_EVENT: [Handler Terminated]
15:37:51.604 [reactor-http-nio-3] DEBUG reactor.ipc.netty.channel.ChannelOperationsHandler - [id: 0x6ab65991, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:50406] Disposing context reactor.ipc.netty.channel.ServerContextHandler@662ac06b
15:37:51.604 [reactor-http-nio-3] DEBUG reactor.ipc.netty.channel.ChannelOperations - [id: 0x6ab65991, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:50406] Discarding inbound content
15:37:51.604 [reactor-http-nio-3] DEBUG reactor.ipc.netty.http.server.HttpServer - [id: 0x6ab65991, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:50406] READ COMPLETE
15:37:51.605 [reactor-http-nio-3] DEBUG reactor.ipc.netty.http.server.HttpServer - [id: 0x6ab65991, L:/0:0:0:0:0:0:0:1:8080 ! R:/0:0:0:0:0:0:0:1:50406] INACTIVE
15:37:51.605 [reactor-http-nio-3] DEBUG reactor.ipc.netty.http.server.HttpServer - [id: 0x6ab65991, L:/0:0:0:0:0:0:0:1:8080 ! R:/0:0:0:0:0:0:0:1:50406] UNREGISTERED

The problem with curl is a red herring. curl :8080 sends the Host header as :8080. curl localhost:8080 sends a legal Host header which fixes the 400 response.

With thanks to @violetagg, we believe this is a Reactor Netty bug caused by zero copy being used even when compression is enabled. I've opened https://github.com/reactor/reactor-netty/issues/340. We'll pick up a version of Reactor Netty containing the fix in due course.

@wilkinsona, it seems that this issue still occurs for 2.0.4.RELEASE version following the same steps as @Brandon-Godwin presented. Could you please check it?

@montgomery1944 It works for me with Spring Boot 2.0.4.RELEASE with the example from @Brandon-Godwin. If you would like us to investigate further, please open a new issue with a minimal, complete, and verifiable example of the problem.

@wilkinsona I have seen the this same issue not be fixed in 2.0.4 RELEASE could I very respectfully (as I'm bound to be wrong here) ask how you tested it? It works for me with curl but only because it doesn't send a Accept-Encoding: gzip, deflate header by default whereas it fails using httpie which does.
To test it I created a brand new project from spring.io, added webflux only, added a static index.html file big enough to be over the default limit and the following minimal config in application.properties

server.port=8888
server.compression.enabled=true

I couldn't see that @montgomery1944 had created a new ticket with a sample app but I'm happy to do that

I can't recall how I tested it, but I must have done something wrong as, having tested it again with 2.0.4, I can reproduce the problem. Thanks for the nudge to double-check.

As before, the problem can be reproduced without Boot with a small modification to the reproduction I posted above. If a predicate is used to control compression (even one that always returns true) then it'll fail:

package com.example.demo;

import java.io.File;
import java.io.IOException;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.http.server.reactive.ReactorHttpHandlerAdapter;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.reactive.config.EnableWebFlux;
import org.springframework.web.reactive.config.ResourceHandlerRegistry;
import org.springframework.web.reactive.config.WebFluxConfigurer;
import org.springframework.web.server.adapter.WebHttpHandlerBuilder;

import reactor.ipc.netty.http.server.HttpServer;

@EnableWebFlux
public class Gh12892Application implements WebFluxConfigurer {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/**").addResourceLocations(new File(".").getAbsoluteFile().toURI().toString());
    }

    public static void main(String[] args) throws IOException {
        FileCopyUtils.copy(new byte[1024], new File("test.txt"));
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Gh12892Application.class);
        HttpServer server = HttpServer.builder().options((options) -> options.compression((req, resp) -> true).port(8080)).build();
        server.startAndAwait(new ReactorHttpHandlerAdapter(WebHttpHandlerBuilder.applicationContext(context).build()));
    }

}

I've opened the above Reactor Netty issue to address this.

@wilkinsona I thought I would test this so upgraded my test app to Spring Boot 2.0.5 and checked that it does use reactor-netty 0.7.9 which should have the fix in and re-ran, I'm still seeing the same issue. I don't know if it's still a reactor-netty issue though.

Thanks for testing. I can confirm that I see the same behaviour as you with Boot 2.0.5. Sorry that we haven't got this one straightened out yet. Let me see if I can figure out where the problem is this time.

This time it's failing because Boot's MIME types CompressionPredicate is returning false due to the response having no content type header: https://github.com/spring-projects/spring-boot/blob/1113c356dc0c2e47f317a46bdddff3747b53a800/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/CompressionCustomizer.java#L65-L79

That's not an unreasonable thing for it to do, but it appears that Reactor Netty can't cope with the predicate opting out of compression as it still sends the Content-Encoding: gzip header.

In this particular case, we'd actually like the response to be compressed as it's serving an HTML file and text/html is one of the MIME types that's compressed by default. So there's a secondary problem here that there's no Content-Type header for the static HTML file.

During request-response processing, the compression predicate is tested twice. It's first tested in reactor.ipc.netty.http.server.HttpServerOperations.sendFile(Path, long, long). There is no Content-Type header in the response so no compression is performed. It's tested a second time in reactor.ipc.netty.http.server.HttpServerOperations.preSendHeadersAndStatus(). At this point there is a Content-Type: text/html header in the response so compression is enabled. As far as I can tell, it's this change in the presence of the Content-Type: text/html header that leads to the Content-Encoding: gzip header being sent with an uncompressed body.

Here's a standalone WebFlux application that reproduces the problem:

package com.example.demo;

import java.io.File;
import java.io.IOException;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.http.server.reactive.ReactorHttpHandlerAdapter;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.reactive.config.EnableWebFlux;
import org.springframework.web.reactive.config.ResourceHandlerRegistry;
import org.springframework.web.reactive.config.WebFluxConfigurer;
import org.springframework.web.server.adapter.WebHttpHandlerBuilder;

import reactor.ipc.netty.http.server.HttpServer;

@EnableWebFlux
public class WebFluxApplication implements WebFluxConfigurer {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/**").addResourceLocations(new File(".").getAbsoluteFile().toURI().toString());
    }

    public static void main(String[] args) throws IOException {
        FileCopyUtils.copy(new byte[1024], new File("test.txt"));
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(WebFluxApplication.class);
        HttpServer server = HttpServer.builder().options((options) -> options.compression((req, resp) ->
            resp.responseHeaders().contains("Content-Type")).port(8080)).build();
        server.startAndAwait(new ReactorHttpHandlerAdapter(WebHttpHandlerBuilder.applicationContext(context).build()));
    }

}

The key difference from the previous one is that the compression predicate in this one returns a different value depending on whether or not the Content-Type header is present.

I'm not sure now if this is a WebFlux bug (it's adding the Content-Type header too late) or a Reactor Netty bug (it's testing the predicate too soon).

My $0.02, in this case the content is static so is the content type, so setting it as early as possible would help later processing make better decisions?
Oh and I've been in software dev for 25+ years, no apology needed for me, if this was easy we'd all be doing it ;)

I've tried the same with Spring Boot 2.1.0 (reactor-netty 0.8.x), and it works now.

There was a lot of rewriting and moving things around in the 0.7 -> 0.8 process, and it seems that this extra compression check on HttpServerOperations got lost in the process.

On the Spring Framework side, the resource handling code hasn't changed a bit, so I'm thinking about an accidental fix in 0.8, or even working by accident in 0.8. Either way, we need to let the Reactor team know about this.

I've raised reactor/reactor-netty#430 as a follow up of this issue.

The extra compression check is new in 0.7.9. It was the change that was hopefully going to fix this issue. It's what fixed this case at least, but it doesn't address the case where the predicate looks at the headers as they change between invocations.

I suspect an issue in Spring Framework https://jira.spring.io/browse/SPR-17348. For the moment I do not see issue in Reactor Netty

Thanks for the input provided by Spring Framework committers, it appeared to be an issue in Reactor Netty.
https://github.com/reactor/reactor-netty/pull/451

@wilkinsona @violetagg tested this on 2.0.6 (reactor.netty 0.7.10) seems to work for files over server.compression.min-response-size but having the ERR_CONTENT_DECODING_FAILED issue for files under server.compression.min-response-size again not sure where the problem lies.

@RobMaskell Can you tell us whether you have compression predicate also?
Do you specify Content-Length as the server.compression.min-response-size is applied only to the responses that have this header.

@RobMaskell I can't reproduce that behaviour in a minimal Spring Boot 2.0.6 application. A file that is below the compression threshold is served with no content encoding:

$ http :8080/small.txt
HTTP/1.1 200 OK
Accept-Ranges: bytes
Content-Length: 869
Content-Type: text/plain
Last-Modified: Wed, 17 Oct 2018 10:43:56 GMT

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent vehicula volutpat odio, vel commodo elit semper fringilla. Maecenas in sapien hendrerit, vestibulum velit nec, facilisis augue. Suspendisse eget lorem libero. Nunc ullamcorper dolor sollicitudin mattis commodo. Etiam imperdiet pharetra arcu, et gravida enim. Quisque volutpat velit in faucibus blandit. Morbi posuere semper nisi vitae ultrices. Duis elit libero, pellentesque eu lobortis nec, viverra et justo. Phasellus ornare non arcu at euismod. Mauris tincidunt laoreet purus at blandit. Proin nec mi condimentum, ultrices mi at, vehicula augue. Nulla bibendum tempor magna, sed luctus dui ultrices at. Vivamus vitae vulputate sapien, a placerat dui. Vestibulum suscipit placerat turpis, sodales suscipit nisl convallis non. Suspendisse lorem libero, placerat eget justo eu, ultricies viverra augue.

A file that's above the threshold is chunked and gzip encoded:

$ http :8080/large.txt
HTTP/1.1 200 OK
Accept-Ranges: bytes
Content-Type: text/plain
Last-Modified: Wed, 17 Oct 2018 10:43:56 GMT
content-encoding: gzip
transfer-encoding: chunked

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent vehicula volutpat odio, vel commodo elit semper fringilla. Maecenas in sapien hendrerit, vestibulum velit nec, facilisis augue. Suspendisse eget lorem libero. Nunc ullamcorper dolor sollicitudin mattis commodo. Etiam imperdiet pharetra arcu, et gravida enim. Quisque volutpat velit in faucibus blandit. Morbi posuere semper nisi vitae ultrices. Duis elit libero, pellentesque eu lobortis nec, viverra et justo. Phasellus ornare non arcu at euismod. Mauris tincidunt laoreet purus at blandit. Proin nec mi condimentum, ultrices mi at, vehicula augue. Nulla bibendum tempor magna, sed luctus dui ultrices at. Vivamus vitae vulputate sapien, a placerat dui. Vestibulum suscipit placerat turpis, sodales suscipit nisl convallis non. Suspendisse lorem libero, placerat eget justo eu, ultricies viverra augue.

Praesent congue nulla sed mollis euismod. Integer viverra leo sed luctus pretium. Quisque pulvinar ante urna, sit amet sodales velit ornare ac. Integer hendrerit lectus elit, congue vestibulum nunc gravida quis. Cras enim turpis, maximus quis purus ut, auctor bibendum erat. Aenean imperdiet sapien lectus, ac ultricies sem dapibus sit amet. Fusce interdum posuere metus vel laoreet. Phasellus luctus facilisis dui et tristique. Cras ornare commodo elit quis consectetur. Vivamus posuere lobortis orci non pellentesque. Cras sit amet mollis massa, at bibendum risus. In eu suscipit sapien.

Cras porta nisl ac faucibus condimentum. Vestibulum porttitor dictum mi at porta. Vivamus pretium, libero non venenatis imperdiet, sapien erat dignissim ligula, vel finibus nulla enim at tortor. Curabitur arcu metus, tristique efficitur turpis nec, dapibus vehicula ligula. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Suspendisse venenatis euismod aliquet. Sed interdum ante sit amet augue faucibus, nec posuere libero ornare. Pellentesque viverra volutpat enim sit amet laoreet. Duis facilisis eros quis nulla mollis condimentum. Ut nunc diam, fermentum et dictum in, posuere vitae justo. Nullam id porta tellus. Aenean blandit ac dolor et ornare. Phasellus nec bibendum urna.

Morbi rhoncus pulvinar mi, eu venenatis purus aliquet vitae. Aenean imperdiet quis ante id euismod. Praesent sit amet mi dictum massa elementum sollicitudin. Donec sollicitudin nisl risus, at luctus quam placerat sed. Suspendisse id turpis sem. Vivamus aliquet nisl ac porttitor interdum. Fusce vehicula tortor felis. Donec ac erat risus.

Duis in elit tellus. Vestibulum non viverra justo, non pharetra dolor. Phasellus ut laoreet justo. Sed quis purus urna. Suspendisse vehicula, libero eu fringilla tempus, sem magna aliquam orci, vel cursus turpis sem ac tellus. Mauris rutrum purus ipsum, facilisis eleifend orci egestas at. Nam varius eros non purus fermentum suscipit. Cras egestas finibus massa ut tincidunt. Cras hendrerit erat augue. Curabitur nec feugiat nibh. Vestibulum mollis justo et gravida auctor. Ut sollicitudin pretium rhoncus.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi aliquet sollicitudin massa in faucibus. Sed at aliquet felis, sed consequat lacus. Donec dictum et neque congue aliquet. Sed interdum elit lorem, at pharetra felis convallis vitae. Aliquam nec vehicula diam, nec auctor ante. Integer vel lacinia risus. Sed varius, dolor eu commodo lacinia, ex mauris eleifend velit, ac lobortis risus velit elementum mauris. Nullam ullamcorper bibendum ipsum, mattis finibus ligula bibendum a. Donec at nibh metus. Maecenas eu purus pulvinar turpis vehicula tempor at a diam. Maecenas ac mauris at lacus vulputate aliquet. Integer sagittis mauris ut fermentum volutpat. Vivamus nec erat ut felis fermentum rutrum. Morbi quis urna scelerisque, viverra leo at, rutrum sapien. Donec vestibulum arcu sed iaculis lacinia.

Integer vitae tincidunt elit. Nullam nibh tellus, facilisis eget arcu at, dignissim lacinia est. Nulla accumsan id metus in rhoncus. Donec ultricies venenatis magna et mattis. Nunc a nisi eget neque varius ultricies. Nullam ac bibendum libero. Curabitur gravida a dolor sed interdum. Duis ut egestas dolor, consectetur rutrum nibh. Etiam sit amet euismod metus. Nulla ac turpis sit amet nunc congue tempus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In non laoreet libero. Fusce fringilla nisi sit amet tellus auctor lobortis. Duis et ultrices odio, sit amet porta ex.

Can you please share a sample that reproduces the ERR_CONTENT_DECODING_FAILED issue?

Ok let me have a look, I'm using Spring Cloud Gateway so I know I'm seeing this in my actually app but I also had a minimal test app that I haven't tried yet.

Right this is officially weird, nothing to do with SGC my basic app is just spring boot and web flux with a single index.html in the static folder, issue is evident in chromium on refresh of page but is now random as to whether I get the page or the error, however testing with httpie I get the page every time so far (20+ times tested). In the browser I mostly get the error and occasionally the page. Page is big enough to be over the gzip threshold so my application.properties just sets a port and turns on compression. When it fails in the browser the size is shown as 164B and when it succeeds it's 2.0KB. My dev system is Elementary Linux, latest Chromium browser and the app is running on open-jdk 8, when I shut down the app to restart the VM it crashed with a close stream type exception which I've never seen before. I'll continue playing see if I can narrow it down at all.

Restarted machine, tested with httpie all ok, opened browser paged loaded, several refreshes ok but probably from cache, Ctrl-Shift-R and ERR_CONTENT_DECODING_FAILED which continued on multiple refreshes.

Testing to see whether the first request in browser always works, opened browser and loaded page, all ok, Ctrl-Shift-R resulted in ERR_CONTENT_DECODING_FAILED restarted the app in IntelliJ went back to browser and page had loaded correctly on it's own! Ghosts... I blame ghosts ;)

This is the error I get now on stopping the app in IntelliJ

2018-10-17 13:38:40.265  INFO 9493 --- [           main] com.example.demo.DemoApplication         : Started DemoApplication in 2.685 seconds (JVM running for 3.168)
Could not read standard output of command '/usr/lib/jvm/java-8-openjdk-amd64/bin/java'.
java.io.IOException: Stream closed
    at java.io.BufferedInputStream.getBufIfOpen(BufferedInputStream.java:170)
    at java.io.BufferedInputStream.read1(BufferedInputStream.java:291)
    at java.io.BufferedInputStream.read(BufferedInputStream.java:345)
    at java.io.FilterInputStream.read(FilterInputStream.java:107)
    at org.gradle.process.internal.streams.ExecOutputHandleRunner.forwardContent(ExecOutputHandleRunner.java:61)
    at org.gradle.process.internal.streams.ExecOutputHandleRunner.run(ExecOutputHandleRunner.java:51)
    at org.gradle.internal.operations.CurrentBuildOperationPreservingRunnable.run(CurrentBuildOperationPreservingRunnable.java:42)
    at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
    at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
    at java.lang.Thread.run(Thread.java:748)

> Task :bootRun FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':bootRun'.
> Process 'command '/usr/lib/jvm/java-8-openjdk-amd64/bin/java'' finished with non-zero exit value 143

Just in case it's relevant, and only because it's new

I've seen that problem before with Gradle, and others have too. I can't be 100% certain, but I don't think it's relevant here.

@wilkinsona is your minimal app on GitHub I could try testing against that and rule out my minimal app? Also which JVM do you use and have you tried this test multiple times in a real browser?

There's a link to a zip of my minimal app in my comment above.

I've just tried it using a browser and I see failures in both Safari and Chrome on macOS. With Safari it flip-flops between serving the file and failing with "cannot decode raw data". With Chrome, it worked once and then fails repeatedly with "ERR_CONTENT_DECODING_FAILED".

When it fails, the content-encoding: gzip and transfer-encoding: chunked headers are sent but the body is plain text.

Ok I have not tried in Safari but we are seeing the same thing in Chrome. Just tried Oracle JDK same behaviour.

give me some time I think I know what might be ...

It's a connection keep alive problem. I can reproduce it with curl:

$ curl -i -H 'Accept-Encoding: gzip' http://localhost:8080/large.txt http://localhost:8080/large.txt
HTTP/1.1 200 OK
Last-Modified: Wed, 17 Oct 2018 10:43:56 GMT
Content-Type: text/plain
Accept-Ranges: bytes
content-encoding: gzip
transfer-encoding: chunked

TSK??0
      ??)xçhfS螖???~?D??ώ?[Yz?W?Lںg?5U???8˘(??%
?]<Aٺ   ]8hҮ?د.3????H{??                       n?Q????J?t??e,]ʠUn<1?5?h<?F??r???O?Knbt1?hJ<?K??P?R?&%???
                        J????X???K ]?6??eMI????<?3}e???&Ø؂O????I??~???.??z?|a??iI
                                                                                 ????ڢ?jw1ydR`?V,?:L?????????DMRB䲓???RmS?'??*????????<}?
                                                                                                                                         Tj?=4
CK??h41?l??)??⿬??(?6??z<O??????8Z??*?FJD???B?k? )DJآ??A?[W??pOg??|?c/1??A
?????Y?-??????鉷?m>BP?gw?oo???P???|?3?m?@?WL⁐????0D???5O??\b<$?=??>}??x??Ó????\??m?0???b??   ?
7?#??bl܈QK?                                                                         DW??w(t?????IJ???;?????C?w??
           gOᲃ\ಮ?7?+>??TL?v?)???mN?@?5?^??z??p?s?Զ??;웁ف ?۠³*;?$?$???F?8?????Y??L?S??^C+?t?????~͂?Ȭ?v{??5?Z???6sO?*?8?t$M.???<??׏L#n?J?N?|E˺????ĭܬ??R???(???????7??f]?Bq??]Ꞿ?|ZXH?Y?.?yY??wK?v\ˀ??j|p2x??,?Z??5?+?   ?^?J??v$)G*?*?j?!}s8R?N=?£[-E?&E?P?J????J?????>?.?j?3
                                         U}K?)Р????V[n?@
                                                        ??,???$e%(b?????c{SU???偫/8v??K??Ґ?1??
                                                                                              ??/?Fo??u/
????ױ_?_&?ȶ{;?                                                                                          I???Vۥ
z?&?g?#y???????Ö?0+?싰?k@~?̻?@?ѭ4???9?N^ ??^B?F
C???b??t96D???w7???%?χ7?YϐÁ?????`j
Z\2#?G?(=?p&nTE?L?s??L?g???,?l??<+?C
                                    -FU%G?:n???Q??c?t??v?`??ȳY?f?8?K?soC?????rE?p?=?!??2Y??ú?$Eu???[????F??uG?l??Q??/*-?S??;
                                                                                                                            ?????o??tWI?@
                                                                                                                                         ?
c?(B??T?7??yj??"?ӶaE?Bti??4?D?]d?????9f??e)?q????F??cS?5?q7??`??@[.????&?rr?X=?6K?K????????2?2?7??܈D??%????????????["?*?5h????1??6?A??n?DM=i#-

??vh}??"??????G????????
H??^?a???U?]?(2] ?5??0z3???H*/?i?????a"??N]D???|?w?[!{KC9?1???T?a   s???????S^??L???z??yHTTP/1.1 200 OK
Last-Modified: Wed, 17 Oct 2018 10:43:56 GMT
Content-Type: text/plain
Accept-Ranges: bytes
content-encoding: gzip
transfer-encoding: chunked

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent vehicula volutpat odio, vel commodo elit semper fringilla. Maecenas in sapien hendrerit, vestibulum velit nec, facilisis augue. Suspendisse eget lorem libero. Nunc ullamcorper dolor sollicitudin mattis commodo. Etiam imperdiet pharetra arcu, et gravida enim. Quisque volutpat velit in faucibus blandit. Morbi posuere semper nisi vitae ultrices. Duis elit libero, pellentesque eu lobortis nec, viverra et justo. Phasellus ornare non arcu at euismod. Mauris tincidunt laoreet purus at blandit. Proin nec mi condimentum, ultrices mi at, vehicula augue. Nulla bibendum tempor magna, sed luctus dui ultrices at. Vivamus vitae vulputate sapien, a placerat dui. Vestibulum suscipit placerat turpis, sodales suscipit nisl convallis non. Suspendisse lorem libero, placerat eget justo eu, ultricies viverra augue.

Praesent congue nulla sed mollis euismod. Integer viverra leo sed luctus pretium. Quisque pulvinar ante urna, sit amet sodales velit ornare ac. Integer hendrerit lectus elit, congue vestibulum nunc gravida quis. Cras enim turpis, maximus quis purus ut, auctor bibendum erat. Aenean imperdiet sapien lectus, ac ultricies sem dapibus sit amet. Fusce interdum posuere metus vel laoreet. Phasellus luctus facilisis dui et tristique. Cras ornare commodo elit quis consectetur. Vivamus posuere lobortis orci non pellentesque. Cras sit amet mollis massa, at bibendum risus. In eu suscipit sapien.

Cras porta nisl ac faucibus condimentum. Vestibulum porttitor dictum mi at porta. Vivamus pretium, libero non venenatis imperdiet, sapien erat dignissim ligula, vel finibus nulla enim at tortor. Curabitur arcu metus, tristique efficitur turpis nec, dapibus vehicula ligula. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Suspendisse venenatis euismod aliquet. Sed interdum ante sit amet augue faucibus, nec posuere libero ornare. Pellentesque viverra volutpat enim sit amet laoreet. Duis facilisis eros quis nulla mollis condimentum. Ut nunc diam, fermentum et dictum in, posuere vitae justo. Nullam id porta tellus. Aenean blandit ac dolor et ornare. Phasellus nec bibendum urna.

Morbi rhoncus pulvinar mi, eu venenatis purus aliquet vitae. Aenean imperdiet quis ante id euismod. Praesent sit amet mi dictum massa elementum sollicitudin. Donec sollicitudin nisl risus, at luctus quam placerat sed. Suspendisse id turpis sem. Vivamus aliquet nisl ac porttitor interdum. Fusce vehicula tortor felis. Donec ac erat risus.

Duis in elit tellus. Vestibulum non viverra justo, non pharetra dolor. Phasellus ut laoreet justo. Sed quis purus urna. Suspendisse vehicula, libero eu fringilla tempus, sem magna aliquam orci, vel cursus turpis sem ac tellus. Mauris rutrum purus ipsum, facilisis eleifend orci egestas at. Nam varius eros non purus fermentum suscipit. Cras egestas finibus massa ut tincidunt. Cras hendrerit erat augue. Curabitur nec feugiat nibh. Vestibulum mollis justo et gravida auctor. Ut sollicitudin pretium rhoncus.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi aliquet sollicitudin massa in faucibus. Sed at aliquet felis, sed consequat lacus. Donec dictum et neque congue aliquet. Sed interdum elit lorem, at pharetra felis convallis vitae. Aliquam nec vehicula diam, nec auctor ante. Integer vel lacinia risus. Sed varius, dolor eu commodo lacinia, ex mauris eleifend velit, ac lobortis risus velit elementum mauris. Nullam ullamcorper bibendum ipsum, mattis finibus ligula bibendum a. Donec at nibh metus. Maecenas eu purus pulvinar turpis vehicula tempor at a diam. Maecenas ac mauris at lacus vulputate aliquet. Integer sagittis mauris ut fermentum volutpat. Vivamus nec erat ut felis fermentum rutrum. Morbi quis urna scelerisque, viverra leo at, rutrum sapien. Donec vestibulum arcu sed iaculis lacinia.

Integer vitae tincidunt elit. Nullam nibh tellus, facilisis eget arcu at, dignissim lacinia est. Nulla accumsan id metus in rhoncus. Donec ultricies venenatis magna et mattis. Nunc a nisi eget neque varius ultricies. Nullam ac bibendum libero. Curabitur gravida a dolor sed interdum. Duis ut egestas dolor, consectetur rutrum nibh. Etiam sit amet euismod metus. Nulla ac turpis sit amet nunc congue tempus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In non laoreet libero. Fusce fringilla nisi sit amet tellus auctor lobortis. Duis et ultrices odio, sit amet porta ex.

Fixed with https://github.com/reactor/reactor-netty/pull/468
Try Reactor Netty 0.7.11.BUILD-SNAPSHOT

Nice work @violetagg worked on my minimal project and the proper one too. Thanks.

@wilkinsona looks like SGC only gzips static files and doesn't honour the compression property when serving from a route but that's a separate issue I'll check if it's been reported already.

Was this page helpful?
0 / 5 - 0 ratings