Unable to make WebSocket transport compression work in RSocket client/server Spring Boot applications running with Netty backend and Spring Boot version 2.5.9.

The Spring Boot allows to specify the server-side RSocket transport and endpoint path in the application.properties, but there are no any additional configuration parameters available besides that. The autoconfig creates an instance of the RSocketWebSocketNettyRouteProvider which doesn't have compression enabled and also doesn't have any customizers to enable it.

To get around that I removed spring.rsocket.server.mapping-path property and declared a bean like this in the server config to pass a WebsocketServerSpec with compress option enabled to httpServerRoutes.ws(...) call:

    @Bean
    NettyRouteProvider rSocketWebsocketRouteProvider(
            RSocketProperties properties, RSocketMessageHandler messageHandler,
            ObjectProvider<RSocketServerCustomizer> customizers) {
        return new NettyRouteProvider() {
            public HttpServerRoutes apply(HttpServerRoutes httpServerRoutes) {
                RSocketServer server = RSocketServer.create(messageHandler.responder());
                customizers.forEach((customizer) -> customizer.customize(server));

                return httpServerRoutes.ws("/rsocket",
                        WebsocketRouteTransport.newHandler(server.asConnectionAcceptor()),
                        WebsocketServerSpec.builder().compress(true).build());
            }
        };
    }

On the client side I'm creating RSocketRequester like this:

RSocketRequester requester = builder
                .setupRoute("/backend/connect")
                .setupData(id)
                .rsocketConnector(connector -> connector
                        .reconnect(Retry.fixedDelay(Integer.MAX_VALUE, Duration.ofSeconds(5)))
                        .acceptor(RSocketMessageHandler.responder(strategies, backendController)) // ****** (1)
                )
                .dataMimeType(MediaType.APPLICATION_JSON)
                .transport(() -> {
                    // httpClient is immutable - baseUrl() creates a copy
                    ClientTransport t = WebsocketClientTransport.create(
                                HttpClient.create().baseUrl(backendUrl), "/rsocket")
                            .webSocketSpec(configurer -> configurer
                                    .compress(true) // ****** (2)
                                    .maxFramePayloadLength(65536));
                    return t.connect();
                });

The webSocketSpec need to have compress flag enabled. Otherwise I don't see compression applied when looking at the traffic in Charles proxy with a simple port forwarding enabled.

The problem is that when compress is enabled on line (2) the client can't complete the connection sequence. However if I comment out the .acceptor() configuration on line (1) the connect is working and I see server to client calls going through and I can see data is being compressed. But without the acceptor server can't call the client.

Here is an example project repository https://github.com/maximdim/rsocket2/tree/rsocket-compression You can launch BackendApplication and AgentApplication to observe described issue.

Comment From: philwebb

It looks like this might be a lower level RSocket problem rather than anything directly tied to the way that Spring Boot configures things. I'll transfer this to the Spring Framework team who will hopefully be better placed to diagnose the issue.

Comment From: philwebb

I've opened https://github.com/spring-projects/spring-boot/issues/29550 to see if we can at least improve the WebsocketServerSpec customization.

Comment From: ekuleshov

Thank you @philwebb.

Just to clarify, when compression is enabled in a plain rsocket/websocket example it works both ways. E.g. in this original example https://github.com/rsocket/rsocket-java/blob/master/rsocket-examples/src/main/java/io/rsocket/examples/transport/ws/WebSocketHeadersSample.java

I can just use the following for both server and client connection and observe client/server data being compressed.

WebsocketClientTransport.create(server.host(), server.port())
  .webSocketSpec(c -> c.compress(true))

Comment From: rstoyanchev

As far as I can see, this is all within the RSocketServerAutoConfiguration. There is no server transport initialization in the Spring Framework. @philwebb now that you've created https://github.com/spring-projects/spring-boot/issues/29550, is there is any reason to still keep this issue open?

Comment From: ekuleshov

As far as I can see, this is all within the RSocketServerAutoConfiguration. There is no server transport initialization in the Spring Framework. @philwebb now that you've created spring-projects/spring-boot#29550, is there is any reason to still keep this issue open?

Please see my rSocketWebsocketRouteProvider() bean override that enables server-side compression. But with that stuff enabled I was unable to confirm compression working between client and server.

The #29550 issue is about removing the need in such override and allowing to configure server-side compression with autoconfig, server properties, etc... But the compression either does not work or my configuration change is not correct one.

Comment From: rstoyanchev

@ekuleshov the sample is missing the customization snippets above, including the reference to a backendController. I've added all that and corrected a couple of other minor things, but I'm not able to reproduce the issue. Could you please update the sample to demonstrate the issue when run?

Comment From: ekuleshov

@ekuleshov the sample is missing the customization snippets above, including the reference to a backendController. I've added all that and corrected a couple of other minor things, but I'm not able to reproduce the issue. Could you please update the sample to demonstrate the issue when run?

@rstoyanchev are you looking at the rsocket-compression branch as per the url linked above?

I just checked that the same quote code is there.

Enabling server side compression: https://github.com/maximdim/rsocket2/blob/664f938e18c57558030a0e87374dc471df1084a5/src/main/java/rsocket/backend/BackendConfig.java#L35

Enabling compression on the client: https://github.com/maximdim/rsocket2/blob/664f938e18c57558030a0e87374dc471df1084a5/src/main/java/rsocket/client/BackendService.java#L54

The main branch may not have the server's acceptor enabled, which in my tests broke the connection handshake or something, so the client couldn't connect. When this line is commented out compression works, but client is unable to call the server: https://github.com/maximdim/rsocket2/blob/664f938e18c57558030a0e87374dc471df1084a5/src/main/java/rsocket/client/BackendService.java#L45

Comment From: rstoyanchev

@ekuleshov apologies for the delay. I have been able to reproduce this and the issue seems to be related to the client acceptor not being able to read anything from the SETUP payload. This is for any client acceptor, and it's reproducible with just RSocket Java. I've created https://github.com/rsocket/rsocket-java/issues/1045 to supersede this one.

Thanks for the report!