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

Fix IllegalArgumentException that prevents STOMP DISCONNECT from reaching the client #30120

Conversation

alexjansons
Copy link
Contributor

In some application setups, the WebSocket server does not transmit the disconnect message to the client, so that the client has no idea that the established connection has been terminated.

This issue arises when the application uses SimpleBrokerMessageHandler and the error handler is set to the instance of
StompSubProtocolErrorHandler or an extended class that does not override the handleErrorMessageToClient method.

The commit fixes disconnect message population so that java.lang.IllegalArgumentException: No StompHeaderAccessor exception is not thrown in the handleErrorMessageToClient method in StompSubProtocolErrorHandler class.

A reproducible example for the case is available here:

The issue arises when the client fails to send heartbeats for specific period, causing the server to terminate the session by invoking the handleDisconnect method in the SimpleBrokerMessageHandler.HeartbeatTask class. This issue was discovered in spring-websocket-5.3.13 but still persists in the latest code base.

If the error handler is not set, then there is no problem as the message is delivered to the client in this scenario. A reproducible example that illustrates this is the DisconnectWithoutErrorHandler.test found at https://github.com/alexjansons/spring-sandbox/blob/main/web-socket/disconnect-error/src/test/java/com/example/websocket/disconnecterror/ApplicationTests.java#L97.

However if the error handler is set to StompSubProtocolErrorHandler class instance or the instance of extended class given that the latter does not implement it's own handleErrorMessageToClient method, the disconnect message transmission process faces the IllegalArgumentException exception in the aforementioned method. The exception is caught and then silently ignored in SubProtocolWebSocketHandler.handleMessage method, which results in no message being sent to the client. This case is covered in DisconnectWithErrorHandler.test at https://github.com/alexjansons/spring-sandbox/blob/main/web-socket/disconnect-error/src/test/java/com/example/websocket/disconnecterror/ApplicationTests.java#L83.

A workaround for this issue is to extend the StompSubProtocolErrorHandler class for the error handler and re-implement the method handleErrorMessageToClient so that it does not generate an exception. An example of this workaround can be found at https://github.com/alexjansons/spring-sandbox/blob/main/web-socket/disconnect-error/src/main/java/com/example/websocket/disconnecterror/Application.java#L24.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Mar 15, 2023
@sbrannen sbrannen added in: web Issues in web modules (web, webmvc, webflux, websocket) type: bug A general bug labels Mar 15, 2023
In some application setups, the WebSocket server does not transmit
the disconnect message to the client, so that the client has no idea
that the established connection has been terminated.

This issue arises when the application uses SimpleBrokerMessageHandler
and the error handler is set to the instance of
StompSubProtocolErrorHandler or an extended class that does not
override the handleErrorMessageToClient method.

The commit fixes disconnect message population so that
`java.lang.IllegalArgumentException: No StompHeaderAccessor` exception
is not thrown in the handleErrorMessageToClient method in
StompSubProtocolErrorHandler class.
@alexjansons alexjansons force-pushed the bugfix/websocket-disconnect-error branch from e3cdd8d to cb785e1 Compare March 16, 2023 13:43
Copy link
Contributor

@simonbasle simonbasle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hey @alexjansons, thanks for the PR! Would you be able to produce a unit test or compact integration test that reproduces the issue and validates the fix?

@@ -465,7 +465,9 @@ else if (StompCommand.CONNECTED.equals(command)) {
}

if (StompCommand.ERROR.equals(command) && getErrorHandler() != null) {
Message<byte[]> errorMessage = getErrorHandler().handleErrorMessageToClient((Message<byte[]>) message);
Message<byte[]> enrichedMessage =
MessageBuilder.createMessage((byte[]) message.getPayload(), accessor.getMessageHeaders());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: rather than casting, you can use payload from the instanceOf at the top

@simonbasle simonbasle added status: waiting-for-feedback We need additional information before we can continue and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels Mar 22, 2023
@rstoyanchev rstoyanchev added this to the 6.0.8 milestone Mar 28, 2023
@rstoyanchev rstoyanchev self-assigned this Mar 28, 2023
@rstoyanchev rstoyanchev removed the status: waiting-for-feedback We need additional information before we can continue label Mar 28, 2023
@rstoyanchev rstoyanchev changed the title Ensure WebSocket disconnect msg reaches the client Fix IllegalArgumentException that prevents WebSocket disconnect message from reaching the client Mar 28, 2023
@rstoyanchev rstoyanchev changed the title Fix IllegalArgumentException that prevents WebSocket disconnect message from reaching the client Fix IllegalArgumentException that prevents STOMP DISCONNECT from reaching the client Apr 11, 2023
rstoyanchev pushed a commit that referenced this pull request Apr 11, 2023
In some application setups, the WebSocket server does not transmit
the disconnect message to the client, so that the client has no idea
that the established connection has been terminated.

This issue arises when the application uses SimpleBrokerMessageHandler
and the error handler is set to the instance of
StompSubProtocolErrorHandler or an extended class that does not
override the handleErrorMessageToClient method.

The commit fixes disconnect message population so that
`java.lang.IllegalArgumentException: No StompHeaderAccessor` exception
is not thrown in the handleErrorMessageToClient method in
StompSubProtocolErrorHandler class.

See gh-30120
izeye added a commit to izeye/spring-framework that referenced this pull request Apr 19, 2023
@izeye izeye mentioned this pull request Apr 19, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: web Issues in web modules (web, webmvc, webflux, websocket) type: bug A general bug
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants