Search code examples
jakarta-eewebsocketendpointpath-parameter

Making path parameters optional in WebSocket endpoints in Java EE


Given a WebSocket endpoint as follows.

@ServerEndpoint(value = "/Push/CartPush/{token}")
public final class CartPush {
    // ...
}

The endpoint is able to accept a path parameter {token}. The path parameter is however, optional which is determined dynamically at run-time in Java Script. Skipping this parameter in JavaScript like the following results in 404.

var ws = new WebSocket("wss://localhost:8443/ContextPath/Push/CartPush");

WebSocket connection to 'wss://localhost:8443/ContextPath/Push/CartPush' failed: Error during WebSocket handshake: Unexpected response code: 404

It makes the token value compulsory as follows.

var token = "token value";
var ws = new WebSocket("wss://localhost:8443/ContextPath/Push/CartPush" + "/" + token);

In order to exclude all unneeded HTTP methods except GET and POST, I use the following restrictions or constraints along with Servlet security constraints using appropriate URL patterns and role mappings in web.xml.

<security-constraint>
    <web-resource-collection>
        <web-resource-name>Disable unneeded HTTP methods by 403</web-resource-name>

        <url-pattern>/Public/*</url-pattern>
        <url-pattern>/Push/*</url-pattern>
        <url-pattern>/javax.faces.resource/*</url-pattern>

        <http-method>GET</http-method>
        <http-method>POST</http-method>
    </web-resource-collection>
</security-constraint>

<deny-uncovered-http-methods/> <!-- Requires Servlet 3.1 -->

How to make the given path parameter optional?

The server in use is WildFly 10.0.0 final / Java EE 7.


Solution

  • Unfortunately, WS URI template is documented to follow [RFC 6570 Level 1] 2 templates. So a Level 3 template like /Push/CartPush{/token} won't work out.

    Your best bet is always suffixing it with / and let the token be an empty string.

    var token = "";
    var ws = new WebSocket("wss://localhost:8443/ContextPath/Push/CartPush/" + token);
    

    It might be worth an enhancement request at WS spec guys.

    Given that the parameter is fully defined in the client, an alternative is to supply it as a request parameter. Naturally, request parameters represent client-defined parameters.

    var ws = new WebSocket("wss://localhost:8443/ContextPath/Push/CartPush?token=" + token);
    
    String token = session.getRequestParameterMap().get("token").get(0);