423 lines
25 KiB
Plaintext
423 lines
25 KiB
Plaintext
//
|
|
// ========================================================================
|
|
// 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 two API implementations of the WebSocket protocol:
|
|
|
|
* An implementation for the standard `javax.websocket` APIs provided by https://www.jcp.org/en/jsr/detail?id=356[JSR 356], described in <<standard,this section>>.
|
|
* An implementation for Jetty-specific WebSocket APIs, described in <<jetty,this section>>.
|
|
|
|
Using the standard `javax.websocket` APIs allows your applications to depend only on standard APIs, and your applications may be deployed in any compliant WebSocket Container that supports JSR 356.
|
|
|
|
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]]
|
|
== Standard APIs Implementation
|
|
|
|
When you write a WebSocket application using the standard `javax.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 `javax.websocket` APIs are provided by the following Maven artifact:
|
|
|
|
[,xml,subs=normal]
|
|
----
|
|
<dependency>
|
|
<groupId>javax.websocket</groupId>
|
|
<artifactId>javax.websocket-api</artifactId>
|
|
<version>1.1</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:
|
|
|
|
[,xml,subs=normal]
|
|
----
|
|
<dependency>
|
|
<groupId>org.eclipse.jetty.toolchain</groupId>
|
|
<artifactId>jetty-javax-websocket-api</artifactId>
|
|
<version>1.1.2</version>
|
|
</dependency>
|
|
----
|
|
|
|
This artifact is nothing more than the `javax.websocket:javax.websocket-api:1.1` artifact repackaged with a proper `module-info.class` file.
|
|
|
|
At runtime, you also need an implementation of the standard `javax.websocket` APIs.
|
|
|
|
Jetty's implementation of the standard `javax.websocket` APIs is provided by the following Maven artifact (and its transitive dependencies):
|
|
|
|
[,xml,subs=normal]
|
|
----
|
|
<dependency>
|
|
<groupId>org.eclipse.jetty.websocket</groupId>
|
|
<artifactId>websocket-javax-server</artifactId>
|
|
<version>{jetty-version}</version>
|
|
</dependency>
|
|
----
|
|
|
|
[NOTE]
|
|
====
|
|
The `javax.websocket-api` artifact and the `websocket-javax-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 `javax.websocket` APIs, you need two steps:
|
|
|
|
. Make sure that Jetty <<standard-container,sets up>> an instance of `javax.websocket.server.ServerContainer`.
|
|
. <<standard-endpoints,Configure>> the WebSocket endpoints that implement your application logic, either by annotating their classes with the standard `javax.websocket` annotations, or by using the `ServerContainer` APIs to register them in your code.
|
|
|
|
[[standard-container]]
|
|
=== Setting Up `ServerContainer`
|
|
|
|
Jetty sets up a `ServerContainer` instance using `JavaxWebSocketServletContainerInitializer`.
|
|
|
|
When you deploy web applications using xref:server/http.adoc#handler-use-webapp-context[`WebAppContext`], then `JavaxWebSocketServletContainerInitializer` 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 `JavaxWebSocketServletContainerInitializer` 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 `JavaxWebSocketServletContainerInitializer.configure(\...)` must be done _before_ the `ServletContextHandler` is started, and configures the `javax.websocket` implementation for that web application context.
|
|
|
|
[[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 `javax.websocket` annotations, extend the `javax.websocket.Endpoint` abstract class, or implement the `javax.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 `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 also use this variant 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 `JavaxWebSocketServletContainerInitializer.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, `JavaxWebSocketServletContainerInitializer` 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.
|
|
|
|
[NOTE]
|
|
====
|
|
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 <<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).
|
|
|
|
[[jetty]]
|
|
== 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:
|
|
|
|
[,xml,subs=normal]
|
|
----
|
|
<dependency>
|
|
<groupId>org.eclipse.jetty.websocket</groupId>
|
|
<artifactId>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=normal]
|
|
----
|
|
<dependency>
|
|
<groupId>org.eclipse.jetty.websocket</groupId>
|
|
<artifactId>websocket-jetty-server</artifactId>
|
|
<version>{jetty-version}</version>
|
|
</dependency>
|
|
----
|
|
|
|
[NOTE]
|
|
====
|
|
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:
|
|
|
|
. Make sure that Jetty <<jetty-container,sets up>> an instance of `JettyWebSocketServerContainer`.
|
|
. Use the `JettyWebSocketServerContainer` APIs in your applications to <<jetty-endpoints,register your 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 `JettyWebSocketServerContainer`
|
|
|
|
Jetty sets up a `JettyWebSocketServerContainer` instance using `JettyWebSocketServletContainerInitializer`.
|
|
|
|
When you deploy web applications using xref:server/http.adoc#handler-use-webapp-context[`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:
|
|
|
|
[,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 `JettyWebSocketServletContainerInitializer` is initialized, so that it sets up the `JettyWebSocketServerContainer`:
|
|
|
|
[,java,indent=0]
|
|
----
|
|
include::code:example$src/main/java/org/eclipse/jetty/docs/programming/server/websocket/WebSocketServerDocs.java[tags=jettyContainerServletContextHandler]
|
|
----
|
|
|
|
Calling `JettyWebSocketServletContainerInitializer.configure(\...)` must be done _before_ the `ServletContextHandler` is started, and configures the Jetty WebSocket implementation for that web application context.
|
|
|
|
[[jetty-endpoints]]
|
|
=== Configuring Endpoints
|
|
|
|
Once you have <<jetty-container,setup>> the `JettyWebSocketServerContainer`, you can configure your xref:client/websocket.adoc#endpoints[WebSocket endpoints].
|
|
|
|
Differently from the <<standard-endpoints,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 xref:server/http.adoc#handler-use-webapp-context[`WebAppContext`].
|
|
|
|
[IMPORTANT]
|
|
====
|
|
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:
|
|
|
|
* <<jetty-endpoints-container,Using `JettyWebSocketServerContainer`>>, which is very similar to how WebSocket endpoints are configured when using the <<standard-endpoints,standard `javax.websocket` APIs>>, but also provides APIs to perform a direct, programmatic, WebSocket upgrade.
|
|
* <<jetty-endpoints-servlet,Using `JettyWebSocketServlet`>>, which may configured in `web.xml`, rather than in Java code.
|
|
|
|
[[jetty-endpoints-container]]
|
|
==== 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`:
|
|
|
|
[,java,indent=0]
|
|
----
|
|
include::code:example$src/main/java/org/eclipse/jetty/docs/programming/server/websocket/WebSocketServerDocs.java[tags=jettyEndpointsInitialization]
|
|
----
|
|
|
|
[,java,indent=0]
|
|
----
|
|
include::code:example$src/main/java/org/eclipse/jetty/docs/programming/server/websocket/WebSocketServerDocs.java[tags=jettyWebSocketInitializerServlet]
|
|
----
|
|
|
|
You can also use this variant to set up the `JettyWebSocketServerContainer` 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=jettyContainerAndEndpoints]
|
|
----
|
|
|
|
In the call to `JettyWebSocketServerContainer.addMapping(\...)`, you can specify a _path spec_ (the first parameter) that can be configured as specified in <<jetty-pathspec,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 <<standard-upgrade,this section>>.
|
|
For more information about the configuration of `WebSocketUpgradeFilter` see also <<configure-filter,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 <<jetty-endpoints-servlet,this section>>) to perform a direct WebSocket upgrade when your application logic demands so:
|
|
|
|
[,java,indent=0]
|
|
----
|
|
include::code:example$src/main/java/org/eclipse/jetty/docs/programming/server/websocket/WebSocketServerDocs.java[tags=jettyContainerServletContextHandler]
|
|
----
|
|
|
|
[,java,indent=0]
|
|
----
|
|
include::code:example$src/main/java/org/eclipse/jetty/docs/programming/server/websocket/WebSocketServerDocs.java[tags=jettyContainerUpgrade]
|
|
----
|
|
|
|
When using `JettyWebSocketServerContainer.upgrade(\...)`, the `WebSocketUpgradeFilter` is not installed, since the WebSocket upgrade is performed programmatically.
|
|
|
|
[[jetty-endpoints-servlet]]
|
|
==== 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 <<configure-filter,this section>> for more information).
|
|
|
|
For example, your `JettyWebSocketServlet` subclass may be declared in code in this way:
|
|
|
|
[,java,indent=0]
|
|
----
|
|
include::code:example$src/main/java/org/eclipse/jetty/docs/programming/server/websocket/WebSocketServerDocs.java[tags=jettyWebSocketServletMain]
|
|
----
|
|
|
|
[,java,indent=0]
|
|
----
|
|
include::code:example$src/main/java/org/eclipse/jetty/docs/programming/server/websocket/WebSocketServerDocs.java[tags=jettyWebSocketServlet]
|
|
----
|
|
|
|
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, `javax.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.
|
|
|
|
[NOTE]
|
|
====
|
|
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 <<standard-upgrade,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.
|
|
|
|
[[jetty-pathspec]]
|
|
==== 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:
|
|
|
|
[,java,indent=0]
|
|
----
|
|
include::code:example$src/main/java/org/eclipse/jetty/docs/programming/server/websocket/WebSocketServerDocs.java[tags=uriTemplatePathSpec]
|
|
----
|
|
|
|
[[configure-filter]]
|
|
== Advanced `WebSocketUpgradeFilter` Configuration
|
|
|
|
The `WebSocketUpgradeFilter` that handles the HTTP requests that upgrade to WebSocket is installed in these cases:
|
|
|
|
* Either by the `JavaxWebSocketServletContainerInitializer`, as described in <<standard,this section>>.
|
|
* Or by a call to `JettyWebSocketServerContainer.addMapping(\...)`, as described in <<jetty,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 ``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 the `CrossOriginFilter` (or other 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=verbatim]
|
|
----
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
|
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
|
|
version="4.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 https://owasp.org/www-community/attacks/csrf[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.
|