= Description I believe I may be experiencing a bug in Tomcat or simply misinterpreting JSR 356. Any thoughts on how to resolve the issue or if I a bug should be created would be welcome. To reproduce:
1) Authenticate to the application over HTTP. In my instance I am using Spring Security which overrides the HttpServletRequest using an HttpServletRequestWrapper 2) Open a WebSocket connection over an "unprotected endpoint" 3) Wait for the HttpSession to timeout while using the WebSocket connection. 4) When the HttpSession times out, the WebSocket connection is closed by WsSessionListener JSR 356 states "If the websocket endpoint is not a protected resource, ... the user identity ... *may* become invalid...without the websocket implementation needing to close the connection". The full excerpt can be found below: > In the case where a websocket endpoint is a protected resource in the web > application (see Chapter 8), that is to say, requires an authorized user to > access it, then the websocket implementation must ensure that the websocket > endpoint does not remain connected to its peer after the underlying > implementation has decided the authenticated identity is no longer valid. > [WSC-7.2-3] This may happen, for example, if the user logs out of the containing > web application, or if the authentication times out or is invalidated for some > other reason. > > On the other hand, if the websocket endpoint is not a protected resource in the > web application, then the user identity under which an opening handshake > established the connection may become invalid or change during the operation of > the websocket without the websocket implementation needing to close the > connection. Should the WebSocket connection be closed when the session expires in this instance? Perhaps this is just that I am misunderstanding the JSR which states *may* instead of *must*. I'm not sure that is the case since a must in this phrasing does not make much sense. For what it is worth, Jetty does not close the connection in this instance. Another point of interest is that we get a NullPointerException in the WsServerContainer when unregistering the session. Is this a possible bug since it is logged at SEVERE? = Complete Example You can find a complete example on github [1]. The steps to reproduce are: 1) Clone the repository and use the wssessionlistener branch or download from [2] 2) Ensure you have installed Maven and run "mvn tomcat7:run" 3) Visit http://localhost:8080/spring-websocket-portfolio/traditional/ 4) Authenticate with the username "fabrice" and the password "fab123" 5) Wait 1 minute (the session is set to expire in a minute) 6) The WebSocket session will be closed We also see the following stacktraces in the terminal. For a formatted version of the stack see the linked gist [3]. Jun 25, 2014 11:34:19 AM org.apache.catalina.session.StandardSession expire SEVERE: Session event listener threw exception java.lang.NullPointerException at org.apache.tomcat.websocket.server.WsServerContainer.unregisterAuthenticatedSession(WsServerContainer.java:367) at org.apache.tomcat.websocket.server.WsServerContainer.unregisterSession(WsServerContainer.java:344) at org.apache.tomcat.websocket.WsSession.sendCloseMessage(WsSession.java:494) at org.apache.tomcat.websocket.WsSession.doClose(WsSession.java:417) at org.apache.tomcat.websocket.WsSession.close(WsSession.java:394) at org.apache.tomcat.websocket.server.WsServerContainer.closeAuthenticatedSession(WsServerContainer.java:377) at org.apache.tomcat.websocket.server.WsSessionListener.sessionDestroyed(WsSessionListener.java:40) at org.apache.catalina.session.StandardSession.expire(StandardSession.java:808) at org.apache.catalina.session.StandardSession.isValid(StandardSession.java:658) at org.apache.catalina.session.ManagerBase.processExpires(ManagerBase.java:534) at org.apache.catalina.session.ManagerBase.backgroundProcess(ManagerBase.java:519) at org.apache.catalina.core.ContainerBase.backgroundProcess(ContainerBase.java:1352) at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1530) at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1540) at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1540) at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.run(ContainerBase.java:1519) at java.lang.Thread.run(Thread.java:744) 11:34:20 [clientOutboundChannel-9] WebSocketServerSockJsSession - Terminating connection after failure to send message to client. java.lang.IllegalArgumentException: Cannot send message after connection closed. at org.springframework.util.Assert.isTrue(Assert.java:65) at org.springframework.web.socket.adapter.AbstractWebSocketSession.sendMessage(AbstractWebSocketSession.java:97) at org.springframework.web.socket.sockjs.transport.session.WebSocketServerSockJsSession.writeFrameInternal(WebSocketServerSockJsSession.java:196) at org.springframework.web.socket.sockjs.transport.session.AbstractSockJsSession.writeFrame(AbstractSockJsSession.java:336) at org.springframework.web.socket.sockjs.transport.session.WebSocketServerSockJsSession.sendMessageInternal(WebSocketServerSockJsSession.java:186) at org.springframework.web.socket.sockjs.transport.session.AbstractSockJsSession.sendMessage(AbstractSockJsSession.java:251) at org.springframework.web.socket.handler.ConcurrentWebSocketSessionDecorator.tryFlushMessageBuffer(ConcurrentWebSocketSessionDecorator.java:126) at org.springframework.web.socket.handler.ConcurrentWebSocketSessionDecorator.sendMessage(ConcurrentWebSocketSessionDecorator.java:99) at org.springframework.web.socket.messaging.StompSubProtocolHandler.handleMessageToClient(StompSubProtocolHandler.java:327) at org.springframework.web.socket.messaging.SubProtocolWebSocketHandler.handleMessage(SubProtocolWebSocketHandler.java:305) at org.springframework.messaging.support.ExecutorSubscribableChannel$1.run(ExecutorSubscribableChannel.java:70) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) at java.lang.Thread.run(Thread.java:744) = Environment Information Tomcat 8.0.8 and 7.0.47 OSX Mavericks java version "1.7.0_45" Java(TM) SE Runtime Environment (build 1.7.0_45-b18) Java HotSpot(TM) 64-Bit Server VM (build 24.45-b08, mixed mode) [1] https://github.com/rwinch/spring-websocket-portfolio/tree/wssessionlistener [2] https://github.com/rwinch/spring-websocket-portfolio/archive/wssessionlistener.zip [3] https://gist.github.com/rwinch/04c59fcacff4a4256030 Cheers, Rob Winch