Merge remote-tracking branch 'origin/jetty-10.0.x' into jetty-10.0.x-3012-Compliance
This commit is contained in:
commit
c7f66521cb
|
@ -633,7 +633,6 @@
|
|||
<dependency>
|
||||
<groupId>org.jboss.logging</groupId>
|
||||
<artifactId>jboss-logging</artifactId>
|
||||
<version>3.3.0.Final</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.cdi</groupId>
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
<url>http://www.eclipse.org/jetty</url>
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.infinispan</bundle-symbolic-name>
|
||||
<infinispan.version>9.1.0.Final</infinispan.version>
|
||||
</properties>
|
||||
<build>
|
||||
<defaultGoal>install</defaultGoal>
|
||||
|
@ -43,7 +42,7 @@
|
|||
<dependency>
|
||||
<groupId>org.infinispan.protostream</groupId>
|
||||
<artifactId>protostream</artifactId>
|
||||
<version>4.1.0.Final</version>
|
||||
<version>4.2.2.Final</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
|
@ -53,13 +52,17 @@
|
|||
<dependency>
|
||||
<groupId>org.infinispan</groupId>
|
||||
<artifactId>infinispan-client-hotrod</artifactId>
|
||||
<version>9.1.0.Final</version>
|
||||
<version>${infinispan.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jboss.logging</groupId>
|
||||
<artifactId>jboss-logging</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.infinispan</groupId>
|
||||
<artifactId>infinispan-remote-query-client</artifactId>
|
||||
<version>9.1.0.Final</version>
|
||||
<version>${infinispan.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
|
|
@ -16,14 +16,10 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
import org.eclipse.jetty.websocket.api.extensions.Extension;
|
||||
|
||||
module org.eclipse.jetty.websocket.jetty.api
|
||||
{
|
||||
exports org.eclipse.jetty.websocket.api;
|
||||
exports org.eclipse.jetty.websocket.api.annotations;
|
||||
exports org.eclipse.jetty.websocket.api.extensions;
|
||||
exports org.eclipse.jetty.websocket.api.util;
|
||||
|
||||
uses Extension;
|
||||
}
|
||||
|
|
|
@ -18,11 +18,8 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.api;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.extensions.Frame;
|
||||
import org.eclipse.jetty.websocket.api.extensions.OutgoingFrames;
|
||||
|
||||
/**
|
||||
* The possible batch modes when invoking {@link OutgoingFrames#outgoingFrame(Frame, WriteCallback, BatchMode)}.
|
||||
* The possible batch modes when enqueuing outgoing frames.
|
||||
*/
|
||||
public enum BatchMode
|
||||
{
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.api.extensions;
|
||||
package org.eclipse.jetty.websocket.api;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
|
@ -18,8 +18,6 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.api;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.extensions.Frame;
|
||||
|
||||
/**
|
||||
* WebSocket Frame Listener interface for incoming WebSocket frames.
|
||||
*/
|
||||
|
|
|
@ -18,22 +18,23 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.api.annotations;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.Frame;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
|
||||
/**
|
||||
* (ADVANCED) Annotation for tagging methods to receive frame events.
|
||||
* <p>
|
||||
* Acceptable method patterns.<br>
|
||||
* Note: {@code methodName} can be any name you want to use.
|
||||
* <ol>
|
||||
* <li><code>public void methodName({@link org.eclipse.jetty.websocket.api.extensions.Frame} frame)</code></li>
|
||||
* <li><code>public void methodName({@link Session} session, {@link org.eclipse.jetty.websocket.api.extensions.Frame} frame)</code></li>
|
||||
* <li><code>public void methodName({@link Frame} frame)</code></li>
|
||||
* <li><code>public void methodName({@link Session} session, {@link Frame} frame)</code></li>
|
||||
* </ol>
|
||||
*/
|
||||
@Documented
|
||||
|
|
|
@ -1,84 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.api.extensions;
|
||||
|
||||
/**
|
||||
* Interface for WebSocket Extensions.
|
||||
* <p>
|
||||
* That {@link Frame}s are passed through the Extension via the {@link IncomingFrames} and {@link OutgoingFrames} interfaces
|
||||
*/
|
||||
public interface Extension extends IncomingFrames, OutgoingFrames
|
||||
{
|
||||
/**
|
||||
* The active configuration for this extension.
|
||||
*
|
||||
* @return the configuration for this extension. never null.
|
||||
*/
|
||||
public ExtensionConfig getConfig();
|
||||
|
||||
/**
|
||||
* The {@code Sec-WebSocket-Extensions} name for this extension.
|
||||
* <p>
|
||||
* Also known as the <a href="https://tools.ietf.org/html/rfc6455#section-9.1">{@code extension-token} per Section 9.1. Negotiating Extensions</a>.
|
||||
*
|
||||
* @return the name of the extension
|
||||
*/
|
||||
public String getName();
|
||||
|
||||
/**
|
||||
* Used to indicate that the extension makes use of the RSV1 bit of the base websocket framing.
|
||||
* <p>
|
||||
* This is used to adjust validation during parsing, as well as a checkpoint against 2 or more extensions all simultaneously claiming ownership of RSV1.
|
||||
*
|
||||
* @return true if extension uses RSV1 for its own purposes.
|
||||
*/
|
||||
public abstract boolean isRsv1User();
|
||||
|
||||
/**
|
||||
* Used to indicate that the extension makes use of the RSV2 bit of the base websocket framing.
|
||||
* <p>
|
||||
* This is used to adjust validation during parsing, as well as a checkpoint against 2 or more extensions all simultaneously claiming ownership of RSV2.
|
||||
*
|
||||
* @return true if extension uses RSV2 for its own purposes.
|
||||
*/
|
||||
public abstract boolean isRsv2User();
|
||||
|
||||
/**
|
||||
* Used to indicate that the extension makes use of the RSV3 bit of the base websocket framing.
|
||||
* <p>
|
||||
* This is used to adjust validation during parsing, as well as a checkpoint against 2 or more extensions all simultaneously claiming ownership of RSV3.
|
||||
*
|
||||
* @return true if extension uses RSV3 for its own purposes.
|
||||
*/
|
||||
public abstract boolean isRsv3User();
|
||||
|
||||
/**
|
||||
* Set the next {@link IncomingFrames} to call in the chain.
|
||||
*
|
||||
* @param nextIncoming the next incoming extension
|
||||
*/
|
||||
public void setNextIncomingFrames(IncomingFrames nextIncoming);
|
||||
|
||||
/**
|
||||
* Set the next {@link OutgoingFrames} to call in the chain.
|
||||
*
|
||||
* @param nextOutgoing the next outgoing extension
|
||||
*/
|
||||
public void setNextOutgoingFrames(OutgoingFrames nextOutgoing);
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.api.extensions;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.Set;
|
||||
|
||||
public abstract class ExtensionFactory implements Iterable<Class<? extends Extension>>
|
||||
{
|
||||
private Map<String, Class<? extends Extension>> availableExtensions;
|
||||
|
||||
public ExtensionFactory()
|
||||
{
|
||||
ServiceLoader<Extension> extensionLoader = ServiceLoader.load(Extension.class);
|
||||
availableExtensions = new HashMap<>();
|
||||
for (Extension ext : extensionLoader)
|
||||
{
|
||||
if (ext != null)
|
||||
{
|
||||
availableExtensions.put(ext.getName(), ext.getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, Class<? extends Extension>> getAvailableExtensions()
|
||||
{
|
||||
return availableExtensions;
|
||||
}
|
||||
|
||||
public Class<? extends Extension> getExtension(String name)
|
||||
{
|
||||
return availableExtensions.get(name);
|
||||
}
|
||||
|
||||
public Set<String> getExtensionNames()
|
||||
{
|
||||
return availableExtensions.keySet();
|
||||
}
|
||||
|
||||
public boolean isAvailable(String name)
|
||||
{
|
||||
return availableExtensions.containsKey(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Class<? extends Extension>> iterator()
|
||||
{
|
||||
return availableExtensions.values().iterator();
|
||||
}
|
||||
|
||||
public abstract Extension newInstance(ExtensionConfig config);
|
||||
|
||||
public void register(String name, Class<? extends Extension> extension)
|
||||
{
|
||||
availableExtensions.put(name, extension);
|
||||
}
|
||||
|
||||
public void unregister(String name)
|
||||
{
|
||||
availableExtensions.remove(name);
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.api.extensions;
|
||||
|
||||
/**
|
||||
* Interface for dealing with Incoming Frames.
|
||||
*/
|
||||
public interface IncomingFrames
|
||||
{
|
||||
public void incomingError(Throwable t);
|
||||
|
||||
/**
|
||||
* Process the incoming frame.
|
||||
* <p>
|
||||
* Note: if you need to hang onto any information from the frame, be sure
|
||||
* to copy it, as the information contained in the Frame will be released
|
||||
* and/or reused by the implementation.
|
||||
*
|
||||
* @param frame the frame to process
|
||||
*/
|
||||
public void incomingFrame(Frame frame);
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.api.extensions;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.BatchMode;
|
||||
import org.eclipse.jetty.websocket.api.WriteCallback;
|
||||
|
||||
/**
|
||||
* Interface for dealing with frames outgoing to (eventually) the network layer.
|
||||
*/
|
||||
public interface OutgoingFrames
|
||||
{
|
||||
/**
|
||||
* A frame, and optional callback, intended for the network layer.
|
||||
* <p>
|
||||
* Note: the frame can undergo many transformations in the various
|
||||
* layers and extensions present in the implementation.
|
||||
* <p>
|
||||
* If you are implementing a mutation, you are obliged to handle
|
||||
* the incoming WriteCallback appropriately.
|
||||
*
|
||||
* @param frame the frame to eventually write to the network layer.
|
||||
* @param callback the callback to notify when the frame is written.
|
||||
* @param batchMode the batch mode requested by the sender.
|
||||
*/
|
||||
void outgoingFrame(Frame frame, WriteCallback callback, BatchMode batchMode);
|
||||
|
||||
}
|
|
@ -18,11 +18,11 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.common;
|
||||
|
||||
import org.eclipse.jetty.websocket.core.Frame;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class JettyWebSocketFrame implements org.eclipse.jetty.websocket.api.extensions.Frame
|
||||
import org.eclipse.jetty.websocket.core.Frame;
|
||||
|
||||
public class JettyWebSocketFrame implements org.eclipse.jetty.websocket.api.Frame
|
||||
{
|
||||
private final Frame frame;
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@ public class JettyWebSocketFrameHandler implements FrameHandler
|
|||
private MessageSink textSink;
|
||||
private MessageSink binarySink;
|
||||
private MessageSink activeMessageSink;
|
||||
private WebSocketSessionImpl session;
|
||||
private WebSocketSession session;
|
||||
|
||||
public JettyWebSocketFrameHandler(WebSocketContainer container,
|
||||
Object endpointInstance,
|
||||
|
@ -108,7 +108,7 @@ public class JettyWebSocketFrameHandler implements FrameHandler
|
|||
this.customizer = customizer;
|
||||
}
|
||||
|
||||
public WebSocketSessionImpl getSession()
|
||||
public WebSocketSession getSession()
|
||||
{
|
||||
return session;
|
||||
}
|
||||
|
@ -120,7 +120,7 @@ public class JettyWebSocketFrameHandler implements FrameHandler
|
|||
{
|
||||
customizer.customize(coreSession);
|
||||
|
||||
session = new WebSocketSessionImpl(coreSession, this, upgradeRequest, upgradeResponse);
|
||||
session = new WebSocketSession(coreSession, this, upgradeRequest, upgradeResponse);
|
||||
|
||||
frameHandle = JettyWebSocketFrameHandlerFactory.bindTo(frameHandle, session);
|
||||
openHandle = JettyWebSocketFrameHandlerFactory.bindTo(openHandle, session);
|
||||
|
|
|
@ -36,6 +36,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
import java.util.concurrent.Executor;
|
||||
|
||||
import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
||||
import org.eclipse.jetty.websocket.api.Frame;
|
||||
import org.eclipse.jetty.websocket.api.InvalidWebSocketException;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.api.UpgradeRequest;
|
||||
|
@ -280,7 +281,7 @@ public class JettyWebSocketFrameHandlerFactory extends ContainerLifeCycle
|
|||
// Frame Listener
|
||||
if (WebSocketFrameListener.class.isAssignableFrom(endpointClass))
|
||||
{
|
||||
Method frameMethod = ReflectUtils.findMethod(endpointClass, "onWebSocketFrame", org.eclipse.jetty.websocket.api.extensions.Frame.class);
|
||||
Method frameMethod = ReflectUtils.findMethod(endpointClass, "onWebSocketFrame", Frame.class);
|
||||
MethodHandle frame = toMethodHandle(lookup, frameMethod);
|
||||
metadata.setFrameHandler(frame, frameMethod);
|
||||
}
|
||||
|
@ -349,7 +350,7 @@ public class JettyWebSocketFrameHandlerFactory extends ContainerLifeCycle
|
|||
{
|
||||
assertSignatureValid(endpointClass, onmethod, OnWebSocketFrame.class);
|
||||
final InvokerUtils.Arg SESSION = new InvokerUtils.Arg(Session.class);
|
||||
final InvokerUtils.Arg FRAME = new InvokerUtils.Arg(org.eclipse.jetty.websocket.api.extensions.Frame.class).required();
|
||||
final InvokerUtils.Arg FRAME = new InvokerUtils.Arg(Frame.class).required();
|
||||
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(endpointClass, onmethod, SESSION, FRAME);
|
||||
metadata.setFrameHandler(methodHandle, onmethod);
|
||||
}
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.common;
|
||||
|
||||
public interface SessionListener
|
||||
{
|
||||
void onCreated(WebSocketSessionImpl session);
|
||||
|
||||
void onOpened(WebSocketSessionImpl session);
|
||||
|
||||
void onClosed(WebSocketSessionImpl session);
|
||||
}
|
|
@ -36,13 +36,13 @@ public class SessionTracker extends AbstractLifeCycle implements WebSocketSessio
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketSessionOpened(WebSocketSessionImpl session)
|
||||
public void onWebSocketSessionOpened(WebSocketSession session)
|
||||
{
|
||||
sessions.add(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketSessionClosed(WebSocketSessionImpl session)
|
||||
public void onWebSocketSessionClosed(WebSocketSession session)
|
||||
{
|
||||
sessions.remove(session);
|
||||
}
|
||||
|
|
|
@ -37,16 +37,16 @@ import org.eclipse.jetty.websocket.api.UpgradeResponse;
|
|||
import org.eclipse.jetty.websocket.api.WebSocketBehavior;
|
||||
import org.eclipse.jetty.websocket.core.FrameHandler;
|
||||
|
||||
public class WebSocketSessionImpl extends AbstractLifeCycle implements Session, Dumpable
|
||||
public class WebSocketSession extends AbstractLifeCycle implements Session, Dumpable
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(WebSocketSessionImpl.class);
|
||||
private static final Logger LOG = Log.getLogger(WebSocketSession.class);
|
||||
private final FrameHandler.CoreSession coreSession;
|
||||
private final JettyWebSocketFrameHandler frameHandler;
|
||||
private final JettyWebSocketRemoteEndpoint remoteEndpoint;
|
||||
private final UpgradeRequest upgradeRequest;
|
||||
private final UpgradeResponse upgradeResponse;
|
||||
|
||||
public WebSocketSessionImpl(
|
||||
public WebSocketSession(
|
||||
FrameHandler.CoreSession coreSession,
|
||||
JettyWebSocketFrameHandler frameHandler,
|
||||
UpgradeRequest upgradeRequest,
|
||||
|
@ -254,6 +254,6 @@ public class WebSocketSessionImpl extends AbstractLifeCycle implements Session,
|
|||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("WebSocketSessionImpl[%s,to=%s,%s,%s]", getBehavior(), getIdleTimeout(), coreSession, frameHandler);
|
||||
return String.format("WebSocketSession[%s,to=%s,%s,%s]", getBehavior(), getIdleTimeout(), coreSession, frameHandler);
|
||||
}
|
||||
}
|
|
@ -23,7 +23,7 @@ package org.eclipse.jetty.websocket.common;
|
|||
*/
|
||||
public interface WebSocketSessionListener
|
||||
{
|
||||
void onWebSocketSessionOpened(WebSocketSessionImpl session);
|
||||
void onWebSocketSessionOpened(WebSocketSession session);
|
||||
|
||||
void onWebSocketSessionClosed(WebSocketSessionImpl session);
|
||||
void onWebSocketSessionClosed(WebSocketSession session);
|
||||
}
|
||||
|
|
|
@ -18,9 +18,9 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.common.endpoints.annotated;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.Frame;
|
||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketFrame;
|
||||
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
|
||||
import org.eclipse.jetty.websocket.api.extensions.Frame;
|
||||
|
||||
@WebSocket
|
||||
public class FrameSocket
|
||||
|
|
|
@ -18,9 +18,9 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.common.endpoints.listeners;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.Frame;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketFrameListener;
|
||||
import org.eclipse.jetty.websocket.api.extensions.Frame;
|
||||
import org.eclipse.jetty.websocket.common.EventQueue;
|
||||
import org.eclipse.jetty.websocket.common.util.TextUtil;
|
||||
import org.eclipse.jetty.websocket.core.CloseStatus;
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
package org.eclipse.jetty.websocket.server;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
|
@ -29,7 +29,6 @@ import org.eclipse.jetty.websocket.common.JettyWebSocketFrameHandlerFactory;
|
|||
import org.eclipse.jetty.websocket.common.WebSocketContainer;
|
||||
import org.eclipse.jetty.websocket.core.FrameHandler;
|
||||
import org.eclipse.jetty.websocket.server.internal.DelegatedJettyServletUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.server.internal.JettyWebSocketServerContainer;
|
||||
import org.eclipse.jetty.websocket.server.internal.UpgradeResponseAdapter;
|
||||
import org.eclipse.jetty.websocket.servlet.FrameHandlerFactory;
|
||||
import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest;
|
||||
|
@ -39,23 +38,6 @@ public class JettyServerFrameHandlerFactory
|
|||
extends JettyWebSocketFrameHandlerFactory
|
||||
implements FrameHandlerFactory, LifeCycle.Listener
|
||||
{
|
||||
public static JettyServerFrameHandlerFactory ensureFactory(ServletContext servletContext)
|
||||
throws ServletException
|
||||
{
|
||||
ContextHandler contextHandler = ServletContextHandler.getServletContextHandler(servletContext, "Jetty Websocket");
|
||||
|
||||
JettyServerFrameHandlerFactory factory = contextHandler.getBean(JettyServerFrameHandlerFactory.class);
|
||||
if (factory == null)
|
||||
{
|
||||
JettyWebSocketServerContainer container = new JettyWebSocketServerContainer(contextHandler);
|
||||
servletContext.setAttribute(WebSocketContainer.class.getName(), container);
|
||||
factory = new JettyServerFrameHandlerFactory(container);
|
||||
contextHandler.addManaged(factory);
|
||||
contextHandler.addLifeCycleListener(factory);
|
||||
}
|
||||
return factory;
|
||||
}
|
||||
|
||||
public JettyServerFrameHandlerFactory(WebSocketContainer container)
|
||||
{
|
||||
super(container);
|
||||
|
|
|
@ -0,0 +1,231 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.server;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.eclipse.jetty.http.pathmap.PathSpec;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
||||
import org.eclipse.jetty.util.component.LifeCycle;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketBehavior;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.common.SessionTracker;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketContainer;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketSessionListener;
|
||||
import org.eclipse.jetty.websocket.core.FrameHandler;
|
||||
import org.eclipse.jetty.websocket.core.WebSocketComponents;
|
||||
import org.eclipse.jetty.websocket.core.WebSocketException;
|
||||
import org.eclipse.jetty.websocket.servlet.FrameHandlerFactory;
|
||||
import org.eclipse.jetty.websocket.servlet.WebSocketCreator;
|
||||
import org.eclipse.jetty.websocket.servlet.WebSocketMapping;
|
||||
|
||||
public class JettyWebSocketServerContainer extends ContainerLifeCycle implements WebSocketContainer, WebSocketPolicy, LifeCycle.Listener
|
||||
{
|
||||
|
||||
public static JettyWebSocketServerContainer ensureContainer(ServletContext servletContext)
|
||||
{
|
||||
ServletContextHandler contextHandler = ServletContextHandler.getServletContextHandler(servletContext, "Javax Websocket");
|
||||
if (contextHandler.getServer() == null)
|
||||
throw new IllegalStateException("Server has not been set on the ServletContextHandler");
|
||||
|
||||
JettyWebSocketServerContainer container = contextHandler.getBean(JettyWebSocketServerContainer.class);
|
||||
if (container == null)
|
||||
{
|
||||
// Find Pre-Existing executor
|
||||
Executor executor = (Executor)servletContext.getAttribute("org.eclipse.jetty.server.Executor");
|
||||
if (executor == null)
|
||||
executor = contextHandler.getServer().getThreadPool();
|
||||
|
||||
// Create the Jetty ServerContainer implementation
|
||||
container = new JettyWebSocketServerContainer(
|
||||
contextHandler,
|
||||
WebSocketMapping.ensureMapping(servletContext, WebSocketMapping.DEFAULT_KEY),
|
||||
WebSocketComponents.ensureWebSocketComponents(servletContext), executor);
|
||||
servletContext.setAttribute(WebSocketContainer.class.getName(), container);
|
||||
contextHandler.addManaged(container);
|
||||
contextHandler.addLifeCycleListener(container);
|
||||
}
|
||||
|
||||
return container;
|
||||
}
|
||||
|
||||
private final static Logger LOG = Log.getLogger(JettyWebSocketServerContainer.class);
|
||||
|
||||
private final WebSocketMapping webSocketMapping;
|
||||
private final WebSocketComponents webSocketComponents;
|
||||
private final FrameHandlerFactory frameHandlerFactory;
|
||||
private final Executor executor;
|
||||
private final FrameHandler.ConfigurationCustomizer customizer = new FrameHandler.ConfigurationCustomizer();
|
||||
|
||||
private final List<WebSocketSessionListener> sessionListeners = new ArrayList<>();
|
||||
private final SessionTracker sessionTracker = new SessionTracker();
|
||||
|
||||
/**
|
||||
* Main entry point for {@link JettyWebSocketServletContainerInitializer}.
|
||||
*
|
||||
* @param webSocketMapping the {@link WebSocketMapping} that this container belongs to
|
||||
* @param webSocketComponents the {@link WebSocketComponents} instance to use
|
||||
* @param executor the {@link Executor} to use
|
||||
*/
|
||||
public JettyWebSocketServerContainer(ServletContextHandler contextHandler, WebSocketMapping webSocketMapping, WebSocketComponents webSocketComponents, Executor executor)
|
||||
{
|
||||
this.webSocketMapping = webSocketMapping;
|
||||
this.webSocketComponents = webSocketComponents;
|
||||
this.executor = executor;
|
||||
|
||||
// Ensure there is a FrameHandlerFactory
|
||||
JettyServerFrameHandlerFactory factory = contextHandler.getBean(JettyServerFrameHandlerFactory.class);
|
||||
if (factory == null)
|
||||
{
|
||||
factory = new JettyServerFrameHandlerFactory(this);
|
||||
contextHandler.addManaged(factory);
|
||||
contextHandler.addLifeCycleListener(factory);
|
||||
}
|
||||
frameHandlerFactory = factory;
|
||||
|
||||
addSessionListener(sessionTracker);
|
||||
}
|
||||
|
||||
public void addMapping(String pathSpec, WebSocketCreator creator)
|
||||
{
|
||||
PathSpec ps = WebSocketMapping.parsePathSpec(pathSpec);
|
||||
if (webSocketMapping.getMapping(ps) != null)
|
||||
throw new WebSocketException("Duplicate WebSocket Mapping for PathSpec");
|
||||
|
||||
webSocketMapping.addMapping(ps, creator, frameHandlerFactory, customizer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Executor getExecutor()
|
||||
{
|
||||
return this.executor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSessionListener(WebSocketSessionListener listener)
|
||||
{
|
||||
sessionListeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeSessionListener(WebSocketSessionListener listener)
|
||||
{
|
||||
return sessionListeners.remove(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifySessionListeners(Consumer<WebSocketSessionListener> consumer)
|
||||
{
|
||||
for (WebSocketSessionListener listener : sessionListeners)
|
||||
{
|
||||
try
|
||||
{
|
||||
consumer.accept(listener);
|
||||
}
|
||||
catch (Throwable x)
|
||||
{
|
||||
LOG.info("Exception while invoking listener " + listener, x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Session> getOpenSessions()
|
||||
{
|
||||
return sessionTracker.getSessions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebSocketBehavior getBehavior()
|
||||
{
|
||||
return WebSocketBehavior.SERVER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Duration getIdleTimeout()
|
||||
{
|
||||
return customizer.getIdleTimeout();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInputBufferSize()
|
||||
{
|
||||
return customizer.getInputBufferSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOutputBufferSize()
|
||||
{
|
||||
return customizer.getOutputBufferSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMaxBinaryMessageSize()
|
||||
{
|
||||
return customizer.getMaxBinaryMessageSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMaxTextMessageSize()
|
||||
{
|
||||
return customizer.getMaxTextMessageSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIdleTimeout(Duration duration)
|
||||
{
|
||||
customizer.setIdleTimeout(duration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInputBufferSize(int size)
|
||||
{
|
||||
customizer.setInputBufferSize(size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOutputBufferSize(int size)
|
||||
{
|
||||
customizer.setOutputBufferSize(size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxBinaryMessageSize(long size)
|
||||
{
|
||||
customizer.setMaxBinaryMessageSize(size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxTextMessageSize(long size)
|
||||
{
|
||||
customizer.setMaxTextMessageSize(size);
|
||||
}
|
||||
}
|
|
@ -18,17 +18,19 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.server;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.ServletContainerInitializer;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import org.eclipse.jetty.servlet.FilterHolder;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.core.WebSocketComponents;
|
||||
import org.eclipse.jetty.websocket.servlet.WebSocketMapping;
|
||||
import org.eclipse.jetty.websocket.servlet.WebSocketUpgradeFilter;
|
||||
|
||||
/**
|
||||
* ServletContext configuration for Jetty Native WebSockets API.
|
||||
|
@ -37,45 +39,23 @@ public class JettyWebSocketServletContainerInitializer implements ServletContain
|
|||
{
|
||||
private static final Logger LOG = Log.getLogger(JettyWebSocketServletContainerInitializer.class);
|
||||
|
||||
public static class JettyWebSocketEmbeddedStarter extends AbstractLifeCycle implements ServletContextHandler.ServletContainerInitializerCaller
|
||||
public static JettyWebSocketServerContainer configureContext(ServletContextHandler context)
|
||||
{
|
||||
private ServletContainerInitializer sci;
|
||||
private ServletContextHandler context;
|
||||
WebSocketComponents components = WebSocketComponents.ensureWebSocketComponents(context.getServletContext());
|
||||
FilterHolder filterHolder = WebSocketUpgradeFilter.ensureFilter(context.getServletContext());
|
||||
WebSocketMapping mapping = WebSocketMapping.ensureMapping(context.getServletContext(), WebSocketMapping.DEFAULT_KEY);
|
||||
JettyWebSocketServerContainer container = JettyWebSocketServerContainer.ensureContainer(context.getServletContext());
|
||||
|
||||
public JettyWebSocketEmbeddedStarter(ServletContainerInitializer sci, ServletContextHandler context)
|
||||
{
|
||||
this.sci = sci;
|
||||
this.context = context;
|
||||
}
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("configureContext {} {} {} {}", container, mapping, filterHolder, components);
|
||||
|
||||
public void doStart()
|
||||
{
|
||||
try
|
||||
{
|
||||
Set<Class<?>> c = Collections.emptySet();
|
||||
sci.onStartup(c, context.getServletContext());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void configure(ServletContextHandler contextHandler)
|
||||
{
|
||||
JettyWebSocketServletContainerInitializer sci = new JettyWebSocketServletContainerInitializer();
|
||||
JettyWebSocketEmbeddedStarter starter = new JettyWebSocketEmbeddedStarter(sci, contextHandler);
|
||||
contextHandler.addBean(starter);
|
||||
return container;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartup(Set<Class<?>> c, ServletContext servletContext) throws ServletException
|
||||
public void onStartup(Set<Class<?>> c, ServletContext context) throws ServletException
|
||||
{
|
||||
WebSocketComponents components = WebSocketComponents.ensureWebSocketComponents(servletContext);
|
||||
JettyServerFrameHandlerFactory factory = JettyServerFrameHandlerFactory.ensureFactory(servletContext);
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("onStartup {} {}", components, factory);
|
||||
ServletContextHandler contextHandler = ServletContextHandler.getServletContextHandler(context,"Jetty WebSocket SCI");
|
||||
JettyWebSocketServletContainerInitializer.configureContext(contextHandler);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,99 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.server.internal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.common.SessionTracker;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketContainer;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketSessionListener;
|
||||
|
||||
public class JettyWebSocketServerContainer implements WebSocketContainer
|
||||
{
|
||||
private final static Logger LOG = Log.getLogger(JettyWebSocketServerContainer.class);
|
||||
private final Executor executor;
|
||||
private final List<WebSocketSessionListener> sessionListeners = new ArrayList<>();
|
||||
private final SessionTracker sessionTracker = new SessionTracker();
|
||||
|
||||
public JettyWebSocketServerContainer(ContextHandler handler)
|
||||
{
|
||||
Executor executor = (Executor) handler
|
||||
.getAttribute("org.eclipse.jetty.server.Executor");
|
||||
if (executor == null)
|
||||
{
|
||||
executor = handler.getServer().getThreadPool();
|
||||
}
|
||||
if (executor == null)
|
||||
{
|
||||
executor = new QueuedThreadPool(); // default settings
|
||||
}
|
||||
this.executor = executor;
|
||||
addSessionListener(sessionTracker);
|
||||
handler.addBean(sessionTracker);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Executor getExecutor()
|
||||
{
|
||||
return this.executor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSessionListener(WebSocketSessionListener listener)
|
||||
{
|
||||
sessionListeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeSessionListener(WebSocketSessionListener listener)
|
||||
{
|
||||
return sessionListeners.remove(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifySessionListeners(Consumer<WebSocketSessionListener> consumer)
|
||||
{
|
||||
for (WebSocketSessionListener listener : sessionListeners)
|
||||
{
|
||||
try
|
||||
{
|
||||
consumer.accept(listener);
|
||||
}
|
||||
catch (Throwable x)
|
||||
{
|
||||
LOG.info("Exception while invoking listener " + listener, x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Session> getOpenSessions()
|
||||
{
|
||||
return sessionTracker.getSessions();
|
||||
}
|
||||
}
|
|
@ -101,7 +101,7 @@ public class BrowserDebugTool
|
|||
|
||||
ServletContextHandler context = new ServletContextHandler();
|
||||
|
||||
JettyWebSocketServletContainerInitializer.configure(context);
|
||||
JettyWebSocketServletContainerInitializer.configureContext(context);
|
||||
|
||||
context.setContextPath("/");
|
||||
Resource staticResourceBase = findStaticResources();
|
||||
|
|
|
@ -40,11 +40,8 @@ import org.eclipse.jetty.websocket.api.Session;
|
|||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;
|
||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
|
||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketError;
|
||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketFrame;
|
||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
|
||||
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
|
||||
import org.eclipse.jetty.websocket.api.extensions.Frame;
|
||||
import org.eclipse.jetty.websocket.core.OpCode;
|
||||
|
||||
@WebSocket
|
||||
public class BrowserSocket
|
||||
|
|
|
@ -29,7 +29,7 @@ import org.eclipse.jetty.util.log.Log;
|
|||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketAdapter;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketSessionImpl;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketSession;
|
||||
import org.eclipse.jetty.websocket.core.internal.WebSocketChannel;
|
||||
import org.eclipse.jetty.websocket.core.internal.WebSocketConnection;
|
||||
import org.hamcrest.Matcher;
|
||||
|
@ -117,9 +117,9 @@ public class CloseTrackingEndpoint extends WebSocketAdapter
|
|||
public EndPoint getEndPoint()
|
||||
{
|
||||
Session session = getSession();
|
||||
assertThat("Session type", session, instanceOf(WebSocketSessionImpl.class));
|
||||
assertThat("Session type", session, instanceOf(WebSocketSession.class));
|
||||
|
||||
WebSocketSessionImpl wsSession = (WebSocketSessionImpl) session;
|
||||
WebSocketSession wsSession = (WebSocketSession) session;
|
||||
WebSocketChannel wsChannel = (WebSocketChannel) wsSession.getCoreSession();
|
||||
WebSocketConnection wsConnection = wsChannel.getConnection();
|
||||
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.tests;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
import org.eclipse.jetty.util.BlockingArrayQueue;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;
|
||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
|
||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketError;
|
||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
|
||||
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
|
||||
|
||||
@WebSocket
|
||||
public class EventSocket
|
||||
{
|
||||
private static Logger LOG = Log.getLogger(EventSocket.class);
|
||||
|
||||
protected Session session;
|
||||
private String behavior;
|
||||
public volatile Throwable failure = null;
|
||||
|
||||
public BlockingQueue<String> receivedMessages = new BlockingArrayQueue<>();
|
||||
|
||||
public CountDownLatch open = new CountDownLatch(1);
|
||||
public CountDownLatch error = new CountDownLatch(1);
|
||||
public CountDownLatch closed = new CountDownLatch(1);
|
||||
|
||||
@OnWebSocketConnect
|
||||
public void onOpen(Session session)
|
||||
{
|
||||
this.session = session;
|
||||
behavior = session.getPolicy().getBehavior().name();
|
||||
LOG.info("{} onOpen(): {}", toString(), session);
|
||||
open.countDown();
|
||||
}
|
||||
|
||||
@OnWebSocketMessage
|
||||
public void onMessage(String message) throws IOException
|
||||
{
|
||||
LOG.info("{} onMessage(): {}", toString(), message);
|
||||
receivedMessages.offer(message);
|
||||
}
|
||||
|
||||
@OnWebSocketClose
|
||||
public void onClose(int statusCode, String reason)
|
||||
{
|
||||
LOG.info("{} onClose(): {}:{}", toString(), statusCode, reason);
|
||||
closed.countDown();
|
||||
}
|
||||
|
||||
@OnWebSocketError
|
||||
public void onError(Throwable cause)
|
||||
{
|
||||
LOG.info("{} onError(): {}", toString(), cause);
|
||||
failure = cause;
|
||||
error.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("[%s@%s]", behavior, Integer.toHexString(hashCode()));
|
||||
}
|
||||
|
||||
@WebSocket
|
||||
public static class EchoSocket extends EventSocket
|
||||
{
|
||||
@Override
|
||||
public void onMessage(String message) throws IOException
|
||||
{
|
||||
super.onMessage(message);
|
||||
session.getRemote().sendStringByFuture(message);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.tests;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
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.client.WebSocketClient;
|
||||
import org.eclipse.jetty.websocket.server.JettyWebSocketServerContainer;
|
||||
import org.eclipse.jetty.websocket.server.JettyWebSocketServletContainerInitializer;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
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.assertTrue;
|
||||
|
||||
public class JettyWebSocketFilterTest
|
||||
{
|
||||
Server server;
|
||||
WebSocketClient client;
|
||||
|
||||
@BeforeEach
|
||||
public void start() throws Exception
|
||||
{
|
||||
server = new Server();
|
||||
ServerConnector connector = new ServerConnector(server);
|
||||
connector.setPort(8080);
|
||||
server.addConnector(connector);
|
||||
|
||||
ServletContextHandler contextHandler = new ServletContextHandler(ServletContextHandler.SESSIONS);
|
||||
contextHandler.setContextPath("/");
|
||||
server.setHandler(contextHandler);
|
||||
|
||||
JettyWebSocketServerContainer container = JettyWebSocketServletContainerInitializer.configureContext(contextHandler);
|
||||
container.addMapping("/", (req, resp)->new EventSocket.EchoSocket());
|
||||
server.start();
|
||||
|
||||
client = new WebSocketClient();
|
||||
client.start();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void stop() throws Exception
|
||||
{
|
||||
client.stop();
|
||||
server.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() throws Exception
|
||||
{
|
||||
URI uri = URI.create("ws://localhost:8080/filterPath");
|
||||
EventSocket socket = new EventSocket();
|
||||
CompletableFuture<Session> connect = client.connect(socket, uri);
|
||||
try(Session session = connect.get(5, TimeUnit.SECONDS))
|
||||
{
|
||||
session.getRemote().sendString("hello world");
|
||||
}
|
||||
assertTrue(socket.closed.await(10, TimeUnit.SECONDS));
|
||||
|
||||
String msg = socket.receivedMessages.poll();
|
||||
assertThat(msg, is("hello world"));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.tests;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
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.client.WebSocketClient;
|
||||
import org.eclipse.jetty.websocket.server.JettyWebSocketServletContainerInitializer;
|
||||
import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
|
||||
import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
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.assertTrue;
|
||||
|
||||
public class JettyWebSocketServletTest
|
||||
{
|
||||
public static class MyWebSocketServlet extends WebSocketServlet
|
||||
{
|
||||
@Override
|
||||
public void configure(WebSocketServletFactory factory)
|
||||
{
|
||||
factory.addMapping("/",(req, resp)->new EventSocket.EchoSocket());
|
||||
}
|
||||
}
|
||||
|
||||
Server server;
|
||||
WebSocketClient client;
|
||||
|
||||
@BeforeEach
|
||||
public void start() throws Exception
|
||||
{
|
||||
server = new Server();
|
||||
ServerConnector connector = new ServerConnector(server);
|
||||
connector.setPort(8080);
|
||||
server.addConnector(connector);
|
||||
|
||||
ServletContextHandler contextHandler = new ServletContextHandler(ServletContextHandler.SESSIONS);
|
||||
contextHandler.setContextPath("/");
|
||||
server.setHandler(contextHandler);
|
||||
|
||||
contextHandler.addServlet(MyWebSocketServlet.class, "/servletPath");
|
||||
|
||||
JettyWebSocketServletContainerInitializer.configureContext(contextHandler);
|
||||
server.start();
|
||||
|
||||
client = new WebSocketClient();
|
||||
client.start();
|
||||
}
|
||||
|
||||
|
||||
@AfterEach
|
||||
public void stop() throws Exception
|
||||
{
|
||||
client.stop();
|
||||
server.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() throws Exception
|
||||
{
|
||||
URI uri = URI.create("ws://localhost:8080/servletPath");
|
||||
EventSocket socket = new EventSocket();
|
||||
CompletableFuture<Session> connect = client.connect(socket, uri);
|
||||
try(Session session = connect.get(5, TimeUnit.SECONDS))
|
||||
{
|
||||
session.getRemote().sendString("hello world");
|
||||
}
|
||||
assertTrue(socket.closed.await(10, TimeUnit.SECONDS));
|
||||
|
||||
String msg = socket.receivedMessages.poll();
|
||||
assertThat(msg, is("hello world"));
|
||||
}
|
||||
}
|
|
@ -1,146 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.tests;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
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.annotations.OnWebSocketClose;
|
||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
|
||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketError;
|
||||
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.JettyWebSocketServletContainerInitializer;
|
||||
import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
|
||||
import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class JettyWebSocketTest
|
||||
{
|
||||
|
||||
@WebSocket
|
||||
public static class EventSocket
|
||||
{
|
||||
CountDownLatch closed = new CountDownLatch(1);
|
||||
|
||||
String behavior;
|
||||
|
||||
@OnWebSocketConnect
|
||||
public void onOpen(Session sess)
|
||||
{
|
||||
behavior = sess.getPolicy().getBehavior().name();
|
||||
System.err.println(toString() + " Socket Connected: " + sess);
|
||||
}
|
||||
|
||||
@OnWebSocketMessage
|
||||
public void onMessage(String message)
|
||||
{
|
||||
System.err.println(toString() + " Received TEXT message: " + message);
|
||||
}
|
||||
|
||||
@OnWebSocketClose
|
||||
public void onClose(int statusCode, String reason)
|
||||
{
|
||||
System.err.println(toString() + " Socket Closed: " + statusCode + ":" + reason);
|
||||
closed.countDown();
|
||||
}
|
||||
|
||||
@OnWebSocketError
|
||||
public void onError(Throwable cause)
|
||||
{
|
||||
cause.printStackTrace(System.err);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("[%s@%s]", behavior, Integer.toHexString(hashCode()));
|
||||
}
|
||||
}
|
||||
|
||||
public static class MyWebSocketServlet extends WebSocketServlet
|
||||
{
|
||||
@Override
|
||||
public void configure(WebSocketServletFactory factory)
|
||||
{
|
||||
factory.addMapping("/",(req, resp)->new EventSocket());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void test() throws Exception
|
||||
{
|
||||
Server server = new Server();
|
||||
ServerConnector connector = new ServerConnector(server);
|
||||
connector.setPort(8080);
|
||||
server.addConnector(connector);
|
||||
|
||||
ServletContextHandler contextHandler = new ServletContextHandler(ServletContextHandler.SESSIONS);
|
||||
contextHandler.setContextPath("/");
|
||||
server.setHandler(contextHandler);
|
||||
|
||||
contextHandler.addServlet(MyWebSocketServlet.class, "/testPath1");
|
||||
contextHandler.addServlet(MyWebSocketServlet.class, "/testPath2");
|
||||
|
||||
try
|
||||
{
|
||||
JettyWebSocketServletContainerInitializer.configure(contextHandler);
|
||||
server.start();
|
||||
|
||||
WebSocketClient client = new WebSocketClient();
|
||||
client.start();
|
||||
|
||||
URI uri = URI.create("ws://localhost:8080/testPath1");
|
||||
EventSocket socket = new EventSocket();
|
||||
CompletableFuture<Session> connect = client.connect(socket, uri);
|
||||
try(Session session = connect.get(5, TimeUnit.SECONDS))
|
||||
{
|
||||
session.getRemote().sendString("hello world");
|
||||
}
|
||||
assertTrue(socket.closed.await(10, TimeUnit.SECONDS));
|
||||
|
||||
|
||||
uri = URI.create("ws://localhost:8080/testPath2");
|
||||
socket = new EventSocket();
|
||||
connect = client.connect(socket, uri);
|
||||
try(Session session = connect.get(5, TimeUnit.SECONDS))
|
||||
{
|
||||
session.getRemote().sendString("hello world");
|
||||
}
|
||||
assertTrue(socket.closed.await(10, TimeUnit.SECONDS));
|
||||
|
||||
|
||||
server.stop();
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -115,7 +115,7 @@ public class WebSocketServletExamplesTest
|
|||
_context.addServlet(MyAdvancedEchoServlet.class, "/advancedEcho");
|
||||
_context.addServlet(MyAuthedServlet.class, "/authed");
|
||||
|
||||
JettyWebSocketServletContainerInitializer.configure(_context);
|
||||
JettyWebSocketServletContainerInitializer.configureContext(_context);
|
||||
_server.start();
|
||||
}
|
||||
|
||||
|
|
|
@ -147,7 +147,7 @@ public class WebSocketStatsTest
|
|||
contextHandler.addServlet(MyWebSocketServlet.class, "/testPath");
|
||||
server.setHandler(contextHandler);
|
||||
|
||||
JettyWebSocketServletContainerInitializer.configure(contextHandler);
|
||||
JettyWebSocketServletContainerInitializer.configureContext(contextHandler);
|
||||
client = new WebSocketClient();
|
||||
|
||||
server.start();
|
||||
|
|
|
@ -74,7 +74,6 @@ public class BadNetworkTest
|
|||
server.addConnector(connector);
|
||||
|
||||
ServletContextHandler context = new ServletContextHandler();
|
||||
JettyWebSocketServletContainerInitializer.configure(context);
|
||||
context.setContextPath("/");
|
||||
ServletHolder holder = new ServletHolder(new WebSocketServlet()
|
||||
{
|
||||
|
@ -92,6 +91,7 @@ public class BadNetworkTest
|
|||
handlers.addHandler(context);
|
||||
handlers.addHandler(new DefaultHandler());
|
||||
server.setHandler(handlers);
|
||||
JettyWebSocketServletContainerInitializer.configureContext(context);
|
||||
|
||||
server.start();
|
||||
}
|
||||
|
|
|
@ -38,6 +38,8 @@ import org.eclipse.jetty.servlet.ServletContextHandler;
|
|||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.api.CloseException;
|
||||
import org.eclipse.jetty.websocket.api.Frame;
|
||||
import org.eclipse.jetty.websocket.api.MessageTooLargeException;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.api.StatusCode;
|
||||
|
@ -118,7 +120,6 @@ public class ClientCloseTest
|
|||
server.addConnector(connector);
|
||||
|
||||
ServletContextHandler context = new ServletContextHandler();
|
||||
JettyWebSocketServletContainerInitializer.configure(context);
|
||||
context.setContextPath("/");
|
||||
ServletHolder holder = new ServletHolder(new WebSocketServlet()
|
||||
{
|
||||
|
@ -136,6 +137,7 @@ public class ClientCloseTest
|
|||
handlers.addHandler(context);
|
||||
handlers.addHandler(new DefaultHandler());
|
||||
server.setHandler(handlers);
|
||||
JettyWebSocketServletContainerInitializer.configureContext(context);
|
||||
|
||||
server.start();
|
||||
}
|
||||
|
@ -427,7 +429,7 @@ public class ClientCloseTest
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketFrame(org.eclipse.jetty.websocket.api.extensions.Frame frame)
|
||||
public void onWebSocketFrame(Frame frame)
|
||||
{
|
||||
if (frame.getOpCode() == OpCode.CLOSE)
|
||||
{
|
||||
|
|
|
@ -22,7 +22,7 @@ import java.util.concurrent.CountDownLatch;
|
|||
|
||||
import org.eclipse.jetty.io.Connection;
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketSessionImpl;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketSession;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketSessionListener;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
|
@ -64,12 +64,12 @@ public class ClientOpenSessionTracker implements Connection.Listener, WebSocketS
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketSessionOpened(WebSocketSessionImpl session)
|
||||
public void onWebSocketSessionOpened(WebSocketSession session)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketSessionClosed(WebSocketSessionImpl session)
|
||||
public void onWebSocketSessionClosed(WebSocketSession session)
|
||||
{
|
||||
this.closeSessionLatch.countDown();
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ import org.eclipse.jetty.websocket.api.StatusCode;
|
|||
import org.eclipse.jetty.websocket.api.util.WSURI;
|
||||
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketSessionImpl;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketSession;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketSessionListener;
|
||||
import org.eclipse.jetty.websocket.server.JettyWebSocketServletContainerInitializer;
|
||||
import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
|
||||
|
@ -68,7 +68,6 @@ public class ClientSessionsTest
|
|||
server.addConnector(connector);
|
||||
|
||||
ServletContextHandler context = new ServletContextHandler();
|
||||
JettyWebSocketServletContainerInitializer.configure(context);
|
||||
context.setContextPath("/");
|
||||
ServletHolder holder = new ServletHolder(new WebSocketServlet()
|
||||
{
|
||||
|
@ -86,6 +85,7 @@ public class ClientSessionsTest
|
|||
handlers.addHandler(context);
|
||||
handlers.addHandler(new DefaultHandler());
|
||||
server.setHandler(handlers);
|
||||
JettyWebSocketServletContainerInitializer.configureContext(context);
|
||||
|
||||
server.start();
|
||||
}
|
||||
|
@ -105,12 +105,12 @@ public class ClientSessionsTest
|
|||
|
||||
client.addSessionListener(new WebSocketSessionListener() {
|
||||
@Override
|
||||
public void onWebSocketSessionOpened(WebSocketSessionImpl session)
|
||||
public void onWebSocketSessionOpened(WebSocketSession session)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketSessionClosed(WebSocketSessionImpl session)
|
||||
public void onWebSocketSessionClosed(WebSocketSession session)
|
||||
{
|
||||
onSessionCloseLatch.countDown();
|
||||
}
|
||||
|
|
|
@ -81,13 +81,13 @@ public class SlowClientTest
|
|||
}
|
||||
});
|
||||
context.addServlet(websocket, "/ws");
|
||||
JettyWebSocketServletContainerInitializer.configure(context);
|
||||
|
||||
HandlerList handlers = new HandlerList();
|
||||
handlers.addHandler(context);
|
||||
handlers.addHandler(new DefaultHandler());
|
||||
|
||||
server.setHandler(handlers);
|
||||
JettyWebSocketServletContainerInitializer.configureContext(context);
|
||||
|
||||
server.start();
|
||||
}
|
||||
|
|
|
@ -56,6 +56,7 @@ public abstract class AbstractCloseEndpoint extends WebSocketAdapter
|
|||
@Override
|
||||
public void onWebSocketError(Throwable cause)
|
||||
{
|
||||
LOG.debug("onWebSocketError({})", cause.getClass().getSimpleName());
|
||||
errors.offer(cause);
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ import org.eclipse.jetty.websocket.api.StatusCode;
|
|||
import org.eclipse.jetty.websocket.api.util.WSURI;
|
||||
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketSessionImpl;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketSession;
|
||||
import org.eclipse.jetty.websocket.core.internal.WebSocketChannel;
|
||||
import org.eclipse.jetty.websocket.server.JettyWebSocketServletContainerInitializer;
|
||||
import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
|
||||
|
@ -84,13 +84,13 @@ public class ServerCloseTest
|
|||
}
|
||||
});
|
||||
context.addServlet(closeEndpoint, "/ws");
|
||||
JettyWebSocketServletContainerInitializer.configure(context);
|
||||
|
||||
HandlerList handlers = new HandlerList();
|
||||
handlers.addHandler(context);
|
||||
handlers.addHandler(new DefaultHandler());
|
||||
|
||||
server.setHandler(handlers);
|
||||
JettyWebSocketServletContainerInitializer.configureContext(context);
|
||||
|
||||
server.start();
|
||||
}
|
||||
|
@ -212,7 +212,7 @@ public class ServerCloseTest
|
|||
Future<Session> futSession = client.connect(clientEndpoint, wsUri, request);
|
||||
|
||||
Session session = null;
|
||||
try(StacklessLogging ignore = new StacklessLogging(WebSocketSessionImpl.class))
|
||||
try(StacklessLogging ignore = new StacklessLogging(WebSocketSession.class))
|
||||
{
|
||||
session = futSession.get(5, SECONDS);
|
||||
|
||||
|
@ -241,9 +241,9 @@ public class ServerCloseTest
|
|||
@Test
|
||||
public void testOpenSessionCleanup() throws Exception
|
||||
{
|
||||
fastFail();
|
||||
fastClose();
|
||||
dropConnection();
|
||||
//fastFail();
|
||||
//fastClose();
|
||||
//dropConnection();
|
||||
|
||||
ClientUpgradeRequest request = new ClientUpgradeRequest();
|
||||
request.setSubProtocols("container");
|
||||
|
@ -253,7 +253,7 @@ public class ServerCloseTest
|
|||
Future<Session> futSession = client.connect(clientEndpoint, wsUri, request);
|
||||
|
||||
Session session = null;
|
||||
try(StacklessLogging ignore = new StacklessLogging(WebSocketSessionImpl.class))
|
||||
try(StacklessLogging ignore = new StacklessLogging(WebSocketSession.class))
|
||||
{
|
||||
session = futSession.get(5, SECONDS);
|
||||
|
||||
|
|
|
@ -81,13 +81,13 @@ public class SlowServerTest
|
|||
}
|
||||
});
|
||||
context.addServlet(websocket, "/ws");
|
||||
JettyWebSocketServletContainerInitializer.configure(context);
|
||||
|
||||
HandlerList handlers = new HandlerList();
|
||||
handlers.addHandler(context);
|
||||
handlers.addHandler(new DefaultHandler());
|
||||
|
||||
server.setHandler(handlers);
|
||||
JettyWebSocketServletContainerInitializer.configureContext(context);
|
||||
|
||||
server.start();
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
# org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.Slf4jLog
|
||||
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
|
||||
org.eclipse.jetty.LEVEL=WARN
|
||||
org.eclipse.jetty.websocket.tests.LEVEL=DEBUG
|
||||
# org.eclipse.jetty.util.log.stderr.LONG=true
|
||||
# org.eclipse.jetty.server.AbstractConnector.LEVEL=DEBUG
|
||||
# org.eclipse.jetty.io.WriteFlusher.LEVEL=DEBUG
|
||||
|
|
|
@ -61,11 +61,11 @@ public class WebSocketMapping implements Dumpable, LifeCycle.Listener
|
|||
{
|
||||
private static final Logger LOG = Log.getLogger(WebSocketMapping.class);
|
||||
|
||||
public static WebSocketMapping ensureMapping(ServletContext servletContext, String mappingKey)
|
||||
public static WebSocketMapping getMapping(ServletContext servletContext, String mappingKey)
|
||||
{
|
||||
ContextHandler contextHandler = ContextHandler.getContextHandler(servletContext);
|
||||
|
||||
Object mappingObject = contextHandler.getAttribute(mappingKey);
|
||||
|
||||
if (mappingObject!=null)
|
||||
{
|
||||
if (WebSocketMapping.class.isInstance(mappingObject))
|
||||
|
@ -73,104 +73,24 @@ public class WebSocketMapping implements Dumpable, LifeCycle.Listener
|
|||
else
|
||||
throw new IllegalStateException(
|
||||
String.format("ContextHandler attribute %s is not of type WebSocketMapping: {%s}",
|
||||
mappingKey, mappingObject.toString()));
|
||||
}
|
||||
else
|
||||
{
|
||||
WebSocketMapping mapping = new WebSocketMapping(WebSocketComponents.ensureWebSocketComponents(servletContext));
|
||||
contextHandler.setAttribute(mappingKey, mapping);
|
||||
return mapping;
|
||||
mappingKey, mappingObject.toString()));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static final String DEFAULT_KEY = "org.eclipse.jetty.websocket.servlet.WebSocketMapping";
|
||||
|
||||
private final PathMappings<Negotiator> mappings = new PathMappings<>();
|
||||
private final WebSocketComponents components;
|
||||
private final Handshaker handshaker = Handshaker.newInstance();
|
||||
|
||||
public WebSocketMapping()
|
||||
public static WebSocketMapping ensureMapping(ServletContext servletContext, String mappingKey)
|
||||
{
|
||||
this(new WebSocketComponents());
|
||||
}
|
||||
ContextHandler contextHandler = ContextHandler.getContextHandler(servletContext);
|
||||
WebSocketMapping mapping = getMapping(servletContext, mappingKey);
|
||||
|
||||
public WebSocketMapping(WebSocketComponents components)
|
||||
{
|
||||
this.components = components;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lifeCycleStopping(LifeCycle context)
|
||||
{
|
||||
ContextHandler contextHandler = (ContextHandler) context;
|
||||
WebSocketMapping mapping = contextHandler.getBean(WebSocketMapping.class);
|
||||
if (mapping == this)
|
||||
{
|
||||
contextHandler.removeBean(mapping);
|
||||
mappings.reset();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Manually add a WebSocket mapping.
|
||||
* <p>
|
||||
* If mapping is added before this configuration is started, then it is persisted through
|
||||
* stop/start of this configuration's lifecycle. Otherwise it will be removed when
|
||||
* this configuration is stopped.
|
||||
* </p>
|
||||
*
|
||||
* @param pathSpec the pathspec to respond on
|
||||
* @param creator the websocket creator to activate on the provided mapping.
|
||||
* @param factory the factory to use to create a FrameHandler for the websocket
|
||||
* @param customizer the customizer to use to customize the WebSocket session.
|
||||
*/
|
||||
public void addMapping(PathSpec pathSpec, WebSocketCreator creator, FrameHandlerFactory factory, FrameHandler.Customizer customizer)
|
||||
throws WebSocketException
|
||||
{
|
||||
// TODO evaluate why this can't be done
|
||||
//if (getMapping(pathSpec) != null)
|
||||
// throw new WebSocketException("Duplicate WebSocket Mapping for PathSpec");
|
||||
|
||||
mappings.put(pathSpec, new Negotiator(creator, factory, customizer));
|
||||
}
|
||||
|
||||
public WebSocketCreator getMapping(PathSpec pathSpec)
|
||||
{
|
||||
Negotiator cn = mappings.get(pathSpec);
|
||||
return cn == null?null:cn.getWebSocketCreator();
|
||||
}
|
||||
|
||||
public boolean removeMapping(PathSpec pathSpec)
|
||||
{
|
||||
return mappings.remove(pathSpec);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String dump()
|
||||
{
|
||||
return Dumpable.dump(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(Appendable out, String indent) throws IOException
|
||||
{
|
||||
Dumpable.dumpObjects(out, indent, this, mappings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the matching {@link MappedResource} for the provided target.
|
||||
*
|
||||
* @param target the target path
|
||||
* @return the matching resource, or null if no match.
|
||||
*/
|
||||
public WebSocketNegotiator getMatchedNegotiator(String target, Consumer<PathSpec> pathSpecConsumer)
|
||||
{
|
||||
MappedResource<Negotiator> mapping = this.mappings.getMatch(target);
|
||||
if (mapping == null)
|
||||
return null;
|
||||
{
|
||||
mapping = new WebSocketMapping(WebSocketComponents.ensureWebSocketComponents(servletContext));
|
||||
contextHandler.setAttribute(mappingKey, mapping);
|
||||
}
|
||||
|
||||
pathSpecConsumer.accept(mapping.getPathSpec());
|
||||
return mapping.getResource();
|
||||
return mapping;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -212,6 +132,91 @@ public class WebSocketMapping implements Dumpable, LifeCycle.Listener
|
|||
throw new IllegalArgumentException("Unrecognized path spec syntax [" + rawSpec + "]");
|
||||
}
|
||||
|
||||
public static final String DEFAULT_KEY = "org.eclipse.jetty.websocket.servlet.WebSocketMapping";
|
||||
|
||||
private final PathMappings<Negotiator> mappings = new PathMappings<>();
|
||||
private final WebSocketComponents components;
|
||||
private final Handshaker handshaker = Handshaker.newInstance();
|
||||
|
||||
public WebSocketMapping()
|
||||
{
|
||||
this(new WebSocketComponents());
|
||||
}
|
||||
|
||||
public WebSocketMapping(WebSocketComponents components)
|
||||
{
|
||||
this.components = components;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lifeCycleStopping(LifeCycle context)
|
||||
{
|
||||
ContextHandler contextHandler = (ContextHandler) context;
|
||||
WebSocketMapping mapping = contextHandler.getBean(WebSocketMapping.class);
|
||||
if (mapping == this)
|
||||
{
|
||||
contextHandler.removeBean(mapping);
|
||||
mappings.reset();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String dump()
|
||||
{
|
||||
return Dumpable.dump(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(Appendable out, String indent) throws IOException
|
||||
{
|
||||
Dumpable.dumpObjects(out, indent, this, mappings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Manually add a WebSocket mapping.
|
||||
* <p>
|
||||
* If mapping is added before this configuration is started, then it is persisted through
|
||||
* stop/start of this configuration's lifecycle. Otherwise it will be removed when
|
||||
* this configuration is stopped.
|
||||
* </p>
|
||||
*
|
||||
* @param pathSpec the pathspec to respond on
|
||||
* @param creator the websocket creator to activate on the provided mapping.
|
||||
* @param factory the factory to use to create a FrameHandler for the websocket
|
||||
* @param customizer the customizer to use to customize the WebSocket session.
|
||||
*/
|
||||
public void addMapping(PathSpec pathSpec, WebSocketCreator creator, FrameHandlerFactory factory, FrameHandler.Customizer customizer) throws WebSocketException
|
||||
{
|
||||
mappings.put(pathSpec, new Negotiator(creator, factory, customizer));
|
||||
}
|
||||
|
||||
public WebSocketCreator getMapping(PathSpec pathSpec)
|
||||
{
|
||||
Negotiator cn = mappings.get(pathSpec);
|
||||
return cn == null?null:cn.getWebSocketCreator();
|
||||
}
|
||||
|
||||
public boolean removeMapping(PathSpec pathSpec)
|
||||
{
|
||||
return mappings.remove(pathSpec);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the matching {@link MappedResource} for the provided target.
|
||||
*
|
||||
* @param target the target path
|
||||
* @return the matching resource, or null if no match.
|
||||
*/
|
||||
public WebSocketNegotiator getMatchedNegotiator(String target, Consumer<PathSpec> pathSpecConsumer)
|
||||
{
|
||||
MappedResource<Negotiator> mapping = this.mappings.getMatch(target);
|
||||
if (mapping == null)
|
||||
return null;
|
||||
|
||||
pathSpecConsumer.accept(mapping.getPathSpec());
|
||||
return mapping.getResource();
|
||||
}
|
||||
|
||||
public boolean upgrade(HttpServletRequest request, HttpServletResponse response, FrameHandler.Customizer defaultCustomizer)
|
||||
{
|
||||
try
|
||||
|
@ -241,9 +246,7 @@ public class WebSocketMapping implements Dumpable, LifeCycle.Listener
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Unable to upgrade: "+e);
|
||||
LOG.ignore(e);
|
||||
LOG.warn("Error during upgrade: ", e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -189,9 +189,10 @@ public abstract class WebSocketServlet extends HttpServlet
|
|||
@Override
|
||||
public void addMapping(PathSpec pathSpec, WebSocketCreator creator)
|
||||
{
|
||||
// TODO a bit fragile. This code knows that only the JettyFHF is added directly as a been
|
||||
ServletContext servletContext = getServletContext();
|
||||
ContextHandler contextHandler = ServletContextHandler.getServletContextHandler(servletContext, "WebSocketServlet");
|
||||
|
||||
// TODO: a bit fragile, this code knows that only the JettyFHF is added as a bean
|
||||
FrameHandlerFactory frameHandlerFactory = contextHandler.getBean(FrameHandlerFactory.class);
|
||||
|
||||
if (frameHandlerFactory==null)
|
||||
|
|
|
@ -21,39 +21,54 @@ package org.eclipse.jetty.websocket.servlet;
|
|||
import java.time.Duration;
|
||||
|
||||
import org.eclipse.jetty.http.pathmap.PathSpec;
|
||||
import org.eclipse.jetty.websocket.core.FrameHandler;
|
||||
import org.eclipse.jetty.websocket.core.WebSocketExtensionRegistry;
|
||||
|
||||
public interface WebSocketServletFactory
|
||||
public interface WebSocketServletFactory extends FrameHandler.Configuration
|
||||
{
|
||||
|
||||
WebSocketExtensionRegistry getExtensionRegistry();
|
||||
|
||||
@Override
|
||||
Duration getIdleTimeout();
|
||||
|
||||
@Override
|
||||
void setIdleTimeout(Duration duration);
|
||||
|
||||
@Override
|
||||
int getInputBufferSize();
|
||||
|
||||
@Override
|
||||
void setInputBufferSize(int bufferSize);
|
||||
|
||||
@Override
|
||||
long getMaxFrameSize();
|
||||
|
||||
@Override
|
||||
void setMaxFrameSize(long maxFrameSize);
|
||||
|
||||
@Override
|
||||
long getMaxBinaryMessageSize();
|
||||
|
||||
@Override
|
||||
void setMaxBinaryMessageSize(long bufferSize);
|
||||
|
||||
@Override
|
||||
long getMaxTextMessageSize();
|
||||
|
||||
@Override
|
||||
void setMaxTextMessageSize(long bufferSize);
|
||||
|
||||
@Override
|
||||
int getOutputBufferSize();
|
||||
|
||||
@Override
|
||||
void setOutputBufferSize(int bufferSize);
|
||||
|
||||
@Override
|
||||
boolean isAutoFragment();
|
||||
|
||||
@Override
|
||||
void setAutoFragment(boolean autoFragment);
|
||||
|
||||
void addMapping(String pathSpec, WebSocketCreator creator);
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.eclipse.jetty.websocket.servlet;
|
|||
import java.io.IOException;
|
||||
import java.time.Duration;
|
||||
import java.util.EnumSet;
|
||||
|
||||
import javax.servlet.DispatcherType;
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
|
@ -82,7 +83,7 @@ public class WebSocketUpgradeFilter implements Filter, Dumpable
|
|||
|
||||
for (FilterHolder holder : servletHandler.getFilters())
|
||||
{
|
||||
if (holder.getInitParameter(MAPPING_INIT_PARAM) != null)
|
||||
if (holder.getInitParameter(MAPPING_ATTRIBUTE_INIT_PARAM) != null)
|
||||
return holder;
|
||||
}
|
||||
|
||||
|
@ -100,7 +101,7 @@ public class WebSocketUpgradeFilter implements Filter, Dumpable
|
|||
EnumSet<DispatcherType> dispatcherTypes = EnumSet.of(DispatcherType.REQUEST);
|
||||
FilterHolder holder = new FilterHolder(new WebSocketUpgradeFilter());
|
||||
holder.setName(name);
|
||||
holder.setInitParameter(MAPPING_INIT_PARAM, WebSocketMapping.DEFAULT_KEY);
|
||||
holder.setInitParameter(MAPPING_ATTRIBUTE_INIT_PARAM, WebSocketMapping.DEFAULT_KEY);
|
||||
|
||||
holder.setAsyncSupported(true);
|
||||
ServletHandler servletHandler = ContextHandler.getContextHandler(servletContext).getChildHandlerByClass(ServletHandler.class);
|
||||
|
@ -110,7 +111,7 @@ public class WebSocketUpgradeFilter implements Filter, Dumpable
|
|||
return holder;
|
||||
}
|
||||
|
||||
public final static String MAPPING_INIT_PARAM = "org.eclipse.jetty.websocket.servlet.WebSocketMapping.key";
|
||||
public final static String MAPPING_ATTRIBUTE_INIT_PARAM = "org.eclipse.jetty.websocket.servlet.WebSocketMapping.key";
|
||||
|
||||
private final FrameHandler.ConfigurationCustomizer defaultCustomizer = new FrameHandler.ConfigurationCustomizer();
|
||||
private WebSocketMapping mapping;
|
||||
|
@ -157,7 +158,7 @@ public class WebSocketUpgradeFilter implements Filter, Dumpable
|
|||
{
|
||||
final ServletContext context = config.getServletContext();
|
||||
|
||||
String mappingKey = config.getInitParameter(MAPPING_INIT_PARAM);
|
||||
String mappingKey = config.getInitParameter(MAPPING_ATTRIBUTE_INIT_PARAM);
|
||||
if (mappingKey != null)
|
||||
mapping = WebSocketMapping.ensureMapping(context, mappingKey);
|
||||
else
|
||||
|
@ -193,4 +194,9 @@ public class WebSocketUpgradeFilter implements Filter, Dumpable
|
|||
if (autoFragment != null)
|
||||
defaultCustomizer.setAutoFragment(Boolean.parseBoolean(autoFragment));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
6
pom.xml
6
pom.xml
|
@ -27,6 +27,7 @@
|
|||
<jetty-test-policy.version>1.2</jetty-test-policy.version>
|
||||
<servlet.api.version>4.0.2</servlet.api.version>
|
||||
<jsp.version>9.0.14.1</jsp.version>
|
||||
<infinispan.version>9.4.8.Final</infinispan.version>
|
||||
<!-- default values are unsupported, but required to be defined for reactor sanity reasons -->
|
||||
<alpn.version>undefined</alpn.version>
|
||||
<conscrypt.version>1.4.1</conscrypt.version>
|
||||
|
@ -1031,6 +1032,11 @@
|
|||
<artifactId>slf4j-simple</artifactId>
|
||||
<version>${slf4j.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jboss.logging</groupId>
|
||||
<artifactId>jboss-logging</artifactId>
|
||||
<version>3.3.2.Final</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.jnr</groupId>
|
||||
<artifactId>jnr-unixsocket</artifactId>
|
||||
|
|
|
@ -106,19 +106,19 @@
|
|||
<dependency>
|
||||
<groupId>org.infinispan</groupId>
|
||||
<artifactId>infinispan-core</artifactId>
|
||||
<version>9.1.0.Final</version>
|
||||
<version>${infinispan.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.infinispan</groupId>
|
||||
<artifactId>infinispan-client-hotrod</artifactId>
|
||||
<version>9.1.0.Final</version>
|
||||
<version>${infinispan.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.infinispan</groupId>
|
||||
<artifactId>infinispan-remote-query-client</artifactId>
|
||||
<version>9.1.0.Final</version>
|
||||
<version>${infinispan.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
|
|
@ -22,9 +22,12 @@ package org.eclipse.jetty.server.session;
|
|||
import org.eclipse.jetty.session.infinispan.InfinispanSessionDataStoreFactory;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@Disabled("Disabled due to Infinispan not supporting JDK 11, see eclipse/jetty.project#3024")
|
||||
/**
|
||||
* ClusteredSessionScavengingTest
|
||||
*
|
||||
*/
|
||||
public class ClusteredSessionScavengingTest extends AbstractClusteredSessionScavengingTest
|
||||
{
|
||||
public InfinispanTestSupport _testSupport;
|
||||
|
@ -44,6 +47,18 @@ public class ClusteredSessionScavengingTest extends AbstractClusteredSessionScav
|
|||
_testSupport.teardown();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Test
|
||||
public void testClusteredScavenge()
|
||||
throws Exception
|
||||
{
|
||||
super.testClusteredScavenge();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.session.AbstractTestBase#createSessionDataStoreFactory()
|
||||
*/
|
||||
@Override
|
||||
public SessionDataStoreFactory createSessionDataStoreFactory()
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue