Is it possible to get the HttpServletRequest inside a @ServerEndpoint? Primarily I am trying to get it so I can access the HttpSession object.
Update (November 2016): The information provided in this answer is for the JSR356 spec, individual implementations of the spec may vary outside of this information. Other suggestions found in comments and other answers are all implementation specific behaviors outside of the JSR356 spec.
If the suggestions in here are causing you problems, upgrade your various installations of Jetty, Tomcat, Wildfly, or Glassfish/Tyrus. All current versions of those implementations have all been reported to work in the way outlined below.
Now back to the original answer from August 2013...
The answer from Martin Andersson has a concurrency flaw. The Configurator can be called by multiple threads at the same time, it is likely that you will not have access to the correct HttpSession object between the calls from modifyHandshake()
and getEndpointInstance()
.
Or said another way...
Here's a modification to Martin's code that uses ServerEndpointConfig.getUserProperties()
map to make the HttpSession
available to your socket instance during the @OnOpen
method call
GetHttpSessionConfigurator.java
package examples;
import javax.servlet.http.HttpSession;
import javax.websocket.HandshakeResponse;
import javax.websocket.server.HandshakeRequest;
import javax.websocket.server.ServerEndpointConfig;
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);
}
}
GetHttpSessionSocket.java
package examples;
import java.io.IOException;
import javax.servlet.http.HttpSession;
import javax.websocket.EndpointConfig;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
@ServerEndpoint(value = "/example",
configurator = GetHttpSessionConfigurator.class)
public class GetHttpSessionSocket
{
private Session wsSession;
private HttpSession httpSession;
@OnOpen
public void open(Session session, EndpointConfig config) {
this.wsSession = session;
this.httpSession = (HttpSession) config.getUserProperties()
.get(HttpSession.class.getName());
}
@OnMessage
public void echo(String msg) throws IOException {
wsSession.getBasicRemote().sendText(msg);
}
}
Bonus feature: no instanceof
or casting required.
Some EndpointConfig Knowledge
EndpointConfig
objects do exist per "Endpoint Instance".
However, an "Endpoint Instance" has 2 meanings with the spec.
javax.websocket.Session
that ties together the object endpoint instance, with its configuration, to a specific logical connection.It is possible to have a singleton Endpoint instance being used for multiple javax.websocket.Session
instances (that is one of the features that ServerEndpointConfig.Configurator
supports)
The ServerContainer implementation will track a set of ServerEndpointConfig's that represent all of the deployed endpoints that the server can respond to a websocket upgrade request.
These ServerEndpointConfig object instances can come from a few different sources.
javax.websocket.server.ServerContainer.addEndpoint(ServerEndpointConfig)
javax.servlet.ServletContextInitializer.contextInitialized(ServletContextEvent sce)
calljavax.websocket.server.ServerApplicationConfig.getEndpointConfigs(Set)
call.@ServerEndpoint
annotated classes.These ServerEndpointConfig
object instances exist as defaults for when a javax.websocket.Session
does eventually get created.
ServerEndpointConfig.Configurator Instance
Before any upgrade requests are received or processed, all of the ServerEndpointConfig.Configurator
objects now exist and are ready to perform their main and sole purpose, to allow for customization of the upgrade process of a websocket connection to an eventual javax.websocket.Session
Access to Session specific EndpointConfig
Note, you cannot access the ServerEndpointConfig
object instances from within a endpoint instance. You can only access EndpointConfig
instances.
This means if you provided ServerContainer.addEndpoint(new MyCustomServerEndpointConfig())
during deploy and later tried to access it via the annotations, it will not work.
All of the following would be invalid.
@OnOpen
public void onOpen(Session session, EndpointConfig config)
{
MyCustomServerEndpointConfig myconfig = (MyCustomServerEndpointConfig) config;
/* this would fail as the config is cannot be cast around like that */
}
// --- or ---
@OnOpen
public void onOpen(Session session, ServerEndpointConfig config)
{
/* For @OnOpen, the websocket implementation would assume
that the ServerEndpointConfig to be a declared PathParam
*/
}
// --- or ---
@OnOpen
public void onOpen(Session session, MyCustomServerEndpointConfig config)
{
/* Again, for @OnOpen, the websocket implementation would assume
that the MyCustomServerEndpointConfig to be a declared PathParam
*/
}
You can access the EndpointConfig during the life of the Endpoint object instance, but under a limited time. The javax.websocket.Endpoint.onOpen(Session,Endpoint)
, annotated @OnOpen
methods, or via the use of CDI. The EndpointConfig is not available in any other way or at any other time.
However, you can always access the UserProperties via the Session.getUserProperties()
call, which is available always. This User Properties map is always available, be it via the annotated techniques (such as a Session parameter during @OnOpen
, @OnClose
, @OnError
, or @OnMessage
calls), via CDI injection of the Session, or even with the use of non-annotated websockets that extend from javax.websocket.Endpoint
.
How Upgrade Works
As stated before, every one of the defined endpoints will have a ServerEndpointConfig
associated with it.
Those ServerEndpointConfigs
are a single instance that represents the default state of the EndpointConfig
that are eventually made available to the Endpoint Instances that are possibly and eventually created.
When a incoming upgrade request arrives, it has go through the following on the JSR.
To note, the ServerEndpointConfig.Configurator is a singleton, per mapped ServerContainer endpoint.
This is intentional, and desired, to allow implementors several features.
If the implementations created a new Configurator for every handshake, this technique would not be possible.
(Disclosure: I write and maintain the JSR-356 implementation for Jetty 9)