//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//

= WebSocket Server

Jetty provides different implementations of the WebSocket protocol:

* A Jakarta EE 8 (`javax.websocket`) implementation, based on the https://jakarta.ee/specifications/websocket/1.1/[Jakarta WebSocket 1.1 Specification].
* A Jakarta EE 9 (`jakarta.websocket`) implementation, based on the https://jakarta.ee/specifications/websocket/2.0/[Jakarta WebSocket 2.0 Specification].
* A Jakarta EE 10 (`jakarta.websocket`) implementation, based on the https://jakarta.ee/specifications/websocket/2.1/[Jakarta WebSocket 2.1 Specification].
* A Jetty specific implementation, based on the Jetty WebSocket APIs, that does not depend on any Jakarta EE APIs.

The Jakarta EE implementations and APIs are described in <<standard,this section>>.

Using the standard Jakarta EE 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.
The standard Jakarta EE WebSocket 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.

The Jetty specific WebSocket implementation and APIs are described in <<jetty,this section>>.

Using the Jetty WebSocket APIs allows your applications to be more efficient and offer greater and more fine-grained control, and provide these features that are not present in the Jakarta EE WebSocket APIs:

* A demand mechanism to control backpressure.
* Remote socket address (IP address and port) information.
* Advanced request URI matching with regular expressions, in addition to Servlet patterns and URI template patterns.
* More configuration options, for example the network buffer capacity.
* Programmatic WebSocket upgrade, in addition to WebSocket upgrade based on URI matching, for maximum flexibility.

If your application needs specific features that are not provided by the standard APIs, the Jetty WebSocket APIs may provide such features.

TIP: If the feature you are looking for is not present, you may ask for these features by https://github.com/jetty/jetty.project/issues[submitting an issue] to the Jetty Project without waiting for the standard Jakarta EE process to approve them and release a new version of the Jakarta EE WebSocket specification.

[[standard]]
== 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, for example for Jakarta {ee-current-caps}, are provided by the following Maven artifact:

[,xml]
----
<dependency>
  <groupId>jakarta.websocket</groupId>
  <artifactId>jakarta.websocket-api</artifactId>
  <version>2.1.0</version>
</dependency>
----

At runtime, you also need an implementation of the standard Jakarta {ee-current-caps} WebSocket APIs, that Jetty provides with the following Maven artifact (and its transitive dependencies):

[,xml,subs=attributes+]
----
<dependency>
  <groupId>org.eclipse.jetty.{ee-current}.websocket</groupId>
  <artifactId>jetty-{ee-current}-websocket-jakarta-server</artifactId>
  <version>{jetty-version}</version>
</dependency>
----

[NOTE]
====
The `jakarta.websocket-api` artifact and the `jetty-{ee-current}-websocket-jakarta-server` artifact (and their 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 {ee-current-caps} WebSocket APIs, you need two steps:

. Make sure that Jetty sets up an instance of `jakarta.websocket.server.ServerContainer`, described in <<standard-container,this section>>.
. 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, described in <<standard-endpoints,this section>>.

[[standard-container]]
=== Setting Up `ServerContainer`

Jetty sets up a `ServerContainer` instance using `JakartaWebSocketServletContainerInitializer`.

When you deploy web applications using xref:server/http.adoc#handler-use-webapp-context[`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:

[,java,indent=0]
----
include::code:example$src/main/java/org/eclipse/jetty/docs/programming/server/websocket/WebSocketServerDocs.java[tags=standardContainerWebAppContext]
----

On the other hand, when you deploy web applications using xref:server/http.adoc#handler-use-servlet-context[`ServletContextHandler`], you have to write the code to ensure that the `JakartaWebSocketServletContainerInitializer` is initialized, so that it sets up the `ServerContainer`:

[,java,indent=0]
----
include::code:example$src/main/java/org/eclipse/jetty/docs/programming/server/websocket/WebSocketServerDocs.java[tags=standardContainerServletContextHandler]
----

Calling `JakartaWebSocketServletContainerInitializer.configure(\...)` must be done _before_ the `ServletContextHandler` is started, and configures the Jakarta {ee-current-caps} WebSocket implementation for that web application context, making `ServerContainer` available to web applications.

[[standard-endpoints]]
=== Configuring Endpoints

Once you have <<standard-container,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 xref:server/http.adoc#handler-use-webapp-context[`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 xref:server/http.adoc#handler-use-webapp-context[`WebAppContext`] but you need to perform more advanced configuration of the `ServerContainer` or of the WebSocket endpoints, or when you deploy web applications using xref:server/http.adoc#handler-use-servlet-context[`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 Servlet `Filter`, or from an `HttpServlet`:

[,java,indent=0]
----
include::code:example$src/main/java/org/eclipse/jetty/docs/programming/server/websocket/WebSocketServerDocs.java[tags=standardEndpointsInitialization]
----

[,java,indent=0]
----
include::code:example$src/main/java/org/eclipse/jetty/docs/programming/server/websocket/WebSocketServerDocs.java[tags=standardWebSocketInitializerServlet]
----

When you deploy web applications using xref:server/http.adoc#handler-use-servlet-context[`ServletContextHandler`], you can alternatively use the code below to set up the `ServerContainer` and configure the WebSocket endpoints in one step:

[,java,indent=0]
----
include::code:example$src/main/java/org/eclipse/jetty/docs/programming/server/websocket/WebSocketServerDocs.java[tags=standardContainerAndEndpoints]
----

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`.

[[standard-upgrade]]
==== Upgrade to WebSocket

Under the hood, `JakartaWebSocketServletContainerInitializer` installs the `org.eclipse.jetty.{ee-current}.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.

[NOTE]
====
The `WebSocketUpgradeFilter` is installed under the filter name corresponding to its class name (that is, the string `"org.eclipse.jetty.{ee-current}.websocket.servlet.WebSocketUpgradeFilter"`) and with a filter mapping of `/*`.

Refer to the <<configure-filter,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).

[[configure-filter]]
== Advanced `WebSocketUpgradeFilter` Configuration

The `WebSocketUpgradeFilter` that handles the HTTP requests that upgrade to WebSocket is installed by the `JakartaWebSocketServletContainerInitializer`, as described in <<standard,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.{ee-current}.websocket.servlet.WebSocketUpgradeFilter"` and with path mapping `/*`.

However, if the `WebSocketUpgradeFilter` is already present in `web.xml` under the default name, then the ``ServletContainerInitializer``s 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 filters for increased security or authentication _before_ the `WebSocketUpgradeFilter`.
* The `WebSocketUpgradeFilter` configuration via ``init-param``s, 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 ``WebSocketUpgradeFilter``s, mapped to different paths, each with its own configuration.

For example:

[,xml,subs=attributes+]
----
<?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 SecurityFilter *must* be the first --> <!--1-->
  <filter>
    <filter-name>security</filter-name>
    <filter-class>com.acme.SecurityFilter</filter-class>
    <async-supported>true</async-supported>
  </filter>
  <filter-mapping>
    <filter-name>security</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.{ee-current}.websocket.servlet.WebSocketUpgradeFilter</filter-name> <!--3-->
    <filter-class>org.eclipse.jetty.{ee-current}.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.{ee-current}.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 custom `SecurityFilter` is the first, to apply custom security.
<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.

[[jetty]]
== Jetty APIs Implementation

When you write a WebSocket application using the Jetty WebSocket APIs, your code typically needs 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:

[,xml,subs=attributes+]
----
<dependency>
  <groupId>org.eclipse.jetty.websocket</groupId>
  <artifactId>jetty-websocket-jetty-api</artifactId>
  <version>{jetty-version}</version>
</dependency>
----

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

[,xml,subs=attributes+]
----
<dependency>
  <groupId>org.eclipse.jetty.websocket</groupId>
  <artifactId>jetty-websocket-jetty-server</artifactId>
  <version>{jetty-version}</version>
</dependency>
----

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

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

. Make sure to <<jetty-container,set up>> an instance of `org.eclipse.jetty.websocket.server.ServerWebSocketContainer`.
. Use the `ServerWebSocketContainer` APIs in your applications to <<jetty-container-websocket-handler,register the WebSocket endpoints>> that implement your application logic.

You can read more about the xref:client/websocket.adoc#architecture[Jetty WebSocket architecture], which is common to both client-side and server-side, to get familiar with the terminology used in the following sections.

[[jetty-container]]
=== Setting up `ServerWebSocketContainer`

You need Jetty to set up a `ServerWebSocketContainer` instance to make your WebSocket applications based on the Jetty WebSocket APIs work.

Your WebSocket web application is represented by a `ContextHandler`.
The WebSocket upgrade is performed in a descendant (typically the only child) of the `ContextHandler`, either by the `org.eclipse.jetty.websocket.server.WebSocketUpgradeHandler`, or by a custom `Handler` that you write and is part of your web application.

In both cases, you need to set up a `ServerWebSocketContainer`, and this can be done <<jetty-container-websocket-handler,implicitly>> by using `WebSocketUpgradeHandler`, or <<jetty-container-websocket-container,explicitly>> by creating the `ServerWebSocketContainer` instance.

[[jetty-container-websocket-handler]]
==== Implicit setup using `WebSocketUpgradeHandler`

Using `WebSocketUpgradeHandler` is the most common way to set up your WebSocket applications.

You can use the `WebSocketUpgradeHandler` and the `ServerWebSocketContainer` APIs to map HTTP request URIs to WebSocket endpoints.

When an HTTP request arrives, `WebSocketUpgradeHandler` tests whether it is a WebSocket upgrade request, whether it matches a mapped URI, and if so upgrades the protocol to WebSocket.

From this point on, the communication on the upgraded connection happens with the WebSocket protocol.
This is very similar to what <<standard-upgrade,`WebSocketUpgradeFilter`>> does when using the Jakarta EE WebSocket APIs.

Once you have set up the `WebSocketUpgradeHandler`, you can use the `ServerWebSocketContainer` APIs to configure the WebSocket endpoints.
The example below shows how to set up the `WebSocketUpgradeHandler` and use the `ServerWebSocketContainer` APIs:

[,java,indent=0]
----
include::code:example$src/main/java/org/eclipse/jetty/docs/programming/server/websocket/WebSocketServerDocs.java[tags=jettyContainerWithUpgradeHandler]
----

The mapping of request URIs to WebSocket endpoints is further explained in <<jetty-pathspec,this section>>.

[[jetty-container-websocket-container]]
==== Explicit setup using `ServerWebSocketContainer`

A more advanced way to set up your WebSocket applications is to explicitly create the `ServerWebSocketContainer` instance programmatically.

This gives you more flexibility when deciding whether an HTTP request should be upgraded to WebSocket, because you do not need to match request URIs (although you can), nor you need to use `WebSocketUpgradeHandler` (although you can).

Once you have created the `ServerWebSocketContainer`, you can use its APIs to configure the WebSocket endpoints as shown in the example below.

[,java,indent=0]
----
include::code:example$src/main/java/org/eclipse/jetty/docs/programming/server/websocket/WebSocketServerDocs.java[tags=jettyContainerWithContainer]
----

Note how the call to `ServerWebSocketContainer.upgrade(\...)` allows you to perform a direct WebSocket upgrade programmatically.

[[jetty-endpoints]]
=== WebSocket Endpoints

When using the Jetty WebSocket APIs, the WebSocket endpoint classes must be either annotated with the Jetty WebSocket annotations from the `org.eclipse.jetty.websocket.api.annotations` package, or implement the `org.eclipse.jetty.websocket.api.Session.Listener` interface.

In the case you want to implement the `Session.Listener` interface, remember that you have to explicitly demand to receive the next WebSocket event.
Use `Session.Listener.AutoDemanding` to automate the demand for simple use cases.

Refer to the Jetty WebSocket architecture xref:client/websocket.adoc#endpoints[section] for more information about Jetty WebSocket endpoints and how to correctly deal with the demand for WebSocket events.

There is no automatic discovery of WebSocket endpoints; all the WebSocket endpoints of your application must be returned by a `org.eclipse.jetty.websocket.server.WebSocketCreator` that is either mapped to a request URI via `ServerWebSocketContainer.addMapping(\...)`, or directly upgraded via `ServerWebSocketContainer.upgrade(\...)`.

In the call to `ServerWebSocketContainer.addMapping(\...)`, you can specify a _path spec_ (the first parameter) that can specified as discussed in <<jetty-pathspec,this section>>.

When the `Server` is started, the lambda passed to `ServerWebSocketContainer.configure(\...)`) is invoked and allows you to explicitly configure the WebSocket endpoints using the Jetty WebSocket APIs provided by `ServerWebSocketContainer`.

[[jetty-pathspec]]
==== Custom PathSpec Mappings

The `ServerWebSocketContainer.addMapping(\...)` API maps a _path spec_ to a `WebSocketCreator` instance (typically a lambda expression).
The path spec is matched against the WebSocket upgrade request URI to select the correspondent `WebSocketCreator` 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 `WebSocketCreator`, it is possible to access the path spec and, for example in case of URI templates, extract additional information in the following way:

[,java,indent=0]
----
include::code:example$src/main/java/org/eclipse/jetty/docs/programming/server/websocket/WebSocketServerDocs.java[tags=uriTemplatePathSpec]
----
