16

I would like to make the connection between a websocket handshake \ session to a HttpSession object.

I've used the following handshake modification:

public class GetHttpSessionConfigurator extends ServerEndpointConfig.Configurator
{
@Override
public void modifyHandshake(ServerEndpointConfig config, 
                            HandshakeRequest request, 
                            HandshakeResponse response)
{
    HttpSession httpSession = (HttpSession)request.getHttpSession();
    config.getUserProperties().put(HttpSession.class.getName(),httpSession);
}
}

As mentioned in this post: Accessing HttpSession from HttpServletRequest in a Web Socket @ServerEndpoint

Now, For some reason on the hand shake, the (HttpSession)request.getHttpSession() returns null all the time.

here is my client side code:

<!DOCTYPE html>
<html>
<head>
<title>Testing websockets</title>
</head>
<body>
<div>
    <input type="submit" value="Start" onclick="start()" />
</div>
<div id="messages"></div>
<script type="text/javascript">
    var webSocket = 
        new WebSocket('ws://localhost:8080/com-byteslounge-websockets/websocket');

    webSocket.onerror = function(event) {
        onError(event)
    };

    webSocket.onopen = function(event) {
        onOpen(event)
    };

    webSocket.onmessage = function(event) {
        onMessage(event)
    };

    function onMessage(event) {
        document.getElementById('messages').innerHTML 
            += '<br />' + event.data;
    }

    function onOpen(event) {
        document.getElementById('messages').innerHTML 
            = 'Connection established';
    }

    function onError(event) {
        alert(event.data);
    }

    function start() {
        webSocket.send('hello');
        return false;
    }
</script>
</body>
</html>

Any ideas why no session is created ? Thanks

Community
  • 1
  • 1
Urbanleg
  • 6,252
  • 16
  • 76
  • 139
  • 1
    I hope keeping the client side code in `Servlet` or `jsp` instead of plain html might help, since session object will be initiated in those cases. I haven't tried though. – Stalin Gino Dec 13 '14 at 20:25
  • I have this issue only if I access my web app through a reverse proxy (nginx). On direct access, getHttpSession does not return null. What is different when using nginx? – mihca Jan 17 '22 at 13:34
  • Found my issue: was mixing "localhost" and "127.0.0.1" in URLs. The http session id was not sent for the other host name I guess. – mihca Jan 17 '22 at 14:18

4 Answers4

11

This is intended behaviour, but I agree it might be confusing. From the HandshakeRequest.getHttpSession javadoc:

/**
 * Return a reference to the HttpSession that the web socket handshake that 
 * started this conversation was part of, if the implementation
 * is part of a Java EE web container.
 *
 * @return the http session or {@code null} if either the websocket
 * implementation is not part of a Java EE web container, or there is
 * no HttpSession associated with the opening handshake request.
 */

Problem is, that HttpSession was not yet created for your client connection and WebSocket API implementation just asks whether there is something created and if not, it does not create it. What you need to do is call httpServletRequest.getSession() sometime before WebSocket impl filter is invoked (doFilter(...) is called).

This can be achieved for example by calling mentioned method in ServletRequestListener#requestInitalized or in different filter, etc..

Pavel Bucek
  • 5,304
  • 27
  • 44
  • 4
    How do you get the httpservletRequest object from the ServletRequestEvent pServletRequestEvent object passed to the requestInitalized method? – xMythicx Sep 03 '15 at 14:28
9

Here is an impl for Pavel Bucek's Answer, after adding it, i got my session

import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpServletRequest;

@WebListener
public class RequestListener implements ServletRequestListener {

    @Override
    public void requestDestroyed(ServletRequestEvent sre) {
        // TODO Auto-generated method stub

    }

    @Override
    public void requestInitialized(ServletRequestEvent sre) {
        ((HttpServletRequest) sre.getServletRequest()).getSession();
    }

}
wutzebaer
  • 14,365
  • 19
  • 99
  • 170
  • Since I usually disable Jar Scanning for a faster startup, I had to also add a listener to web.xml, e.g. `path.to.RequestListener` in order to register the `@WebListener` without relying on the annotations. – isapir Sep 22 '16 at 04:30
1

Building on @pavel-bucek 's answer, I wrote a simple HttpSessionInitializerFilter servlet filter.

Just download the jar from the "Releases" page and save it anywhere in the classpath, then add the following snippet to your web.xml descriptor (modify the url-pattern as needed):

<filter>
  <filter-name>HttpSessionInitializerFilter</filter-name>
  <filter-class>net.twentyonesolutions.servlet.filter.HttpSessionInitializerFilter</filter-class>
</filter>

<filter-mapping>
  <filter-name>HttpSessionInitializerFilter</filter-name>
  <url-pattern>/ws/*</url-pattern>
</filter-mapping>
isapir
  • 21,295
  • 13
  • 115
  • 116
0

first: create a new class

import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpServletRequest;

@WebListener

public class RequestListener implements ServletRequestListener {

    @Override
    public void requestDestroyed(ServletRequestEvent servletRequestEvent) {
    }

    @Override
    public void requestInitialized(ServletRequestEvent servletRequestEvent) {
        ((HttpServletRequest)servletRequestEvent.getServletRequest()).getSession();
    }
}

and then add the "ServletComponentScan" annotation on the App main:

@SpringBootApplication

@ServletComponentScan

public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
Vosang
  • 1