During migration from Spring 6.0 and replacing JettyWebSocketClient with StandardWebSocketClient we noticed that StandardWebSocketSession incorrectly returns a remote port instead of a local port from WebSocketSession#getLocalAddress() for the client WS session. Old removed JettyWebSocketSession was implementing this method correctly. It was returning the port of the local socket of the underlying TCP connection.
This problem comes from the following implementation in StandardWebsocketClient which is obviously erroneous:
@Override
protected CompletableFuture<WebSocketSession> executeInternal(WebSocketHandler webSocketHandler,
HttpHeaders headers, final URI uri, List<String> protocols,
List<WebSocketExtension> extensions, Map<String, Object> attributes) {
int port = getPort(uri);
InetSocketAddress localAddress = new InetSocketAddress(getLocalHost(), port);
InetSocketAddress remoteAddress = new InetSocketAddress(uri.getHost(), port);
StandardWebSocketSession session = new StandardWebSocketSession(headers,
attributes, localAddress, remoteAddress);
Client WS Session shouldn't use the same port value for both the local and remote addresses.
There was a previous report about this bug and regression that was incorrectly closed for being a question: https://github.com/spring-projects/spring-framework/issues/22395
Workaround
To work around this bug, instead of
WebSocketSession session = ...
InetSocketAddress localAddress = session.getLocalAddress();
users should do
InetSocketAddress localAddress = (InetSocketAddress)((JakartaWebSocketSession)(((StandardWebSocketSession)
session).getNativeSession())).getCoreSession().getLocalAddress();
when are using Jakarta WS implementation.
Comment From: rstoyanchev
Thanks for the report. You're correct, but jakarta.session.Session doesn't make this available and there is no other way to get it. I think we can update the Javadoc to warn about it.
Comment From: Spikhalskiy
@rstoyanchev Do you think it would be productive to start a conversation in the Jakarta Websocket API project about adding a #getLocalAddress() method to a session? It's not intuitive why this information should be encapsulated and not be exposed in the session.
I think it's reasonable to expect an API to allow retrieving a local port the session is bound to.
Comment From: rstoyanchev
I think it is a good idea. I found https://github.com/jakartaee/websocket/issues/255 for remote address that mentions local address, but it was created a while ago. Maybe it can be revived with more comments and votes. Perhaps the title can be updated too to reflect a request for both local and remote address.
Comment From: Spikhalskiy
@rstoyanchev I will open a discussion in https://github.com/jakartaee/websocket referencing this issue sometime later.
But don't you think that it's a better solution to make StandardWebSocketSession.getLocalAddress throw in case no correct values can be determined? We just faced a pretty unpleasant long investigation because we were using getLocalAddress as a key to maintain an internal structure of open WS clients and the silent change of the method behavior led to a problem that wasn't trivial to trace. If this method was throwing, it would be immediately clear what's going on.
Comment From: rstoyanchev
The method allows for returning null. We could probably do that rather than throw an exception. I've created #34331.