Merged branch 'jetty-10.0.x' into 'jetty-11.0.x'.
Signed-off-by: Simone Bordet <simone.bordet@gmail.com>
This commit is contained in:
commit
0243df8f00
|
@ -54,7 +54,12 @@ You may create multiple instances of `WebSocketClient`, but typically one instan
|
|||
Creating multiple instances may be necessary for example when you need to specify different configuration parameters for different instances.
|
||||
For example, you may need different instances when you need to configure the `HttpClient` differently: different transports, different proxies, different cookie stores, different authentications, etc.
|
||||
|
||||
WebSocket specific configuration may be typically be given a default value in `WebSocketClient` and then overridden more specifically, see for example xref:pg-websocket-session-configure[this section].
|
||||
The configuration that is not WebSocket specific (such as idle timeout, etc.) should be directly configured on the associated `HttpClient` instance.
|
||||
|
||||
The WebSocket specific configuration can be configured directly on the `WebSocketClient` instance.
|
||||
Configuring the `WebSocketClient` allows to give default values to various parameters, whose values may be overridden more specifically, as described in xref:pg-websocket-session-configure[this section].
|
||||
|
||||
Refer to the `WebSocketClient` link:{javadoc-url}/org/eclipse/jetty/websocket/client/WebSocketClient.html[javadocs] for the setter methods available to customize the WebSocket specific configuration.
|
||||
|
||||
[[pg-client-websocket-stop]]
|
||||
==== Stopping WebSocketClient
|
||||
|
|
|
@ -49,6 +49,8 @@ To configure correctly your WebSocket application based on the Jetty WebSocket A
|
|||
. Make sure that Jetty xref:pg-server-websocket-jetty-container[sets up] an instance of `JettyWebSocketServerContainer`.
|
||||
. Use the `JettyWebSocketServerContainer` APIs in your applications to xref:pg-server-websocket-jetty-endpoints[register your WebSocket endpoints] that implement your application logic.
|
||||
|
||||
You can read more about the xref:pg-websocket-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.
|
||||
|
||||
[[pg-server-websocket-jetty-container]]
|
||||
===== Setting up `JettyWebSocketServerContainer`
|
||||
|
||||
|
@ -112,10 +114,12 @@ You can also use this variant to set up the `JettyWebSocketServerContainer` and
|
|||
include::../../{doc_code}/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 xref:pg-server-websocket-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 xref:pg-server-websocket-standard-upgrade[this section].
|
||||
For more information about the `WebSocketUpgradeFilter` see also xref:pg-server-websocket-configure-filter[this section].
|
||||
For more information about the configuration of `WebSocketUpgradeFilter` see also xref:pg-server-websocket-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 xref:pg-server-websocket-jetty-endpoints-servlet[this section]) to perform a direct WebSocket upgrade when your application logic demands so:
|
||||
|
||||
|
@ -175,3 +179,22 @@ However, it is typically best to avoid mixing the use of `JettyWebSocketServerCo
|
|||
|
||||
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 xref:pg-server-websocket-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.
|
||||
|
||||
[[pg-server-websocket-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:
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
include::../../{doc_code}/org/eclipse/jetty/docs/programming/server/websocket/WebSocketServerDocs.java[tags=uriTemplatePathSpec]
|
||||
----
|
||||
|
|
|
@ -91,7 +91,7 @@ Calling `JakartaWebSocketServletContainerInitializer.configure(\...)` must be do
|
|||
[[pg-server-websocket-standard-endpoints]]
|
||||
===== Configuring Endpoints
|
||||
|
||||
Once you have xref:pg-server-websocket-standard-container[setup] the `ServerContainer`, you can configure your xref:pg-websocket-endpoints[WebSocket endpoints].
|
||||
Once you have xref:pg-server-websocket-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.
|
||||
|
||||
|
|
|
@ -21,19 +21,16 @@ 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 few features that are not present in the Jetty WebSocket APIs:
|
||||
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.
|
||||
* `Reader` and `InputStream` for simple, blocking, message streaming.
|
||||
* Simple URI template matching.
|
||||
|
||||
On the other hand, the Jetty WebSocket APIs are more efficient and offer greater and more fine-grained control, and provide features that are not present in the standard APIs:
|
||||
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.
|
||||
* Control of the idle timeout.
|
||||
* 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.
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
// Snippets of WebSocket documentation that are common between client and server.
|
||||
|
||||
[[pg-websocket-architecture]]
|
||||
==== WebSocket Architecture
|
||||
==== Jetty WebSocket Architecture
|
||||
|
||||
The Jetty WebSocket architecture is organized around the concept of a logical _connection_ between the client and the server.
|
||||
|
||||
|
@ -152,6 +152,29 @@ You want to do this as soon as you have access to the `Session` object, typicall
|
|||
include::{doc_code}/org/eclipse/jetty/docs/programming/WebSocketDocs.java[tags=sessionConfigure]
|
||||
----
|
||||
|
||||
The settings that can be configured include:
|
||||
|
||||
maxBinaryMessageSize::
|
||||
the maximum size in bytes of a binary message (which may be composed of multiple frames) that can be received.
|
||||
|
||||
maxTextMessageSize::
|
||||
the maximum size in bytes of a text message (which may be composed of multiple frames) that can be received.
|
||||
|
||||
maxFrameSize::
|
||||
the maximum payload size in bytes of any WebSocket frame that can be received.
|
||||
|
||||
inputBufferSize::
|
||||
the input (read from network/transport layer) buffer size in bytes; it has no relationship with the WebSocket frame size or message size.
|
||||
|
||||
outputBufferSize::
|
||||
the output (write to network/transport layer) buffer size in bytes; it has no relationship to the WebSocket frame size or message size.
|
||||
|
||||
autoFragment::
|
||||
whether WebSocket frames are automatically fragmented to respect the maximum frame size.
|
||||
|
||||
idleTimeout::
|
||||
the duration that a WebSocket connection may remain idle (that is, there is no network traffic, neither in read nor in write) before being closed by the implementation.
|
||||
|
||||
Please refer to the `Session` link:{javadoc-url}/org/eclipse/jetty/websocket/api/Session.html[javadocs] for the complete list of configuration APIs.
|
||||
|
||||
[[pg-websocket-session-send]]
|
||||
|
|
|
@ -15,6 +15,7 @@ package org.eclipse.jetty.docs.programming.server.websocket;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServlet;
|
||||
|
@ -24,6 +25,8 @@ import jakarta.websocket.DeploymentException;
|
|||
import jakarta.websocket.server.ServerContainer;
|
||||
import jakarta.websocket.server.ServerEndpoint;
|
||||
import jakarta.websocket.server.ServerEndpointConfig;
|
||||
import org.eclipse.jetty.http.pathmap.PathSpec;
|
||||
import org.eclipse.jetty.http.pathmap.UriTemplatePathSpec;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
|
@ -348,4 +351,38 @@ public class WebSocketServerDocs
|
|||
private static class MyOtherJettyWebSocketEndPoint
|
||||
{
|
||||
}
|
||||
|
||||
public void uriTemplatePathSpec()
|
||||
{
|
||||
Server server = new Server(8080);
|
||||
|
||||
// tag::uriTemplatePathSpec[]
|
||||
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);
|
||||
});
|
||||
});
|
||||
// end::uriTemplatePathSpec[]
|
||||
}
|
||||
|
||||
@WebSocket
|
||||
private static class MyWebSocketRoomEndPoint
|
||||
{
|
||||
public MyWebSocketRoomEndPoint(String room)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,14 +22,49 @@ public final class WebSocketConstants
|
|||
public static final int SPEC_VERSION = 13;
|
||||
public static final String SPEC_VERSION_STRING = Integer.toString(SPEC_VERSION);
|
||||
|
||||
/**
|
||||
* Max Binary Message Size - The maximum size of a binary message which can be received.
|
||||
*/
|
||||
public static final int DEFAULT_MAX_BINARY_MESSAGE_SIZE = 64 * 1024;
|
||||
|
||||
/**
|
||||
* Max Text Message Size - The maximum size of a text message which can be received.
|
||||
*/
|
||||
public static final int DEFAULT_MAX_TEXT_MESSAGE_SIZE = 64 * 1024;
|
||||
|
||||
/**
|
||||
* Max Frame Size - The maximum payload size of any WebSocket Frame which can be received.
|
||||
*/
|
||||
public static final int DEFAULT_MAX_FRAME_SIZE = 64 * 1024;
|
||||
|
||||
/**
|
||||
* Output Buffer Size - The output (write to network layer) buffer size. This is the raw write operation buffer size and has no relationship to the websocket frame.
|
||||
*/
|
||||
public static final int DEFAULT_INPUT_BUFFER_SIZE = 4 * 1024;
|
||||
|
||||
/**
|
||||
* Input Buffer Size - The input (read from network layer) buffer size. This is the raw read operation buffer size, before the parsing of the websocket frames.
|
||||
*/
|
||||
public static final int DEFAULT_OUTPUT_BUFFER_SIZE = 4 * 1024;
|
||||
|
||||
/**
|
||||
* Max Outgoing Frames - Set the maximum number of data frames allowed to be waiting to be sent at any one time.
|
||||
*/
|
||||
public static final int DEFAULT_MAX_OUTGOING_FRAMES = -1;
|
||||
|
||||
/**
|
||||
* Auto Fragment - If set to true, frames are automatically fragmented to respect the maximum frame size.
|
||||
*/
|
||||
public static final boolean DEFAULT_AUTO_FRAGMENT = true;
|
||||
|
||||
/**
|
||||
* Idle Timeout - The duration that a websocket may be idle before being closed by the implementation.
|
||||
*/
|
||||
public static final Duration DEFAULT_IDLE_TIMEOUT = Duration.ofSeconds(30);
|
||||
|
||||
/**
|
||||
* Write Timeout - The maximum time a frame may be waiting to be sent.
|
||||
*/
|
||||
public static final Duration DEFAULT_WRITE_TIMEOUT = Duration.ZERO;
|
||||
|
||||
/**
|
||||
|
|
|
@ -13,12 +13,20 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.tests;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.http.pathmap.PathSpec;
|
||||
import org.eclipse.jetty.http.pathmap.UriTemplatePathSpec;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.api.WriteCallback;
|
||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
|
||||
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
import org.eclipse.jetty.websocket.server.JettyServerUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.server.config.JettyWebSocketServletContainerInitializer;
|
||||
|
@ -28,6 +36,8 @@ import org.junit.jupiter.api.Test;
|
|||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class JettyWebSocketServletAttributeTest
|
||||
|
@ -87,4 +97,47 @@ public class JettyWebSocketServletAttributeTest
|
|||
clientEndpoint.session.close();
|
||||
assertTrue(clientEndpoint.closeLatch.await(5, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPathSpecAttribute() throws Exception
|
||||
{
|
||||
start((context, container) -> container.addMapping("uri-template|/{path}", (req, resp) ->
|
||||
{
|
||||
UriTemplatePathSpec pathSpec = (UriTemplatePathSpec)req.getServletAttribute(PathSpec.class.getName());
|
||||
assertNotNull(pathSpec);
|
||||
|
||||
Map<String, String> params = pathSpec.getPathParams(req.getRequestPath());
|
||||
String path = params.get("path");
|
||||
assertNotNull(path);
|
||||
|
||||
return new ParamWebSocketEndPoint(path);
|
||||
}));
|
||||
|
||||
String param = "world";
|
||||
URI uri = URI.create("ws://localhost:" + connector.getLocalPort() + "/" + param);
|
||||
EventSocket clientEndpoint = new EventSocket();
|
||||
try (Session session = client.connect(clientEndpoint, uri).get(5, TimeUnit.SECONDS))
|
||||
{
|
||||
session.getRemote().sendString("hello", WriteCallback.NOOP);
|
||||
String path = clientEndpoint.textMessages.poll(5, TimeUnit.SECONDS);
|
||||
assertEquals(param, path);
|
||||
}
|
||||
}
|
||||
|
||||
@WebSocket
|
||||
public static class ParamWebSocketEndPoint
|
||||
{
|
||||
private final String param;
|
||||
|
||||
public ParamWebSocketEndPoint(String param)
|
||||
{
|
||||
this.param = param;
|
||||
}
|
||||
|
||||
@OnWebSocketMessage
|
||||
public void onText(Session session, String text) throws IOException
|
||||
{
|
||||
session.getRemote().sendString(param);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue