WebSocket Server

Jetty provides two API implementations of the WebSocket protocol:

Using the standard jakarta.websocket APIs allows your applications to depend only on standard APIs, and your applications may be deployed in any compliant WebSocket Container that supports Jakarta WebSocket 2.0.

The standard APIs provide these features that are not present in the Jetty WebSocket APIs:

  • Encoders and Decoders for automatic conversion of text or binary messages to objects.

On the other hand, the Jetty WebSocket APIs are more efficient and offer greater and more fine-grained control, and provide these features that are not present in the standard APIs:

  • Suspend/resume to control backpressure.

  • Remote socket address (IP address and port) information.

  • WebSocket upgrade handling via Filter or Servlet.

  • Advanced URI matching with Servlet WebSocket upgrade.

  • Configuration of the network buffer capacity.

If your application needs specific features that are not provided by the standard APIs, the Jetty WebSocket APIs may provide such features — and if they do not, you may ask for these features by submitting an issue to the Jetty Project without waiting for the standard process to approve them.

Standard APIs Implementation

When you write a WebSocket application using the standard jakarta.websocket APIs, your code typically need to depend on just the APIs to compile your application. However, at runtime you need to have an implementation of the standard APIs in your class-path (or module-path).

The standard jakarta.websocket APIs are provided by the following Maven artifact:

<dependency>
  <groupId>jakarta.websocket</groupId>
  <artifactId>jakarta.websocket-api</artifactId>
  <version>2.0.0</version>
</dependency>

However, the artifact above lacks a proper JPMS module-info.class file, and therefore it is a little more difficult to use if you want to use of JPMS for your application.

If you want to use JPMS for your application, you can use this Maven artifact instead:

<dependency>
  <groupId>org.eclipse.jetty.toolchain</groupId>
  <artifactId>jetty-jakarta-websocket-api</artifactId>
  <version>2.0.0</version>
</dependency>

This artifact is nothing more than the jakarta.websocket:jakarta.websocket-api:2.0.0 artifact repackaged with a proper module-info.class file.

At runtime, you also need an implementation of the standard jakarta.websocket APIs.

Jetty’s implementation of the standard jakarta.websocket APIs is provided by the following Maven artifact (and its transitive dependencies):

<dependency>
  <groupId>org.eclipse.jetty.websocket</groupId>
  <artifactId>websocket-jakarta-server</artifactId>
  <version>11.0.21-SNAPSHOT</version>
</dependency>

The jakarta.websocket-api artifact and the websocket-jakarta-server artifact (and its transitive dependencies) should be present in the server class-path (or module-path), and never in the web application’s /WEB-INF/lib directory.

To configure correctly your WebSocket application based on the standard jakarta.websocket APIs, you need two steps:

  1. Make sure that Jetty sets up an instance of jakarta.websocket.server.ServerContainer.

  2. Configure the WebSocket endpoints that implement your application logic, either by annotating their classes with the standard jakarta.websocket annotations, or by using the ServerContainer APIs to register them in your code.

Setting Up ServerContainer

Jetty sets up a ServerContainer instance using JakartaWebSocketServletContainerInitializer.

When you deploy web applications using WebAppContext, then JakartaWebSocketServletContainerInitializer is automatically discovered and initialized by Jetty when the web application starts, so that it sets up the ServerContainer. In this way, you do not need to write any additional code:

// Create a Server with a ServerConnector listening on port 8080.
Server server = new Server(8080);

// Create a WebAppContext with the given context path.
WebAppContext handler = new WebAppContext("/path/to/webapp", "/ctx");
server.setHandler(handler);

// Starting the Server will start the WebAppContext.
server.start();

On the other hand, when you deploy web applications using ServletContextHandler, you have to write the code to ensure that the JakartaWebSocketServletContainerInitializer is initialized, so that it sets up the ServerContainer:

// Create a Server with a ServerConnector listening on port 8080.
Server server = new Server(8080);

// Create a ServletContextHandler with the given context path.
ServletContextHandler handler = new ServletContextHandler(server, "/ctx");
server.setHandler(handler);

// Ensure that JavaxWebSocketServletContainerInitializer is initialized,
// to setup the ServerContainer for this web application context.
JakartaWebSocketServletContainerInitializer.configure(handler, null);

// Starting the Server will start the ServletContextHandler.
server.start();

Calling JakartaWebSocketServletContainerInitializer.configure(...) must be done before the ServletContextHandler is started, and configures the jakarta.websocket implementation for that web application context.

Configuring Endpoints

Once you have setup the ServerContainer, you can configure your WebSocket endpoints.

The WebSocket endpoints classes may be either annotated with the standard jakarta.websocket annotations, extend the jakarta.websocket.Endpoint abstract class, or implement the jakarta.websocket.server.ServerApplicationConfig interface.

When you deploy web applications using WebAppContext, then annotated WebSocket endpoint classes are automatically discovered and registered. In this way, you do not need to write any additional code; you just need to ensure that your WebSocket endpoint classes are present in the web application’s /WEB-INF/classes directory, or in a *.jar file in /WEB-INF/lib.

On the other hand, when you deploy web applications using WebAppContext but you need to perform more advanced configuration of the ServerContainer or of the WebSocket endpoints, or when you deploy web applications using ServletContextHandler, you need to access the ServerContainer APIs.

The ServerContainer instance is stored as a ServletContext attribute, so it can be retrieved when the ServletContext is initialized, either from a ServletContextListener or from a HttpServlet:

// Create a Server with a ServerConnector listening on port 8080.
Server server = new Server(8080);

// Create a ServletContextHandler with the given context path.
ServletContextHandler handler = new ServletContextHandler(server, "/ctx");
server.setHandler(handler);

// Ensure that JavaxWebSocketServletContainerInitializer is initialized,
// to setup the ServerContainer for this web application context.
JakartaWebSocketServletContainerInitializer.configure(handler, null);

// Add a WebSocket-initializer Servlet to register WebSocket endpoints.
handler.addServlet(MyJavaxWebSocketInitializerServlet.class, "/*");

// Starting the Server will start the ServletContextHandler.
server.start();
public class MyJavaxWebSocketInitializerServlet extends HttpServlet
{
    @Override
    public void init() throws ServletException
    {
        try
        {
            // Retrieve the ServerContainer from the ServletContext attributes.
            ServerContainer container = (ServerContainer)getServletContext().getAttribute(ServerContainer.class.getName());

            // Configure the ServerContainer.
            container.setDefaultMaxTextMessageBufferSize(128 * 1024);

            // Simple registration of your WebSocket endpoints.
            container.addEndpoint(MyJavaxWebSocketEndPoint.class);

            // Advanced registration of your WebSocket endpoints.
            container.addEndpoint(
                ServerEndpointConfig.Builder.create(MyJavaxWebSocketEndPoint.class, "/ws")
                    .subprotocols(List.of("my-ws-protocol"))
                    .build()
            );
        }
        catch (DeploymentException x)
        {
            throw new ServletException(x);
        }
    }
}

When you deploy web applications using ServletContextHandler, you can also use this variant to set up the ServerContainer and configure the WebSocket endpoints in one step:

// Create a Server with a ServerConnector listening on port 8080.
Server server = new Server(8080);

// Create a ServletContextHandler with the given context path.
ServletContextHandler handler = new ServletContextHandler(server, "/ctx");
server.setHandler(handler);

// Setup the ServerContainer and the WebSocket endpoints for this web application context.
JakartaWebSocketServletContainerInitializer.configure(handler, (servletContext, container) ->
{
    // Configure the ServerContainer.
    container.setDefaultMaxTextMessageBufferSize(128 * 1024);

    // Simple registration of your WebSocket endpoints.
    container.addEndpoint(MyJavaxWebSocketEndPoint.class);

    // Advanced registration of your WebSocket endpoints.
    container.addEndpoint(
        ServerEndpointConfig.Builder.create(MyJavaxWebSocketEndPoint.class, "/ws")
            .subprotocols(List.of("my-ws-protocol"))
            .build()
    );
});

// Starting the Server will start the ServletContextHandler.
server.start();

When the ServletContextHandler is started, the Configurator lambda (the second parameter passed to JakartaWebSocketServletContainerInitializer.configure(...)) is invoked and allows you to explicitly configure the WebSocket endpoints using the standard APIs provided by ServerContainer.

Upgrade to WebSocket

Under the hood, JakartaWebSocketServletContainerInitializer installs the org.eclipse.jetty.websocket.servlet.WebSocketUpgradeFilter, which is the component that intercepts HTTP requests to upgrade to WebSocket, and performs the upgrade from the HTTP protocol to the WebSocket protocol.

The WebSocketUpgradeFilter is installed under the filter name corresponding to its class name (that is, the string "org.eclipse.jetty.websocket.servlet.WebSocketUpgradeFilter") and with a filter mapping of /*.

Refer to the advanced WebSocketUpgradeFilter configuration section for more information.

With the default configuration, every HTTP request flows first through the WebSocketUpgradeFilter.

If the HTTP request is a valid upgrade to WebSocket, then WebSocketUpgradeFilter tries to find a matching WebSocket endpoint for the request URI path; if the match is found, WebSocketUpgradeFilter performs the upgrade and does not invoke any other Filter or Servlet. From this point on, the communication happens with the WebSocket protocol, and HTTP components such as Filters and Servlets are not relevant anymore.

If the HTTP request is not an upgrade to WebSocket, or WebSocketUpgradeFilter did not find a matching WebSocket endpoint for the request URI path, then the request is passed to the Filter chain of your web application, and eventually the request arrives to a Servlet to be processed (otherwise a 404 Not Found response is returned to client).

Jetty APIs Implementation

When you write a WebSocket application using the Jetty WebSocket APIs, your code typically need to depend on just the Jetty WebSocket APIs to compile your application. However, at runtime you need to have the implementation of the Jetty WebSocket APIs in your class-path (or module-path).

Jetty’s WebSocket APIs are provided by the following Maven artifact:

<dependency>
  <groupId>org.eclipse.jetty.websocket</groupId>
  <artifactId>websocket-jetty-api</artifactId>
  <version>11.0.21-SNAPSHOT</version>
</dependency>

Jetty’s implementation of the Jetty WebSocket APIs is provided by the following Maven artifact (and its transitive dependencies):

<dependency>
  <groupId>org.eclipse.jetty.websocket</groupId>
  <artifactId>websocket-jetty-server</artifactId>
  <version>11.0.21-SNAPSHOT</version>
</dependency>

The websocket-jetty-api artifact and the websocket-jetty-server artifact (and its transitive dependencies) should be present in the server class-path (or module-path), and never in the web application’s /WEB-INF/lib directory.

To configure correctly your WebSocket application based on the Jetty WebSocket APIs, you need two steps:

  1. Make sure that Jetty sets up an instance of JettyWebSocketServerContainer.

  2. Use the JettyWebSocketServerContainer APIs in your applications to register your WebSocket endpoints that implement your application logic.

You can read more about the Jetty WebSocket architecture, which is common to both client-side and server-side, to get familiar with the terminology used in the following sections.

Setting up JettyWebSocketServerContainer

Jetty sets up a JettyWebSocketServerContainer instance using JettyWebSocketServletContainerInitializer.

When you deploy web applications using WebAppContext, then JettyWebSocketServletContainerInitializer is automatically discovered and initialized by Jetty when the web application starts, so that it sets up the JettyWebSocketServerContainer. In this way, you do not need to write any additional code:

// Create a Server with a ServerConnector listening on port 8080.
Server server = new Server(8080);

// Create a WebAppContext with the given context path.
WebAppContext handler = new WebAppContext("/path/to/webapp", "/ctx");
server.setHandler(handler);

// Starting the Server will start the WebAppContext.
server.start();

On the other hand, when you deploy web applications using ServletContextHandler, you have to write the code to ensure that the JettyWebSocketServletContainerInitializer is initialized, so that it sets up the JettyWebSocketServerContainer:

// Create a Server with a ServerConnector listening on port 8080.
Server server = new Server(8080);

// Create a ServletContextHandler with the given context path.
ServletContextHandler handler = new ServletContextHandler(server, "/ctx");
server.setHandler(handler);

// Ensure that JettyWebSocketServletContainerInitializer is initialized,
// to setup the JettyWebSocketServerContainer for this web application context.
JettyWebSocketServletContainerInitializer.configure(handler, null);

// Starting the Server will start the ServletContextHandler.
server.start();

Calling JettyWebSocketServletContainerInitializer.configure(...) must be done before the ServletContextHandler is started, and configures the Jetty WebSocket implementation for that web application context.

Configuring Endpoints

Once you have setup the JettyWebSocketServerContainer, you can configure your WebSocket endpoints.

Differently from the configuration of standard WebSocket endpoints, WebSocket endpoint classes may be annotated with Jetty WebSocket API annotations, or extend the org.eclipse.jetty.websocket.api.WebSocketListener interface, but they are not automatically discovered, not even when deploying web applications using WebAppContext.

When using the Jetty WebSocket APIs, WebSocket endpoints must always be explicitly configured.

There are two ways of configuring WebSocket endpoints when using the Jetty WebSocket APIs:

Using JettyWebSocketServerContainer

To register WebSocket endpoints using the Jetty WebSocket APIs you need to access the JettyWebSocketServerContainer APIs.

The JettyWebSocketServerContainer instance is stored in the ServletContext, so it can be retrieved when the ServletContext is initialized, either from a ServletContextListener or from a HttpServlet:

// Create a Server with a ServerConnector listening on port 8080.
Server server = new Server(8080);

// Create a ServletContextHandler with the given context path.
ServletContextHandler handler = new ServletContextHandler(server, "/ctx");
server.setHandler(handler);

// Ensure that JettyWebSocketServletContainerInitializer is initialized,
// to setup the JettyWebSocketServerContainer for this web application context.
JettyWebSocketServletContainerInitializer.configure(handler, null);

// Add a WebSocket-initializer Servlet to register WebSocket endpoints.
handler.addServlet(MyJettyWebSocketInitializerServlet.class, "/*");

// Starting the Server will start the ServletContextHandler.
server.start();
public class MyJettyWebSocketInitializerServlet extends HttpServlet
{
    @Override
    public void init() throws ServletException
    {
        // Retrieve the JettyWebSocketServerContainer.
        JettyWebSocketServerContainer container = JettyWebSocketServerContainer.getContainer(getServletContext());

        // Configure the JettyWebSocketServerContainer.
        container.setMaxTextMessageSize(128 * 1024);

        // Simple registration of your WebSocket endpoints.
        container.addMapping("/ws/myURI", MyJettyWebSocketEndPoint.class);

        // Advanced registration of your WebSocket endpoints.
        container.addMapping("/ws/myOtherURI", (upgradeRequest, upgradeResponse) ->
            new MyOtherJettyWebSocketEndPoint()
        );
    }
}

You can also use this variant to set up the JettyWebSocketServerContainer and configure the WebSocket endpoints in one step:

// Create a Server with a ServerConnector listening on port 8080.
Server server = new Server(8080);

// Create a ServletContextHandler with the given context path.
ServletContextHandler handler = new ServletContextHandler(server, "/ctx");
server.setHandler(handler);

// Setup the JettyWebSocketServerContainer and the WebSocket endpoints for this web application context.
JettyWebSocketServletContainerInitializer.configure(handler, (servletContext, container) ->
{
    // Configure the ServerContainer.
    container.setMaxTextMessageSize(128 * 1024);

    // Add your WebSocket endpoint(s) to the JettyWebSocketServerContainer.
    container.addMapping("/ws/myURI", MyJettyWebSocketEndPoint.class);

    // Use JettyWebSocketCreator to have more control on the WebSocket endpoint creation.
    container.addMapping("/ws/myOtherURI", (upgradeRequest, upgradeResponse) ->
    {
        // Possibly inspect the upgrade request and modify the upgrade response.
        upgradeResponse.setAcceptedSubProtocol("my-ws-protocol");

        // Create the new WebSocket endpoint.
        return new MyOtherJettyWebSocketEndPoint();
    });
});

// Starting the Server will start the ServletContextHandler.
server.start();

In the call to JettyWebSocketServerContainer.addMapping(...), you can specify a path spec (the first parameter) that can be configured as specified in this section.

When the ServletContextHandler is started, the Configurator lambda (the second parameter passed to JettyWebSocketServletContainerInitializer.configure(...)) is invoked and allows you to explicitly configure the WebSocket endpoints using the Jetty WebSocket APIs provided by JettyWebSocketServerContainer.

Under the hood, the call to JettyWebSocketServerContainer.addMapping(...) installs the org.eclipse.jetty.websocket.servlet.WebSocketUpgradeFilter, which is the component that intercepts HTTP requests to upgrade to WebSocket, described in this section. For more information about the configuration of WebSocketUpgradeFilter see also this section.

One last alternative to register your WebSocket endpoints is to use a programmatic WebSocket upgrade via JettyWebSocketServerContainer.upgrade(...), which allows you to use a standard HttpServlet subclass (rather than a JettyWebSocketServlet as explained in this section) to perform a direct WebSocket upgrade when your application logic demands so:

// Create a Server with a ServerConnector listening on port 8080.
Server server = new Server(8080);

// Create a ServletContextHandler with the given context path.
ServletContextHandler handler = new ServletContextHandler(server, "/ctx");
server.setHandler(handler);

// Ensure that JettyWebSocketServletContainerInitializer is initialized,
// to setup the JettyWebSocketServerContainer for this web application context.
JettyWebSocketServletContainerInitializer.configure(handler, null);

// Starting the Server will start the ServletContextHandler.
server.start();
public class ProgrammaticWebSocketUpgradeServlet extends HttpServlet
{
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException
    {
        if (requiresWebSocketUpgrade(request))
        {
            // Retrieve the JettyWebSocketServerContainer.
            JettyWebSocketServerContainer container = JettyWebSocketServerContainer.getContainer(getServletContext());

            // Use a JettyWebSocketCreator to inspect the upgrade request,
            // possibly modify the upgrade response, and create the WebSocket endpoint.
            JettyWebSocketCreator creator = (upgradeRequest, upgradeResponse) -> new MyJettyWebSocketEndPoint();

            // Perform the direct WebSocket upgrade.
            container.upgrade(creator, request, response);
        }
        else
        {
            // Normal handling of the HTTP request/response.
        }
    }
}

When using JettyWebSocketServerContainer.upgrade(...), the WebSocketUpgradeFilter is not installed, since the WebSocket upgrade is performed programmatically.

Using JettyWebSocketServlet

An alternative way to register WebSocket endpoints using the Jetty WebSocket APIs is to use a JettyWebSocketServlet subclass (or even many different JettyWebSocketServlet subclasses).

This method has the advantage that it does not install the WebSocketUpgradeFilter under the hood, because the WebSocket upgrade is handled directly by your JettyWebSocketServlet subclass. This may also have a performance benefit for non-WebSocket HTTP requests (as they will not pass through the WebSocketUpgradeFilter).

Your JettyWebSocketServlet subclass may be declared and configured either in code or in web.xml. Declaring your JettyWebSocketServlet subclass explicitly in code or in web.xml also simplifies the declaration and configuration of other web components such as other Servlets and/or Filters (for example, it is easier to configure the CrossOriginFilter, see also this section for more information).

For example, your JettyWebSocketServlet subclass may be declared in code in this way:

// Create a Server with a ServerConnector listening on port 8080.
Server server = new Server(8080);

// Create a ServletContextHandler with the given context path.
ServletContextHandler handler = new ServletContextHandler(server, "/ctx");
server.setHandler(handler);

// Setup the JettyWebSocketServerContainer to initialize WebSocket components.
JettyWebSocketServletContainerInitializer.configure(handler, null);

// Add your WebSocketServlet subclass to the ServletContextHandler.
handler.addServlet(MyJettyWebSocketServlet.class, "/ws/*");

// Starting the Server will start the ServletContextHandler.
server.start();
public class MyJettyWebSocketServlet extends JettyWebSocketServlet
{
    @Override
    protected void configure(JettyWebSocketServletFactory factory)
    {
        // At most 1 MiB text messages.
        factory.setMaxTextMessageSize(1048576);

        // Add the WebSocket endpoint.
        factory.addMapping("/ws/someURI", (upgradeRequest, upgradeResponse) ->
        {
            // Possibly inspect the upgrade request and modify the upgrade response.

            // Create the new WebSocket endpoint.
            return new MyJettyWebSocketEndPoint();
        });
    }
}

Note how in the call to JettyWebSocketServletContainerInitializer.configure(...) the second parameter is null, because WebSocket endpoints are not created here, but instead by one (or more) JettyWebSocketServlet subclasses. Yet the call is necessary to create other WebSocket implementation components that are necessary also when using JettyWebSocketServlet subclasses.

An HTTP upgrade request to WebSocket that matches your JettyWebSocketServlet subclass path mapping (specified above via ServletContextHandler.addServlet(...)) arrives at the Servlet and is inspected to verify whether it is a valid upgrade to WebSocket.

If the HTTP request is a valid upgrade to WebSocket, JettyWebSocketServlet calls configure(JettyWebSocketServletFactory factory) that you have overridden in your subclass, so that your application can instantiate and return the WebSocket endpoint. After having obtained the WebSocket endpoint, JettyWebSocketServlet performs the WebSocket upgrade. From this point on, the communication happens with the WebSocket protocol, and HTTP components such as Filters and Servlets are not relevant anymore.

If the HTTP request is not an upgrade to WebSocket, JettyWebSocketServlet delegates the processing to the superclass, jakarta.servlet.HttpServlet, which in turn invokes methods such as doGet(...) or doPost(...) depending on the HTTP method. If your JettyWebSocketServlet subclass did not override the doXYZ(...) method corresponding to the HTTP request, a 405 Method Not Allowed response is returned to the client, as per the standard HttpServlet class implementation.

It is possible to use both JettyWebSocketServerContainer and JettyWebSocketServlet.

However, it is typically best to avoid mixing the use of JettyWebSocketServerContainer with the use of JettyWebSocketServlet, so that all your WebSocket endpoints are initialized by the same code in one place only.

Using JettyWebSocketServerContainer.addMapping(...) will install the WebSocketUpgradeFilter under the hood, which by default will intercepts all HTTP requests to upgrade to WebSocket. However, as explained in this section, if WebSocketUpgradeFilter does not find a matching WebSocket endpoint for the request URI path, then the HTTP request is passed to the Filter chain of your web application and may arrive to your JettyWebSocketServlet subclass, where it would be processed and possibly result in a WebSocket upgrade.

Custom PathSpec Mappings

The JettyWebSocketServerContainer.addMapping(...) API maps a path spec to a JettyWebSocketCreator instance (typically a lambda expression). The path spec is matched against the WebSocket upgrade request URI to select the correspondent JettyWebSocketCreator to invoke.

The path spec can have these forms:

  • Servlet syntax, specified with servlet|<path spec>, where the servlet| prefix can be omitted if the path spec begins with / or *. (for example, /ws, /ws/chat or *.ws).

  • Regex syntax, specified with regex|<path spec>, where the regex| prefix can be omitted if the path spec begins with ^ (for example, ^/ws/[0-9]+).

  • URI template syntax, specified with uri-template|<path spec> (for example uri-template|/ws/chat/{room}).

Within the JettyWebSocketCreator, it is possible to access the path spec and, for example in case of URI templates, extract additional information in the following way:

ServletContextHandler handler = new ServletContextHandler(server, "/ctx");

// Configure the JettyWebSocketServerContainer.
JettyWebSocketServletContainerInitializer.configure(handler, (servletContext, container) ->
{
    container.addMapping("/ws/chat/{room}", (upgradeRequest, upgradeResponse) ->
    {
        // Retrieve the URI template.
        UriTemplatePathSpec pathSpec = (UriTemplatePathSpec)upgradeRequest.getServletAttribute(PathSpec.class.getName());

        // Match the URI template.
        Map<String, String> params = pathSpec.getPathParams(upgradeRequest.getRequestPath());
        String room = params.get("room");

        // Create the new WebSocket endpoint with the URI template information.
        return new MyWebSocketRoomEndPoint(room);
    });
});

Advanced WebSocketUpgradeFilter Configuration

The WebSocketUpgradeFilter that handles the HTTP requests that upgrade to WebSocket is installed in these cases:

  • Either by the JakartaWebSocketServletContainerInitializer, as described in this section.

  • Or by a call to JettyWebSocketServerContainer.addMapping(...), as described in this section.

Typically, the WebSocketUpgradeFilter is not present in the web.xml configuration, and therefore the mechanisms above create a new WebSocketUpgradeFilter and install it before any other Filter declared in web.xml, under the default name of "org.eclipse.jetty.websocket.servlet.WebSocketUpgradeFilter" and with path mapping /*.

However, if the WebSocketUpgradeFilter is already present in web.xml under the default name, then the ServletContainerInitializers will use that declared in web.xml instead of creating a new one.

This allows you to customize:

  • The filter order; for example, by configuring the CrossOriginFilter (or other filters) for increased security or authentication before the WebSocketUpgradeFilter.

  • The WebSocketUpgradeFilter configuration via init-params, that affects all Session instances created by this filter.

  • The WebSocketUpgradeFilter path mapping. Rather than the default mapping of /*, you can map the WebSocketUpgradeFilter to a more specific path such as /ws/*.

  • The possibility to have multiple WebSocketUpgradeFilters, mapped to different paths, each with its own configuration.

For example:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
         version="5.0">
  <display-name>My WebSocket WebApp</display-name>

  <!-- The CrossOriginFilter *must* be the first --> (1)
  <filter>
    <filter-name>cross-origin</filter-name>
    <filter-class>org.eclipse.jetty.servlets.CrossOriginFilter</filter-class>
    <async-supported>true</async-supported>
  </filter>
  <filter-mapping>
    <filter-name>cross-origin</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

  <!-- Configure the default WebSocketUpgradeFilter --> (2)
  <filter>
    <!-- The filter name must be the default WebSocketUpgradeFilter name -->
    <filter-name>org.eclipse.jetty.websocket.servlet.WebSocketUpgradeFilter</filter-name> (3)
    <filter-class>org.eclipse.jetty.websocket.servlet.WebSocketUpgradeFilter</filter-class>
    <!-- Configure at most 1 MiB text messages -->
    <init-param> (4)
      <param-name>maxTextMessageSize</param-name>
      <param-value>1048576</param-value>
    </init-param>
    <async-supported>true</async-supported>
  </filter>
  <filter-mapping>
    <filter-name>org.eclipse.jetty.websocket.servlet.WebSocketUpgradeFilter</filter-name>
    <!-- Use a more specific path mapping for WebSocket requests -->
    <url-pattern>/ws/*</url-pattern> (5)
  </filter-mapping>

</web-app>
1 The CrossOriginFilter is the first to protect against cross-site request forgery attacks.
2 The configuration for the default WebSocketUpgradeFilter.
3 Note the use of the default WebSocketUpgradeFilter name.
4 Specific configuration for WebSocketUpgradeFilter parameters.
5 Use a more specific path mapping for WebSocketUpgradeFilter.

Note that using a more specific path mapping for WebSocket requests is also beneficial to the performance of normal HTTP requests: they do not go through the WebSocketUpgradeFilter (as they will not match its path mapping), saving the cost of analyzing them to see whether they are WebSocket upgrade requests or not.