Issue #207 - more test induced fixes

# Conflicts:
#	jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/IdleTimeoutTest.java
This commit is contained in:
Joakim Erdfelt 2017-05-04 13:37:29 -07:00
parent 79f30041a1
commit ad29d65229
33 changed files with 1697 additions and 1850 deletions

View File

@ -1,119 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2017 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.jsr356.server;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.assertThat;
import java.net.URI;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.StatusCode;
import org.eclipse.jetty.websocket.client.WebSocketClient;
import org.eclipse.jetty.websocket.common.test.LeakTrackingBufferPoolRule;
import org.eclipse.jetty.websocket.jsr356.server.samples.idletimeout.IdleTimeoutContextListener;
import org.eclipse.jetty.websocket.jsr356.server.samples.idletimeout.OnOpenIdleTimeoutEndpoint;
import org.eclipse.jetty.websocket.jsr356.server.samples.idletimeout.OnOpenIdleTimeoutSocket;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
public class IdleTimeoutTest
{
private static final Logger LOG = Log.getLogger(IdleTimeoutTest.class);
private static WSServer server;
@BeforeClass
public static void setupServer() throws Exception
{
server = new WSServer(MavenTestingUtils.getTargetTestingPath(IdleTimeoutTest.class.getName()),"app");
server.copyWebInf("idle-timeout-config-web.xml");
// the endpoint (extends javax.websocket.Endpoint)
server.copyClass(OnOpenIdleTimeoutEndpoint.class);
// the configuration that adds the endpoint
server.copyClass(IdleTimeoutContextListener.class);
// the annotated socket
server.copyClass(OnOpenIdleTimeoutSocket.class);
server.start();
WebAppContext webapp = server.createWebAppContext();
server.deployWebapp(webapp);
// wsb.dump();
}
@AfterClass
public static void stopServer()
{
server.stop();
}
private void assertConnectionTimeout(URI uri) throws Exception
{
WebSocketClient client = new WebSocketClient();
try
{
client.start();
JettyEchoSocket clientSocket = new JettyEchoSocket();
Future<Session> clientConnectFuture = client.connect(clientSocket,uri);
// wait for connect
clientConnectFuture.get(1,TimeUnit.SECONDS);
// wait 1 second
TimeUnit.SECONDS.sleep(1);
// Try to write
clientSocket.sendMessage("You shouldn't be there");
// See if remote sent anything (it shouldn't have)
String incomingMessage = clientSocket.messageQueue.poll(1, TimeUnit.SECONDS);
assertThat("Should not have received messages echoed back",incomingMessage,nullValue());
// wait for local close
clientSocket.awaitCloseEvent("Client");
clientSocket.assertCloseInfo("Client", StatusCode.SHUTDOWN, containsString("Idle Timeout"));
}
finally
{
client.stop();
}
}
@Test
public void testAnnotated() throws Exception
{
URI uri = server.getServerBaseURI();
assertConnectionTimeout(uri.resolve("idle-onopen-socket"));
}
@Test
public void testEndpoint() throws Exception
{
URI uri = server.getServerBaseURI();
assertConnectionTimeout(uri.resolve("idle-onopen-endpoint"));
}
}

View File

@ -1,183 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2017 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.jsr356.server;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import java.net.URI;
import java.util.Collection;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import javax.websocket.CloseReason;
import javax.websocket.Endpoint;
import javax.websocket.EndpointConfig;
import javax.websocket.OnMessage;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.websocket.common.WebSocketSession;
import org.eclipse.jetty.websocket.jsr356.ClientContainer;
import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer;
import org.eclipse.jetty.websocket.server.WebSocketServerFactory;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
public class SessionTrackingTest
{
public static class ClientSocket extends Endpoint
{
public Session session;
public CountDownLatch openLatch = new CountDownLatch(1);
public CountDownLatch closeLatch = new CountDownLatch(1);
@Override
public void onOpen(Session session, EndpointConfig config)
{
this.session = session;
openLatch.countDown();
}
@Override
public void onClose(Session session, CloseReason closeReason)
{
closeLatch.countDown();
}
public void waitForOpen(long timeout, TimeUnit unit) throws InterruptedException
{
assertThat("ClientSocket opened",openLatch.await(timeout,unit),is(true));
}
public void waitForClose(long timeout, TimeUnit unit) throws InterruptedException
{
assertThat("ClientSocket opened",closeLatch.await(timeout,unit),is(true));
}
}
@ServerEndpoint("/test")
public static class EchoSocket
{
@OnMessage
public String echo(String msg)
{
return msg;
}
}
private static Server server;
private static WebSocketServerFactory wsServerFactory;
private static URI serverURI;
@BeforeClass
public static void startServer() throws Exception
{
Server server = new Server();
ServerConnector serverConnector = new ServerConnector(server);
serverConnector.setPort(0);
server.addConnector(serverConnector);
ServletContextHandler servletContextHandler = new ServletContextHandler(ServletContextHandler.NO_SESSIONS);
servletContextHandler.setContextPath("/");
server.setHandler(servletContextHandler);
ServerContainer serverContainer = WebSocketServerContainerInitializer.configureContext(servletContextHandler);
serverContainer.addEndpoint(EchoSocket.class);
wsServerFactory = serverContainer.getWebSocketServerFactory();
server.start();
String host = serverConnector.getHost();
if (StringUtil.isBlank(host))
{
host = "localhost";
}
serverURI = new URI("ws://" + host + ":" + serverConnector.getLocalPort());
}
@AfterClass
public static void stopServer() throws Exception
{
if (server == null)
{
return;
}
server.stop();
}
@Test
public void testAddRemoveSessions() throws Exception
{
// Create Client
ClientContainer clientContainer = new ClientContainer();
try
{
clientContainer.start();
// Establish connections
ClientSocket cli1 = new ClientSocket();
clientContainer.connectToServer(cli1,serverURI.resolve("/test"));
cli1.waitForOpen(1,TimeUnit.SECONDS);
// Assert open connections
assertServerOpenConnectionCount(1);
// Establish new connection
ClientSocket cli2 = new ClientSocket();
clientContainer.connectToServer(cli2,serverURI.resolve("/test"));
cli2.waitForOpen(1,TimeUnit.SECONDS);
// Assert open connections
assertServerOpenConnectionCount(2);
// Establish close both connections
cli1.session.close();
cli2.session.close();
cli1.waitForClose(1,TimeUnit.SECONDS);
cli2.waitForClose(1,TimeUnit.SECONDS);
// Assert open connections
assertServerOpenConnectionCount(0);
}
finally
{
clientContainer.stop();
}
}
private void assertServerOpenConnectionCount(int expectedCount)
{
Collection<javax.websocket.Session> sessions = wsServerFactory.getBeans(javax.websocket.Session.class);
int openCount = 0;
for (javax.websocket.Session session : sessions)
{
assertThat("Session.isopen: " + session,session.isOpen(),is(true));
openCount++;
}
assertThat("Open Session Count",openCount,is(expectedCount));
}
}

View File

@ -86,27 +86,29 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Rem
private final Executor executor;
private final AtomicConnectionState connectionState = new AtomicConnectionState();
private final AtomicBoolean closeSent = new AtomicBoolean();
// The websocket endpoint object itself
private final Object endpoint;
// Callbacks
private FrameCallback onDisconnectCallback = new CompletionCallback() {
private FrameCallback onDisconnectCallback = new CompletionCallback()
{
@Override
public void complete()
{
if (connectionState.onClosed())
{
LOG.debug("ConnectionState: Transition to CLOSED");
if (LOG.isDebugEnabled())
LOG.debug("ConnectionState: Transition to CLOSED");
connection.disconnect();
}
}
};
// Endpoint Functions and MessageSinks
protected EndpointFunctions endpointFunctions;
private MessageSink activeMessageSink;
private ClassLoader classLoader;
private ExtensionFactory extensionFactory;
private BatchMode batchmode = BatchMode.AUTO;
@ -124,9 +126,9 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Rem
{
Objects.requireNonNull(containerScope, "Container Scope cannot be null");
Objects.requireNonNull(requestURI, "Request URI cannot be null");
LOG = Log.getLogger(WebSocketSession.class.getName() + "." + connection.getPolicy().getBehavior().name());
this.classLoader = Thread.currentThread().getContextClassLoader();
this.containerScope = containerScope;
this.requestURI = requestURI;
@ -135,7 +137,7 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Rem
this.executor = connection.getExecutor();
this.outgoingHandler = connection;
this.policy = connection.getPolicy();
addBean(this.connection);
}
@ -155,13 +157,13 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Rem
/* This is assumed to always be a NORMAL closure, no reason phrase */
close(StatusCode.NORMAL, null);
}
@Override
public void close(CloseStatus closeStatus)
{
close(closeStatus.getCode(),closeStatus.getPhrase());
close(closeStatus.getCode(), closeStatus.getPhrase());
}
@Override
public void close(int statusCode, String reason)
{
@ -177,19 +179,21 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Rem
{
connectionState.onClosing(); // move to CLOSING state (always)
if(closeSent.compareAndSet(false,true))
if (closeSent.compareAndSet(false, true))
{
LOG.debug("Sending Close Frame");
if (LOG.isDebugEnabled())
LOG.debug("Sending Close Frame");
CloseFrame closeFrame = closeInfo.asFrame();
outgoingHandler.outgoingFrame(closeFrame, callback, BatchMode.OFF);
}
else
{
LOG.debug("Close Frame Previously Sent: ignoring: {} [{}]", closeInfo, callback);
if (LOG.isDebugEnabled())
LOG.debug("Close Frame Previously Sent: ignoring: {} [{}]", closeInfo, callback);
callback.succeed();
}
}
/**
* Harsh disconnect
*/
@ -198,31 +202,31 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Rem
{
connection.disconnect();
}
public void dispatch(Runnable runnable)
{
executor.execute(runnable);
}
@Override
protected void doStart() throws Exception
{
if (LOG.isDebugEnabled())
LOG.debug("starting - {}", this);
Iterator<RemoteEndpointFactory> iter = ServiceLoader.load(RemoteEndpointFactory.class).iterator();
if (iter.hasNext())
remoteEndpointFactory = iter.next();
if (remoteEndpointFactory == null)
remoteEndpointFactory = this;
if (LOG.isDebugEnabled())
LOG.debug("Using RemoteEndpointFactory: {}", remoteEndpointFactory);
this.endpointFunctions = newEndpointFunctions(this.endpoint);
addManaged(this.endpointFunctions);
super.doStart();
connection.setMaxIdleTimeout(this.policy.getIdleTimeout());
@ -232,27 +236,27 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Rem
{
fastFail = pendingError.get();
}
if(fastFail != null)
if (fastFail != null)
onError(fastFail);
}
@Override
protected void doStop() throws Exception
{
if (LOG.isDebugEnabled())
LOG.debug("stopping - {}", this);
try
{
close(StatusCode.SHUTDOWN,"Shutdown");
close(StatusCode.SHUTDOWN, "Shutdown");
}
catch (Throwable t)
catch (Throwable ignore)
{
LOG.debug("During Connection Shutdown",t);
LOG.ignore(ignore);
}
super.doStop();
}
@Override
public void dump(Appendable out, String indent) throws IOException
{
@ -268,7 +272,7 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Rem
out.append(outgoingHandler.toString()).append(System.lineSeparator());
}
}
@Override
public boolean equals(Object obj)
{
@ -298,17 +302,17 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Rem
}
return true;
}
public ByteBufferPool getBufferPool()
{
return this.connection.getBufferPool();
}
public ClassLoader getClassLoader()
{
return this.getClass().getClassLoader();
}
public LogicalConnection getConnection()
{
return connection;
@ -324,17 +328,17 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Rem
{
return this.containerScope;
}
public Executor getExecutor()
{
return executor;
}
public ExtensionFactory getExtensionFactory()
{
return extensionFactory;
}
/**
* The idle timeout in milliseconds
*/
@ -343,43 +347,43 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Rem
{
return connection.getMaxIdleTimeout();
}
private Throwable getInvokedCause(Throwable t)
{
if (t instanceof FunctionCallException)
{
Throwable cause = ((FunctionCallException) t).getInvokedCause();
if(cause != null)
if (cause != null)
return cause;
}
return t;
}
@Override
public InetSocketAddress getLocalAddress()
{
return connection.getLocalAddress();
}
@ManagedAttribute(readonly = true)
public OutgoingFrames getOutgoingHandler()
{
return outgoingHandler;
}
@Override
public WebSocketPolicy getPolicy()
{
return this.policy;
}
@Override
public String getProtocolVersion()
{
return protocolVersion;
}
@Override
public RemoteEndpoint getRemote()
{
@ -387,44 +391,47 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Rem
LOG.debug("{}.getRemote()", this.getClass().getSimpleName());
AtomicConnectionState.State state = connectionState.get();
if ((state == AtomicConnectionState.State.OPEN) || (state == AtomicConnectionState.State.CONNECTED))
{
return remote;
}
throw new WebSocketException("RemoteEndpoint unavailable, current state [" + state + "], expecting [OPEN or CONNECTED]");
String err = String.format("RemoteEndpoint unavailable, current state [%s], expecting [%s or %s]",
state.name(), AtomicConnectionState.State.OPEN.name(), AtomicConnectionState.State.CONNECTED.name());
throw new WebSocketException(err);
}
@Override
public InetSocketAddress getRemoteAddress()
{
return connection.getRemoteAddress();
}
public URI getRequestURI()
{
return requestURI;
}
@Override
public UpgradeRequest getUpgradeRequest()
{
return this.upgradeRequest;
}
@Override
public UpgradeResponse getUpgradeResponse()
{
return this.upgradeResponse;
}
@Override
public WebSocketSession getWebSocketSession()
{
return this;
}
@Override
public int hashCode()
{
@ -440,14 +447,14 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Rem
@Override
public void incomingFrame(Frame frame, FrameCallback callback)
{
try(ThreadClassLoaderScope scope = new ThreadClassLoaderScope(classLoader))
try (ThreadClassLoaderScope scope = new ThreadClassLoaderScope(classLoader))
{
if (connectionState.get() == AtomicConnectionState.State.OPEN)
if (connectionState.get() != AtomicConnectionState.State.CLOSED)
{
// For endpoints that want to see raw frames.
// These are immutable.
endpointFunctions.onFrame(frame);
byte opcode = frame.getOpCode();
switch (opcode)
{
@ -457,13 +464,21 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Rem
if (connectionState.onClosing())
{
LOG.debug("ConnectionState: Transition to CLOSING");
if (LOG.isDebugEnabled())
LOG.debug("ConnectionState: Transition to CLOSING");
CloseFrame closeframe = (CloseFrame) frame;
closeInfo = new CloseInfo(closeframe, true);
}
else if (connectionState.onClosed())
{
if (LOG.isDebugEnabled())
LOG.debug("ConnectionState: Transition to CLOSED");
connection.disconnect();
}
else
{
LOG.debug("ConnectionState: {} - Close Frame Received", connectionState);
if (LOG.isDebugEnabled())
LOG.debug("ConnectionState: {} - Close Frame Received", connectionState);
}
if (closeInfo != null)
@ -474,14 +489,14 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Rem
// let fill/parse continue
callback.succeed();
return;
}
case OpCode.PING:
{
if (LOG.isDebugEnabled())
LOG.debug("PING: {}", BufferUtil.toDetailString(frame.getPayload()));
ByteBuffer pongBuf;
if (frame.hasPayload())
{
@ -493,17 +508,18 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Rem
{
pongBuf = ByteBuffer.allocate(0);
}
endpointFunctions.onPing(frame.getPayload());
callback.succeed();
try
{
getRemote().sendPong(pongBuf);
}
catch (Throwable t)
{
LOG.debug("Unable to send pong", t);
if (LOG.isDebugEnabled())
LOG.debug("Unable to send pong", t);
}
break;
}
@ -511,7 +527,7 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Rem
{
if (LOG.isDebugEnabled())
LOG.debug("PONG: {}", BufferUtil.toDetailString(frame.getPayload()));
endpointFunctions.onPong(frame.getPayload());
callback.succeed();
break;
@ -531,7 +547,7 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Rem
endpointFunctions.onContinuation(frame, callback);
if (activeMessageSink != null)
activeMessageSink.accept(frame, callback);
return;
}
default:
@ -562,7 +578,7 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Rem
{
return this.connectionState.get() == AtomicConnectionState.State.OPEN;
}
@Override
public boolean isSecure()
{
@ -570,19 +586,19 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Rem
{
throw new IllegalStateException("No valid UpgradeRequest yet");
}
URI requestURI = upgradeRequest.getRequestURI();
return "wss".equalsIgnoreCase(requestURI.getScheme());
}
public void notifyClose(int statusCode, String reason)
{
if (LOG.isDebugEnabled())
{
LOG.debug("notifyClose({},{}) [{}]", statusCode, reason, getState());
}
CloseInfo closeInfo = new CloseInfo(statusCode, reason);
endpointFunctions.onClose(closeInfo);
}
@ -590,7 +606,7 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Rem
/**
* Error Event.
* <p>
* Can be seen from Session and Connection.
* Can be seen from Session and Connection.
* </p>
*
* @param t the raw cause
@ -612,10 +628,10 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Rem
if (openFuture != null && !openFuture.isDone())
openFuture.completeExceptionally(cause);
// Forward Errors to User WebSocket Object
endpointFunctions.onError(cause);
if (cause instanceof NotUtf8Exception)
{
close(StatusCode.BAD_PAYLOAD, cause.getMessage(), onDisconnectCallback);
@ -636,7 +652,7 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Rem
{
CloseException ce = (CloseException) cause;
FrameCallback callback = EMPTY;
// Force disconnect for protocol breaking status codes
switch (ce.getStatusCode())
{
@ -645,6 +661,7 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Rem
case StatusCode.BAD_PAYLOAD:
case StatusCode.MESSAGE_TOO_LARGE:
case StatusCode.POLICY_VIOLATION:
case StatusCode.SERVER_ERROR:
{
callback = onDisconnectCallback;
}
@ -655,7 +672,7 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Rem
else
{
LOG.warn("Unhandled Error (closing connection)", cause);
// Exception on end-user WS-Endpoint.
// Fast-fail & close connection with reason.
int statusCode = StatusCode.SERVER_ERROR;
@ -669,6 +686,7 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Rem
/**
* Connection Disconnect Event
*
* @param connection the connection
*/
@Override
@ -688,6 +706,7 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Rem
/**
* Connection Open Event
*
* @param connection the connection
*/
@Override
@ -701,9 +720,9 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Rem
public WebSocketRemoteEndpoint newRemoteEndpoint(LogicalConnection connection, OutgoingFrames outgoingFrames, BatchMode batchMode)
{
return new WebSocketRemoteEndpoint(this,outgoingHandler,getBatchMode());
return new WebSocketRemoteEndpoint(this, outgoingHandler, getBatchMode());
}
/**
* Open/Activate the session
*/
@ -711,53 +730,78 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Rem
{
if (LOG.isDebugEnabled())
LOG.debug("{}.open()", this.getClass().getSimpleName());
if (remote != null)
{
// already opened
return;
}
try (ThreadClassLoaderScope scope = new ThreadClassLoaderScope(classLoader))
{
// Upgrade success
if(connectionState.onConnected())
if (connectionState.onConnected())
{
if (LOG.isDebugEnabled())
LOG.debug("ConnectionState: Transition to CONNECTED");
// Connect remote
remote = remoteEndpointFactory.newRemoteEndpoint(connection, outgoingHandler, getBatchMode());
if (LOG.isDebugEnabled())
LOG.debug("{}.open() remote={}", this.getClass().getSimpleName(), remote);
// Open WebSocket
endpointFunctions.onOpen(this);
// Open connection
if(connectionState.onOpen())
try
{
// notify session listeners
try
// Open WebSocket
endpointFunctions.onOpen(this);
// Open connection
if (connectionState.onOpen())
{
if (LOG.isDebugEnabled())
LOG.debug("{}.onSessionOpened()", containerScope.getClass().getSimpleName());
containerScope.onSessionOpened(this);
LOG.debug("ConnectionState: Transition to OPEN");
// notify session listeners
try
{
if (LOG.isDebugEnabled())
LOG.debug("{}.onSessionOpened()", containerScope.getClass().getSimpleName());
containerScope.onSessionOpened(this);
}
catch (Throwable t)
{
LOG.ignore(t);
}
if (LOG.isDebugEnabled())
{
LOG.debug("open -> {}", dump());
}
if (openFuture != null)
{
openFuture.complete(this);
}
}
catch (Throwable t)
{
LOG.ignore(t);
}
if (LOG.isDebugEnabled())
{
LOG.debug("open -> {}", dump());
}
if (openFuture != null)
{
openFuture.complete(this);
}
connection.fillInterested();
}
catch (Throwable t)
{
endpointFunctions.getLog().warn("Error during OPEN", t);
onError(new CloseException(StatusCode.SERVER_ERROR, t));
}
/* Perform fillInterested outside of onConnected / onOpen.
*
* This is to allow for 2 specific scenarios.
*
* 1) Fast Close
* When an end users WSEndpoint.onOpen() calls
* the Session.close() method.
* This is a state transition of CONNECTING -> CONNECTED -> CLOSING
* 2) Fast Fail
* When an end users WSEndpoint.onOpen() throws an Exception.
*/
connection.fillInterested();
}
else
{
@ -778,17 +822,17 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Rem
onError(t);
}
}
public void setExtensionFactory(ExtensionFactory extensionFactory)
{
this.extensionFactory = extensionFactory;
}
public void setFuture(CompletableFuture<Session> fut)
{
this.openFuture = fut;
}
/**
* Set the timeout in milliseconds
*/
@ -797,12 +841,12 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Rem
{
connection.setMaxIdleTimeout(ms);
}
public void setOutgoingHandler(OutgoingFrames outgoing)
{
this.outgoingHandler = outgoing;
}
public void setUpgradeRequest(UpgradeRequest request)
{
this.upgradeRequest = request;
@ -824,18 +868,18 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Rem
}
}
}
public void setUpgradeResponse(UpgradeResponse response)
{
this.upgradeResponse = response;
}
@Override
public SuspendToken suspend()
{
return connection.suspend();
}
/**
* @return the default (initial) value for the batching mode.
*/
@ -843,7 +887,7 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Rem
{
return this.batchmode;
}
@Override
public String toString()
{
@ -861,7 +905,7 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Rem
sb.append(',').append(getConnection().getClass().getSimpleName());
if (getConnection() instanceof AbstractWebSocketConnection)
{
if(isOpen() && remote != null)
if (isOpen() && remote != null)
{
sb.append(',').append(getRemoteAddress());
if (getPolicy().getBehavior() == WebSocketBehavior.SERVER)
@ -874,11 +918,11 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Rem
sb.append(']');
return sb.toString();
}
public interface Listener
{
void onOpened(WebSocketSession session);
void onClosed(WebSocketSession session);
}
}

View File

@ -79,6 +79,7 @@ public class CommonEndpointFunctions<T extends Session> extends AbstractLifeCycl
protected final WebSocketPolicy policy;
protected final Executor executor;
protected Logger endpointLog;
private T session;
private Function<T, Void> onOpenFunction;
private Function<CloseInfo, Void> onCloseFunction;
@ -513,6 +514,16 @@ public class CommonEndpointFunctions<T extends Session> extends AbstractLifeCycl
return executor;
}
public Logger getLog()
{
if(endpointLog == null)
{
endpointLog = Log.getLogger(endpoint.getClass());
}
return endpointLog;
}
public T getSession()
{
return session;

View File

@ -21,6 +21,7 @@ package org.eclipse.jetty.websocket.common.function;
import java.nio.ByteBuffer;
import org.eclipse.jetty.util.component.LifeCycle;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.websocket.api.FrameCallback;
import org.eclipse.jetty.websocket.api.extensions.Frame;
import org.eclipse.jetty.websocket.common.CloseInfo;
@ -32,6 +33,8 @@ import org.eclipse.jetty.websocket.common.CloseInfo;
*/
public interface EndpointFunctions<T> extends LifeCycle
{
Logger getLog();
void onOpen(T session);
void onClose(CloseInfo close);

View File

@ -435,8 +435,10 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
@Override
public void resume()
{
suspendToken.set(false);
fillAndParse();
if (suspendToken.compareAndSet(true, false))
{
fillAndParse();
}
}
public boolean addListener(LogicalConnection.Listener listener)

View File

@ -50,6 +50,7 @@ public class LocalFuzzer implements AutoCloseable
public final LocalFuzzer.Provider provider;
public final UnitGenerator generator;
public final LocalConnector.LocalEndPoint endPoint;
public final HttpTester.Response upgradeResponse;
public LocalFuzzer(LocalFuzzer.Provider provider) throws Exception
{
@ -68,7 +69,7 @@ public class LocalFuzzer implements AutoCloseable
LOG.debug("Request: {}", upgradeRequest);
ByteBuffer upgradeRequestBytes = BufferUtil.toBuffer(upgradeRequest.toString(), StandardCharsets.UTF_8);
this.endPoint = this.provider.newLocalConnection();
performUpgrade(endPoint, upgradeRequestBytes);
this.upgradeResponse = performUpgrade(endPoint, upgradeRequestBytes);
this.generator = new UnitGenerator(WebSocketPolicy.newClientPolicy());
}
@ -291,6 +292,27 @@ public class LocalFuzzer implements AutoCloseable
endPoint.addInputEOF();
}
/**
* Generate a ByteBuffer for each frame, and submit each to
* {@link org.eclipse.jetty.server.LocalConnector.LocalEndPoint#addInput(ByteBuffer)}
*
* @param frames the list of frames to send
*/
public void sendFrames(WebSocketFrame ... frames)
{
boolean eof = false;
for (WebSocketFrame f : frames)
{
ByteBuffer buffer = generator.generate(f);
endPoint.addInput(buffer);
if (f.getOpCode() == OpCode.CLOSE)
eof = true;
}
if (eof)
endPoint.addInputEOF();
}
/**
* Generate a ByteBuffer for each frame, and submit each to
* {@link org.eclipse.jetty.server.LocalConnector.LocalEndPoint#addInput(ByteBuffer)}

View File

@ -24,6 +24,7 @@ import java.util.Map;
import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.MappedByteBufferPool;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.LocalConnector;
@ -115,6 +116,14 @@ public class LocalServer extends ContainerLifeCycle implements LocalFuzzer.Provi
return new LocalFuzzer(this, requestPath, upgradeRequest);
}
protected Handler createRootHandler(Server server) throws Exception
{
servletContextHandler = new ServletContextHandler(server, "/", true, false);
servletContextHandler.setContextPath("/");
configureServletContextHandler(servletContextHandler);
return servletContextHandler;
}
protected void configureServletContextHandler(ServletContextHandler context) throws Exception
{
/* override to change context handler */
@ -166,10 +175,8 @@ public class LocalServer extends ContainerLifeCycle implements LocalFuzzer.Provi
localConnector = new LocalConnector(server);
server.addConnector(localConnector);
servletContextHandler = new ServletContextHandler(server, "/", true, false);
servletContextHandler.setContextPath("/");
configureServletContextHandler(servletContextHandler);
server.setHandler(servletContextHandler);
Handler rootHandler = createRootHandler(server);
server.setHandler(rootHandler);
// Start Server
addBean(server);

View File

@ -0,0 +1,111 @@
//
// ========================================================================
// Copyright (c) 1995-2017 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.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.security.DigestOutputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.jetty.toolchain.test.Hex;
import org.eclipse.jetty.toolchain.test.IO;
import org.junit.Assert;
/**
* Calculate the sha1sum for various content
*/
public class Sha1Sum
{
private static class NoOpOutputStream extends OutputStream
{
@Override
public void write(byte[] b) throws IOException
{
}
@Override
public void write(byte[] b, int off, int len) throws IOException
{
}
@Override
public void flush() throws IOException
{
}
@Override
public void close() throws IOException
{
}
@Override
public void write(int b) throws IOException
{
}
}
public static String calculate(File file) throws NoSuchAlgorithmException, IOException
{
return calculate(file.toPath());
}
public static String calculate(Path path) throws NoSuchAlgorithmException, IOException
{
MessageDigest digest = MessageDigest.getInstance("SHA1");
try (InputStream in = Files.newInputStream(path,StandardOpenOption.READ);
NoOpOutputStream noop = new NoOpOutputStream();
DigestOutputStream digester = new DigestOutputStream(noop,digest))
{
IO.copy(in,digester);
return Hex.asHex(digest.digest());
}
}
public static String calculate(byte[] buf) throws NoSuchAlgorithmException
{
MessageDigest digest = MessageDigest.getInstance("SHA1");
digest.update(buf);
return Hex.asHex(digest.digest());
}
public static String calculate(byte[] buf, int offset, int len) throws NoSuchAlgorithmException
{
MessageDigest digest = MessageDigest.getInstance("SHA1");
digest.update(buf,offset,len);
return Hex.asHex(digest.digest());
}
public static String loadSha1(File sha1File) throws IOException
{
String contents = IO.readToString(sha1File);
Pattern pat = Pattern.compile("^[0-9A-Fa-f]*");
Matcher mat = pat.matcher(contents);
Assert.assertTrue("Should have found HEX code in SHA1 file: " + sha1File,mat.find());
return mat.group();
}
}

View File

@ -0,0 +1,105 @@
//
// ========================================================================
// Copyright (c) 1995-2017 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.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
import org.eclipse.jetty.websocket.api.BatchMode;
import org.eclipse.jetty.websocket.api.FrameCallback;
import org.eclipse.jetty.websocket.api.WebSocketBehavior;
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
import org.eclipse.jetty.websocket.common.WebSocketFrame;
import org.eclipse.jetty.websocket.common.extensions.ExtensionStack;
import org.eclipse.jetty.websocket.common.extensions.WebSocketExtensionFactory;
import org.eclipse.jetty.websocket.common.scopes.SimpleContainerScope;
public class UnitExtensionStack extends ExtensionStack
{
public static UnitExtensionStack clientBased()
{
return policyBased(new WebSocketPolicy(WebSocketBehavior.CLIENT));
}
public static UnitExtensionStack serverBased()
{
return policyBased(new WebSocketPolicy(WebSocketBehavior.SERVER));
}
private static UnitExtensionStack policyBased(WebSocketPolicy policy)
{
SimpleContainerScope containerScope = new SimpleContainerScope(policy);
WebSocketExtensionFactory extensionFactory = new WebSocketExtensionFactory(containerScope);
return new UnitExtensionStack(extensionFactory);
}
private UnitExtensionStack(WebSocketExtensionFactory extensionFactory)
{
super(extensionFactory);
}
/**
* Process frames
*/
public BlockingQueue<WebSocketFrame> processIncoming(BlockingQueue<WebSocketFrame> framesQueue)
{
BlockingQueue<WebSocketFrame> processed = new LinkedBlockingDeque<>();
setNextIncoming((frame, callback) ->
{
processed.offer(WebSocketFrame.copy(frame));
callback.succeed();
});
FrameCallback callback = new FrameCallback.Adapter();
for (WebSocketFrame frame : framesQueue)
{
incomingFrame(frame, callback);
}
setNextIncoming(null);
return processed;
}
/**
* Process frames as if they are for an outgoing path
*
* @param frames the frames to process
* @return the processed frames (post extension stack)
*/
public List<WebSocketFrame> processOutgoing(List<WebSocketFrame> frames)
{
List<WebSocketFrame> captured = new ArrayList<>();
setNextOutgoing((frame, callback, batchMode) ->
{
captured.add(WebSocketFrame.copy(frame));
callback.succeed();
});
FrameCallback callback = new FrameCallback.Adapter();
for (WebSocketFrame frame : frames)
{
outgoingFrame(frame, callback, BatchMode.OFF);
}
setNextOutgoing(null);
return captured;
}
}

View File

@ -24,20 +24,15 @@ import static org.junit.Assert.assertThat;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Path;
import java.util.Map;
import org.eclipse.jetty.annotations.AnnotationConfiguration;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.MappedByteBufferPool;
import org.eclipse.jetty.plus.webapp.EnvConfiguration;
import org.eclipse.jetty.plus.webapp.PlusConfiguration;
import org.eclipse.jetty.server.LocalConnector;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.toolchain.test.FS;
@ -54,24 +49,18 @@ import org.eclipse.jetty.webapp.MetaInfConfiguration;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.webapp.WebInfConfiguration;
import org.eclipse.jetty.webapp.WebXmlConfiguration;
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
import org.eclipse.jetty.websocket.common.Parser;
/**
* Utility to build out exploded directory WebApps, in the /target/tests/ directory, for testing out servers that use javax.websocket endpoints.
* <p>
* This is particularly useful when the WebSocket endpoints are discovered via the javax.websocket annotation scanning.
*/
public class WSServer implements LocalFuzzer.Provider
public class WSServer extends LocalServer implements LocalFuzzer.Provider
{
private static final Logger LOG = Log.getLogger(WSServer.class);
private final Path contextDir;
private final String contextPath;
private final ByteBufferPool bufferPool = new MappedByteBufferPool();
private Server server;
private URI serverUri;
private ContextHandlerCollection contexts;
private LocalConnector localConnector;
private Path webinf;
private Path classesDir;
@ -182,103 +171,16 @@ public class WSServer implements LocalFuzzer.Provider
}
}
public void dump()
{
server.dumpStdErr();
}
public LocalConnector getLocalConnector()
{
return localConnector;
}
@Override
public Parser newClientParser(Parser.Handler parserHandler)
{
return new Parser(WebSocketPolicy.newClientPolicy(), bufferPool, parserHandler);
}
@Override
public LocalConnector.LocalEndPoint newLocalConnection()
{
return getLocalConnector().connect();
}
public LocalFuzzer newLocalFuzzer() throws Exception
{
return new LocalFuzzer(this);
}
public LocalFuzzer newLocalFuzzer(CharSequence requestPath) throws Exception
{
return new LocalFuzzer(this, requestPath);
}
public LocalFuzzer newLocalFuzzer(CharSequence requestPath, Map<String,String> upgradeRequest) throws Exception
{
return new LocalFuzzer(this, requestPath, upgradeRequest);
}
public URI getServerBaseURI()
{
return serverUri;
}
public Server getServer()
{
return server;
}
public Path getWebAppDir()
{
return this.contextDir;
}
public void start() throws Exception
@Override
protected Handler createRootHandler(Server server) throws Exception
{
server = new Server();
// Main network connector
ServerConnector connector = new ServerConnector(server);
connector.setPort(0);
server.addConnector(connector);
// Add Local Connector
localConnector = new LocalConnector(server);
server.addConnector(localConnector);
HandlerCollection handlers = new HandlerCollection();
contexts = new ContextHandlerCollection();
handlers.addHandler(contexts);
server.setHandler(handlers);
server.start();
String host = connector.getHost();
if (host == null)
{
host = "localhost";
}
int port = connector.getLocalPort();
serverUri = new URI(String.format("ws://%s:%d%s/", host, port, contextPath));
if (LOG.isDebugEnabled())
LOG.debug("Server started on {}", serverUri);
}
public void stop()
{
if (server == null)
{
return;
}
try
{
server.stop();
}
catch (Exception e)
{
e.printStackTrace(System.err);
}
return contexts;
}
}

View File

@ -1,204 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2017 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.server;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertThat;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.URI;
import java.util.List;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import javax.servlet.ServletContext;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.util.DecoratedObjectFactory;
import org.eclipse.jetty.util.Decorator;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.WebSocketAdapter;
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
import org.eclipse.jetty.websocket.client.WebSocketClient;
import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest;
import org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse;
import org.eclipse.jetty.websocket.servlet.WebSocketCreator;
import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
import org.eclipse.jetty.websocket.tests.Defaults;
import org.eclipse.jetty.websocket.tests.SimpleServletServer;
import org.eclipse.jetty.websocket.tests.TrackingEndpoint;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestName;
public class DecoratorsLegacyTest
{
private static class DecoratorsSocket extends WebSocketAdapter
{
private final DecoratedObjectFactory objFactory;
public DecoratorsSocket(DecoratedObjectFactory objFactory)
{
this.objFactory = objFactory;
}
@Override
public void onWebSocketText(String message)
{
StringWriter str = new StringWriter();
PrintWriter out = new PrintWriter(str);
if (objFactory != null)
{
out.printf("Object is a DecoratedObjectFactory%n");
List<Decorator> decorators = objFactory.getDecorators();
out.printf("Decorators.size = [%d]%n", decorators.size());
for (Decorator decorator : decorators)
{
out.printf(" decorator[] = %s%n", decorator.getClass().getName());
}
}
else
{
out.printf("DecoratedObjectFactory is NULL%n");
}
getRemote().sendStringByFuture(str.toString());
}
}
private static class DecoratorsCreator implements WebSocketCreator
{
@Override
public Object createWebSocket(ServletUpgradeRequest req, ServletUpgradeResponse resp)
{
ServletContext servletContext = req.getHttpServletRequest().getServletContext();
DecoratedObjectFactory objFactory = (DecoratedObjectFactory) servletContext.getAttribute(DecoratedObjectFactory.ATTR);
return new DecoratorsSocket(objFactory);
}
}
public static class DecoratorsRequestServlet extends WebSocketServlet
{
private static final long serialVersionUID = 1L;
private final WebSocketCreator creator;
public DecoratorsRequestServlet(WebSocketCreator creator)
{
this.creator = creator;
}
@Override
public void configure(WebSocketServletFactory factory)
{
factory.setCreator(this.creator);
}
}
@SuppressWarnings("deprecation")
private static class DummyLegacyDecorator implements org.eclipse.jetty.servlet.ServletContextHandler.Decorator
{
@Override
public <T> T decorate(T o)
{
return o;
}
@Override
public void destroy(Object o)
{
}
}
private static SimpleServletServer server;
private static DecoratorsCreator decoratorsCreator;
@BeforeClass
public static void startServer() throws Exception
{
decoratorsCreator = new DecoratorsCreator();
server = new SimpleServletServer(new DecoratorsRequestServlet(decoratorsCreator))
{
@SuppressWarnings("deprecation")
@Override
protected void configureServletContextHandler(ServletContextHandler context)
{
context.getObjectFactory().clear();
// Add decorator in the legacy way
context.addDecorator(new DummyLegacyDecorator());
}
};
server.start();
}
@AfterClass
public static void stopServer() throws Exception
{
server.stop();
}
@Rule
public TestName testname = new TestName();
private WebSocketClient client;
@Before
public void startClient() throws Exception
{
client = new WebSocketClient();
client.start();
}
@After
public void stopClient() throws Exception
{
client.stop();
}
@Test
public void testAccessRequestCookies() throws Exception
{
client.setMaxIdleTimeout(TimeUnit.SECONDS.toMillis(1));
URI wsUri = server.getServerUri();
TrackingEndpoint clientSocket = new TrackingEndpoint(testname.getMethodName());
ClientUpgradeRequest upgradeRequest = new ClientUpgradeRequest();
Future<Session> clientConnectFuture = client.connect(clientSocket, wsUri, upgradeRequest);
Session clientSession = clientConnectFuture.get(Defaults.CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
// Request Info
clientSession.getRemote().sendString("info");
// Read message
String incomingMsg = clientSocket.messageQueue.poll(5, TimeUnit.SECONDS);
assertThat("DecoratedObjectFactory", incomingMsg, containsString("Object is a DecoratedObjectFactory"));
assertThat("decorators.size", incomingMsg, containsString("Decorators.size = [1]"));
assertThat("decorator type", incomingMsg, containsString("decorator[] = " + DummyLegacyDecorator.class.getName()));
clientSession.close();
}
}

View File

@ -18,14 +18,16 @@
package org.eclipse.jetty.websocket.tests.server;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertThat;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.Future;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import javax.servlet.ServletContext;
@ -33,29 +35,34 @@ import javax.servlet.ServletContext;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.util.DecoratedObjectFactory;
import org.eclipse.jetty.util.Decorator;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.websocket.api.StatusCode;
import org.eclipse.jetty.websocket.api.WebSocketAdapter;
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
import org.eclipse.jetty.websocket.client.WebSocketClient;
import org.eclipse.jetty.websocket.common.CloseInfo;
import org.eclipse.jetty.websocket.common.OpCode;
import org.eclipse.jetty.websocket.common.WebSocketFrame;
import org.eclipse.jetty.websocket.common.frames.TextFrame;
import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest;
import org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse;
import org.eclipse.jetty.websocket.servlet.WebSocketCreator;
import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
import org.eclipse.jetty.websocket.tests.Defaults;
import org.eclipse.jetty.websocket.tests.LocalFuzzer;
import org.eclipse.jetty.websocket.tests.SimpleServletServer;
import org.eclipse.jetty.websocket.tests.TrackingEndpoint;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestName;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@Ignore
/**
* Test the {@link Decorator} features of the WebSocketServer
*/
@RunWith(Parameterized.class)
public class DecoratorsTest
{
private static final Logger LOG = Log.getLogger(DecoratorsTest.class);
private static class DecoratorsSocket extends WebSocketAdapter
{
private final DecoratedObjectFactory objFactory;
@ -85,6 +92,8 @@ public class DecoratorsTest
{
out.printf("DecoratedObjectFactory is NULL%n");
}
LOG.debug(out.toString());
getRemote().sendStringByFuture(str.toString());
}
@ -131,73 +140,100 @@ public class DecoratorsTest
{
}
}
private static SimpleServletServer server;
private static DecoratorsCreator decoratorsCreator;
@BeforeClass
public static void startServer() throws Exception
@SuppressWarnings("deprecation")
private static class DummyLegacyDecorator implements org.eclipse.jetty.servlet.ServletContextHandler.Decorator
{
decoratorsCreator = new DecoratorsCreator();
server = new SimpleServletServer(new DecoratorsRequestServlet(decoratorsCreator))
@Override
public <T> T decorate(T o)
{
return o;
}
@Override
public void destroy(Object o)
{
}
}
private interface Case
{
void customize(ServletContextHandler context);
}
@SuppressWarnings("deprecation")
@Parameterized.Parameters(name = "{0}")
public static Collection<Object[]> data()
{
List<Object[]> cases = new ArrayList<>();
cases.add(new Object[] {
"Legacy Usage",
(Case) (context) -> {
context.getObjectFactory().clear();
// Add decorator in the legacy way
context.addDecorator(new DummyLegacyDecorator());
},
DummyLegacyDecorator.class
});
cases.add(new Object[] {
"Recommended Usage",
(Case) (context) -> {
// Add decorator in the new util way
context.getObjectFactory().clear();
context.getObjectFactory().addDecorator(new DummyUtilDecorator());
},
DummyUtilDecorator.class
});
return cases;
}
private SimpleServletServer server;
private Class<?> expectedDecoratorClass;
public DecoratorsTest(String testId, Case testcase, Class<?> expectedDecoratorClass) throws Exception
{
LOG.debug("Testing {}", testId);
this.expectedDecoratorClass = expectedDecoratorClass;
server = new SimpleServletServer(new DecoratorsRequestServlet(new DecoratorsCreator()))
{
@Override
protected void configureServletContextHandler(ServletContextHandler context)
{
// Add decorator in the new util way
context.getObjectFactory().clear();
context.getObjectFactory().addDecorator(new DummyUtilDecorator());
super.configureServletContextHandler(context);
testcase.customize(context);
}
};
server.start();
}
@AfterClass
public static void stopServer() throws Exception
@After
public void stopServer() throws Exception
{
server.stop();
}
@Rule
public TestName testname = new TestName();
private WebSocketClient client;
@Before
public void startClient() throws Exception
{
client = new WebSocketClient();
client.start();
}
@After
public void stopClient() throws Exception
{
client.stop();
}
@Test
public void testAccessRequestCookies() throws Exception
{
client.setMaxIdleTimeout(TimeUnit.SECONDS.toMillis(1));
URI wsUri = server.getServerUri();
TrackingEndpoint clientSocket = new TrackingEndpoint(testname.getMethodName());
ClientUpgradeRequest upgradeRequest = new ClientUpgradeRequest();
Future<Session> clientConnectFuture = client.connect(clientSocket, wsUri, upgradeRequest);
Session clientSession = clientConnectFuture.get(Defaults.CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
// Request Info
clientSession.getRemote().sendString("info");
// Read message
String incomingMsg = clientSocket.messageQueue.poll(5, TimeUnit.SECONDS);
assertThat("DecoratedObjectFactory", incomingMsg, containsString("Object is a DecoratedObjectFactory"));
assertThat("decorators.size", incomingMsg, containsString("Decorators.size = [1]"));
assertThat("decorator type", incomingMsg, containsString("decorator[] = " + DummyUtilDecorator.class.getName()));
clientSession.close();
try (LocalFuzzer session = server.newLocalFuzzer("/"))
{
session.sendFrames(
new TextFrame().setPayload("info"),
new CloseInfo(StatusCode.NORMAL).asFrame()
);
BlockingQueue<WebSocketFrame> framesQueue = session.getOutputFrames();
WebSocketFrame frame = framesQueue.poll(1, TimeUnit.SECONDS);
assertThat("Frame.opCode", frame.getOpCode(), is(OpCode.TEXT));
String payload = frame.getPayloadAsUTF8();
assertThat("Text - DecoratedObjectFactory", payload, containsString("Object is a DecoratedObjectFactory"));
assertThat("Text - decorators.size", payload, containsString("Decorators.size = [1]"));
assertThat("Text - decorator type", payload, containsString("decorator[] = " + this.expectedDecoratorClass.getName()));
}
}
}

View File

@ -18,92 +18,41 @@
package org.eclipse.jetty.websocket.tests.server;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.Map;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig;
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
import org.eclipse.jetty.websocket.client.WebSocketClient;
import org.eclipse.jetty.websocket.tests.Defaults;
import org.eclipse.jetty.websocket.tests.SimpleServletServer;
import org.eclipse.jetty.websocket.tests.TrackingEndpoint;
import org.eclipse.jetty.websocket.tests.servlets.EchoServlet;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.eclipse.jetty.websocket.api.StatusCode;
import org.eclipse.jetty.websocket.common.CloseInfo;
import org.eclipse.jetty.websocket.common.WebSocketFrame;
import org.eclipse.jetty.websocket.common.frames.TextFrame;
import org.eclipse.jetty.websocket.tests.LocalFuzzer;
import org.eclipse.jetty.websocket.tests.UpgradeUtils;
import org.junit.Test;
import org.junit.rules.TestName;
public class FirefoxTest
public class FirefoxTest extends AbstractLocalServerCase
{
private static SimpleServletServer server;
@BeforeClass
public static void startServer() throws Exception
{
server = new SimpleServletServer(new EchoServlet());
server.start();
}
@AfterClass
public static void stopServer() throws Exception
{
server.stop();
}
@Rule
public TestName testname = new TestName();
private WebSocketClient client;
@Before
public void startClient() throws Exception
{
client = new WebSocketClient();
client.start();
}
@After
public void stopClient() throws Exception
{
client.stop();
}
@Test
public void testConnectionKeepAlive() throws Exception
{
URI wsUri = server.getServerUri();
TrackingEndpoint clientSocket = new TrackingEndpoint(testname.getMethodName());
ClientUpgradeRequest upgradeRequest = new ClientUpgradeRequest();
// Odd Connection Header value seen in Firefox
upgradeRequest.setHeader("Connection", "keep-alive, Upgrade");
Future<Session> clientConnectFuture = client.connect(clientSocket, wsUri, upgradeRequest);
Session clientSession = clientConnectFuture.get(Defaults.CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
List<ExtensionConfig> extensionConfigList = clientSession.getUpgradeResponse().getExtensions();
assertThat("Client Upgrade Response.Extensions", extensionConfigList.size(), is(1));
assertThat("Client Upgrade Response.Extensions[0]", extensionConfigList.get(0).toString(), containsString("x-webkit-deflate-frame"));
// Message
String msg = "this is an echo ... cho ... ho ... o";
clientSession.getRemote().sendString(msg);
List<WebSocketFrame> send = new ArrayList<>();
send.add(new TextFrame().setPayload(msg));
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
// Read message
String incomingMsg = clientSocket.messageQueue.poll(5, TimeUnit.SECONDS);
Assert.assertThat("Incoming Message", incomingMsg, is(msg));
List<WebSocketFrame> expect = new ArrayList<>();
expect.add(new TextFrame().setPayload(msg));
expect.add(new CloseInfo(StatusCode.NORMAL).asFrame());
clientSession.close();
Map<String,String> upgradeHeaders = UpgradeUtils.newDefaultUpgradeRequestHeaders();
// Odd Connection Header value seen in Firefox
upgradeHeaders.put("Connection", "keep-alive, Upgrade");
try (LocalFuzzer session = server.newLocalFuzzer("/", upgradeHeaders))
{
session.sendBulk(send);
session.expect(expect);
}
}
}

View File

@ -20,31 +20,31 @@ package org.eclipse.jetty.websocket.tests.server;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.junit.Assert.assertThat;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.StatusCode;
import org.eclipse.jetty.websocket.api.WebSocketConstants;
import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig;
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
import org.eclipse.jetty.websocket.client.WebSocketClient;
import org.eclipse.jetty.websocket.api.extensions.ExtensionFactory;
import org.eclipse.jetty.websocket.common.CloseInfo;
import org.eclipse.jetty.websocket.common.WebSocketFrame;
import org.eclipse.jetty.websocket.tests.Defaults;
import org.eclipse.jetty.websocket.common.frames.TextFrame;
import org.eclipse.jetty.websocket.tests.LocalFuzzer;
import org.eclipse.jetty.websocket.tests.SimpleServletServer;
import org.eclipse.jetty.websocket.tests.TrackingEndpoint;
import org.eclipse.jetty.websocket.tests.UnitExtensionStack;
import org.eclipse.jetty.websocket.tests.UpgradeUtils;
import org.eclipse.jetty.websocket.tests.servlets.EchoServlet;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestName;
public class FragmentExtensionTest
{
@ -63,24 +63,6 @@ public class FragmentExtensionTest
server.stop();
}
@Rule
public TestName testname = new TestName();
private WebSocketClient client;
@Before
public void startClient() throws Exception
{
client = new WebSocketClient();
client.start();
}
@After
public void stopClient() throws Exception
{
client.stop();
}
private String[] split(String str, int partSize)
{
int strLength = str.length();
@ -98,36 +80,41 @@ public class FragmentExtensionTest
@Test
public void testFragmentExtension() throws Exception
{
Assume.assumeTrue("Server has fragment registered",
server.getWebSocketServletFactory().getExtensionFactory().isAvailable("fragment"));
ExtensionFactory extensionFactory = server.getWebSocketServletFactory().getExtensionFactory();
assertThat("Extension Factory", extensionFactory, notNullValue());
Assume.assumeTrue("Server has fragment registered", extensionFactory.isAvailable("fragment"));
int fragSize = 4;
URI wsUri = server.getServerUri();
TrackingEndpoint clientSocket = new TrackingEndpoint(testname.getMethodName());
ClientUpgradeRequest upgradeRequest = new ClientUpgradeRequest();
upgradeRequest.addExtensions("fragment;maxLength=" + fragSize);
upgradeRequest.setSubProtocols("onConnect");
Future<Session> clientConnectFuture = client.connect(clientSocket, wsUri, upgradeRequest);
Session clientSession = clientConnectFuture.get(Defaults.CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
List<ExtensionConfig> extensionConfigList = clientSession.getUpgradeResponse().getExtensions();
assertThat("Client Upgrade Response.Extensions", extensionConfigList.size(), is(1));
assertThat("Client Upgrade Response.Extensions[0]", extensionConfigList.get(0).toString(), containsString("fragment"));
// Message
String msg = "Sent as a long message that should be split";
clientSession.getRemote().sendString(msg);
// Read message
String parts[] = split(msg, fragSize);
for (int i = 0; i < parts.length; i++)
List<WebSocketFrame> send = new ArrayList<>();
send.add(new TextFrame().setPayload(msg));
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
Map<String,String> upgradeHeaders = UpgradeUtils.newDefaultUpgradeRequestHeaders();
upgradeHeaders.put(WebSocketConstants.SEC_WEBSOCKET_EXTENSIONS, "fragment;maxLength=" + fragSize);
try (LocalFuzzer session = server.newLocalFuzzer("/", upgradeHeaders))
{
WebSocketFrame frame = clientSocket.framesQueue.poll();
Assert.assertThat("text[" + i + "].payload", frame.getPayloadAsUTF8(), is(parts[i]));
String negotiatedExtensions = session.upgradeResponse.get(WebSocketConstants.SEC_WEBSOCKET_EXTENSIONS);
List<ExtensionConfig> extensionConfigList = ExtensionConfig.parseList(negotiatedExtensions);
assertThat("Client Upgrade Response.Extensions", extensionConfigList.size(), is(1));
assertThat("Client Upgrade Response.Extensions[0]", extensionConfigList.get(0).toString(), containsString("fragment"));
UnitExtensionStack extensionStack = UnitExtensionStack.clientBased();
List<WebSocketFrame> outgoingFrames = extensionStack.processOutgoing(send);
session.sendBulk(outgoingFrames);
BlockingQueue<WebSocketFrame> framesQueue = session.getOutputFrames();
BlockingQueue<WebSocketFrame> incomingFrames = extensionStack.processIncoming(framesQueue);
String parts[] = split(msg, fragSize);
for (int i = 0; i < parts.length; i++)
{
WebSocketFrame frame = incomingFrames.poll();
Assert.assertThat("text[" + i + "].payload", frame.getPayloadAsUTF8(), is(parts[i]));
}
}
clientSession.close();
}
}

View File

@ -20,94 +20,82 @@ package org.eclipse.jetty.websocket.tests.server;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.junit.Assert.assertThat;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.StatusCode;
import org.eclipse.jetty.websocket.api.WebSocketConstants;
import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig;
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
import org.eclipse.jetty.websocket.client.WebSocketClient;
import org.eclipse.jetty.websocket.tests.Defaults;
import org.eclipse.jetty.websocket.api.extensions.ExtensionFactory;
import org.eclipse.jetty.websocket.common.CloseInfo;
import org.eclipse.jetty.websocket.common.OpCode;
import org.eclipse.jetty.websocket.common.WebSocketFrame;
import org.eclipse.jetty.websocket.common.frames.TextFrame;
import org.eclipse.jetty.websocket.tests.LocalFuzzer;
import org.eclipse.jetty.websocket.tests.SimpleServletServer;
import org.eclipse.jetty.websocket.tests.TrackingEndpoint;
import org.eclipse.jetty.websocket.tests.UnitExtensionStack;
import org.eclipse.jetty.websocket.tests.UpgradeUtils;
import org.eclipse.jetty.websocket.tests.servlets.EchoServlet;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestName;
public class IdentityExtensionTest
{
private static SimpleServletServer server;
@BeforeClass
public static void startServer() throws Exception
{
server = new SimpleServletServer(new EchoServlet());
server.start();
}
@AfterClass
public static void stopServer() throws Exception
{
server.stop();
}
@Rule
public TestName testname = new TestName();
private WebSocketClient client;
@Before
public void startClient() throws Exception
{
client = new WebSocketClient();
client.start();
}
@After
public void stopClient() throws Exception
{
client.stop();
}
@Test(timeout = 60000)
public void testIdentityExtension() throws Exception
{
Assume.assumeTrue("Server has identity extension registered",
server.getWebSocketServletFactory().getExtensionFactory().isAvailable("identity"));
URI wsUri = server.getServerUri();
TrackingEndpoint clientSocket = new TrackingEndpoint(testname.getMethodName());
ClientUpgradeRequest upgradeRequest = new ClientUpgradeRequest();
upgradeRequest.addExtensions("identity;param=0");
upgradeRequest.addExtensions("identity;param=1, identity ; param = '2' ; other = ' some = value '");
upgradeRequest.setSubProtocols("onConnect");
Future<Session> clientConnectFuture = client.connect(clientSocket, wsUri, upgradeRequest);
Session clientSession = clientConnectFuture.get(Defaults.CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
List<ExtensionConfig> extensionConfigList = clientSession.getUpgradeResponse().getExtensions();
assertThat("Client Upgrade Response.Extensions", extensionConfigList.size(), is(3));
assertThat("Client Upgrade Response.Extensions[0]", extensionConfigList.get(0).toString(), containsString("identity"));
// Message
String msg = "Hello Identity";
clientSession.getRemote().sendString(msg);
// Read message
String incomingMsg = clientSocket.messageQueue.poll(5, TimeUnit.SECONDS);
Assert.assertThat("Incoming Message", incomingMsg, is(msg));
clientSession.close();
ExtensionFactory extensionFactory = server.getWebSocketServletFactory().getExtensionFactory();
assertThat("Extension Factory", extensionFactory, notNullValue());
Assume.assumeTrue("Server has identity registered", extensionFactory.isAvailable("identity"));
List<WebSocketFrame> send = new ArrayList<>();
send.add(new TextFrame().setPayload("Hello Identity"));
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
Map<String, String> upgradeHeaders = UpgradeUtils.newDefaultUpgradeRequestHeaders();
upgradeHeaders.put(WebSocketConstants.SEC_WEBSOCKET_EXTENSIONS, "identity;param=0, identity;param=1, identity ; param = '2' ; other = ' some = value '");
try (LocalFuzzer session = server.newLocalFuzzer("/", upgradeHeaders))
{
String negotiatedExtensions = session.upgradeResponse.get(WebSocketConstants.SEC_WEBSOCKET_EXTENSIONS);
List<ExtensionConfig> extensionConfigList = ExtensionConfig.parseList(negotiatedExtensions);
assertThat("Client Upgrade Response.Extensions", extensionConfigList.size(), is(3));
assertThat("Client Upgrade Response.Extensions[0]", extensionConfigList.get(0).toString(), containsString("identity"));
UnitExtensionStack extensionStack = UnitExtensionStack.clientBased();
List<WebSocketFrame> outgoingFrames = extensionStack.processOutgoing(send);
session.sendBulk(outgoingFrames);
BlockingQueue<WebSocketFrame> framesQueue = session.getOutputFrames();
BlockingQueue<WebSocketFrame> incomingFrames = extensionStack.processIncoming(framesQueue);
WebSocketFrame frame = incomingFrames.poll();
Assert.assertThat("Frame.opCode", frame.getOpCode(), is(OpCode.TEXT));
Assert.assertThat("Frame.text-payload", frame.getPayloadAsUTF8(), is("Hello Identity"));
}
}
}

View File

@ -18,25 +18,24 @@
package org.eclipse.jetty.websocket.tests.server;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertThat;
import java.net.URI;
import java.util.concurrent.Future;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.StatusCode;
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
import org.eclipse.jetty.websocket.client.WebSocketClient;
import org.eclipse.jetty.websocket.common.CloseInfo;
import org.eclipse.jetty.websocket.common.OpCode;
import org.eclipse.jetty.websocket.common.WebSocketFrame;
import org.eclipse.jetty.websocket.common.frames.TextFrame;
import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
import org.eclipse.jetty.websocket.tests.Defaults;
import org.eclipse.jetty.websocket.tests.LocalFuzzer;
import org.eclipse.jetty.websocket.tests.SimpleServletServer;
import org.eclipse.jetty.websocket.tests.TrackingEndpoint;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
@ -45,7 +44,7 @@ import org.junit.rules.TestName;
public class IdleTimeoutTest
{
@WebSocket(maxIdleTime = 500)
public static class FastTimeoutRFCSocket extends RFC6455Socket
public static class FastTimeoutSocket
{
}
@ -55,11 +54,14 @@ public class IdleTimeoutTest
@Override
public void configure(WebSocketServletFactory factory)
{
factory.register(FastTimeoutRFCSocket.class);
factory.register(FastTimeoutSocket.class);
}
}
private static SimpleServletServer server;
protected static SimpleServletServer server;
@Rule
public TestName testname = new TestName();
@BeforeClass
public static void startServer() throws Exception
@ -74,24 +76,6 @@ public class IdleTimeoutTest
server.stop();
}
@Rule
public TestName testname = new TestName();
private WebSocketClient client;
@Before
public void startClient() throws Exception
{
client = new WebSocketClient();
client.start();
}
@After
public void stopClient() throws Exception
{
client.stop();
}
/**
* Test IdleTimeout on server.
*
@ -100,32 +84,19 @@ public class IdleTimeoutTest
@Test
public void testIdleTimeout() throws Exception
{
client.setMaxIdleTimeout(2500);
URI wsUri = server.getServerUri();
TrackingEndpoint clientSocket = new TrackingEndpoint(testname.getMethodName());
ClientUpgradeRequest upgradeRequest = new ClientUpgradeRequest();
upgradeRequest.setSubProtocols("onConnect");
Future<Session> clientConnectFuture = client.connect(clientSocket, wsUri, upgradeRequest);
Session clientSession = clientConnectFuture.get(Defaults.CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
// This wait should be shorter than client timeout above, but
// longer than server timeout configured in FastTimeoutRFCSocket
// eg: websocket server endpoint timeout < this timeout < websocket client idle timeout
TimeUnit.MILLISECONDS.sleep(1000);
// Write to server
// This action is possible, but does nothing.
// Server could be in a half-closed state at this point.
// Where the server read is closed (due to timeout), but the server write is still open.
// The server could not read this frame, if it is in this half closed state
clientSession.getRemote().sendString("Hello");
// Expect closure, as server should have timed out
clientSocket.awaitCloseEvent("Client");
clientSocket.assertCloseInfo("Client", StatusCode.SHUTDOWN, containsString("Timeout"));
clientSession.close();
try (LocalFuzzer session = server.newLocalFuzzer())
{
// wait 1 second to allow timeout to fire off
TimeUnit.SECONDS.sleep(1);
session.sendFrames(new TextFrame().setPayload("You shouldn't be there"));
BlockingQueue<WebSocketFrame> framesQueue = session.getOutputFrames();
WebSocketFrame frame = framesQueue.poll(1, TimeUnit.SECONDS);
assertThat("Frame.opCode", frame.getOpCode(), is(OpCode.CLOSE));
CloseInfo closeInfo = new CloseInfo(frame);
assertThat("Close.statusCode", closeInfo.getStatusCode(), is(StatusCode.SHUTDOWN));
assertThat("Close.reason", closeInfo.getReason(), containsString("Timeout"));
}
}
}

View File

@ -1,105 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2017 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.server;
import static org.hamcrest.Matchers.anyOf;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import java.net.HttpCookie;
import java.net.URI;
import java.util.List;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
import org.eclipse.jetty.websocket.client.WebSocketClient;
import org.eclipse.jetty.websocket.tests.Defaults;
import org.eclipse.jetty.websocket.tests.SimpleServletServer;
import org.eclipse.jetty.websocket.tests.TrackingEndpoint;
import org.eclipse.jetty.websocket.tests.servlets.EchoServlet;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestName;
public class RequestHeadersTest
{
private static SimpleServletServer server;
@BeforeClass
public static void startServer() throws Exception
{
server = new SimpleServletServer(new EchoServlet());
server.start();
}
@AfterClass
public static void stopServer() throws Exception
{
server.stop();
}
@Rule
public TestName testname = new TestName();
private WebSocketClient client;
@Before
public void startClient() throws Exception
{
client = new WebSocketClient();
client.start();
}
@After
public void stopClient() throws Exception
{
client.stop();
}
@Test
public void testAccessRequestCookies() throws Exception
{
URI wsUri = server.getServerUri();
client.setMaxIdleTimeout(1000);
TrackingEndpoint clientSocket = new TrackingEndpoint(testname.getMethodName());
ClientUpgradeRequest upgradeRequest = new ClientUpgradeRequest();
upgradeRequest.setHeader("Cookie", "fruit=Pear; type=Anjou");
Future<Session> clientConnectFuture = client.connect(clientSocket, wsUri, upgradeRequest);
Session clientSession = clientConnectFuture.get(Defaults.CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
List<HttpCookie> cookies = clientSession.getUpgradeRequest().getCookies();
Assert.assertThat("Request cookies", cookies, notNullValue());
Assert.assertThat("Request cookies.size", cookies.size(), is(2));
for (HttpCookie cookie : cookies)
{
Assert.assertThat("Cookie name", cookie.getName(), anyOf(is("fruit"), is("type")));
Assert.assertThat("Cookie value", cookie.getValue(), anyOf(is("Pear"), is("Anjou")));
}
clientSession.close();
}
}

View File

@ -18,11 +18,8 @@
package org.eclipse.jetty.websocket.tests.server;
import static org.hamcrest.Matchers.is;
import java.net.URI;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.SuspendToken;
@ -30,24 +27,20 @@ import org.eclipse.jetty.websocket.api.WriteCallback;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
import org.eclipse.jetty.websocket.client.WebSocketClient;
import org.eclipse.jetty.websocket.common.WebSocketFrame;
import org.eclipse.jetty.websocket.common.frames.CloseFrame;
import org.eclipse.jetty.websocket.common.frames.TextFrame;
import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest;
import org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse;
import org.eclipse.jetty.websocket.servlet.WebSocketCreator;
import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
import org.eclipse.jetty.websocket.tests.Defaults;
import org.eclipse.jetty.websocket.tests.LocalFuzzer;
import org.eclipse.jetty.websocket.tests.SimpleServletServer;
import org.eclipse.jetty.websocket.tests.TrackingEndpoint;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestName;
public class SuspendResumeTest
{
@ -69,7 +62,6 @@ public class SuspendResumeTest
this.session.getRemote().sendString(message,
new WriteCallback()
{
@Override
public void writeSuccess()
{
@ -94,7 +86,7 @@ public class SuspendResumeTest
}
}
public static class EchoServlet extends WebSocketServlet
public static class BackPressureServlet extends WebSocketServlet
{
private static final long serialVersionUID = 1L;
@ -110,7 +102,7 @@ public class SuspendResumeTest
@BeforeClass
public static void startServer() throws Exception
{
server = new SimpleServletServer(new EchoServlet());
server = new SimpleServletServer(new BackPressureServlet());
server.start();
}
@ -120,46 +112,43 @@ public class SuspendResumeTest
server.stop();
}
@Rule
public TestName testname = new TestName();
private WebSocketClient client;
@Before
public void startClient() throws Exception
{
client = new WebSocketClient();
client.start();
}
@After
public void stopClient() throws Exception
{
client.stop();
}
@Test
public void testSuspendResume() throws Exception
{
URI wsUri = server.getServerUri();
List<WebSocketFrame> send = new ArrayList<>();
send.add(new TextFrame().setPayload("echo1"));
send.add(new TextFrame().setPayload("echo2"));
send.add(new CloseFrame());
TrackingEndpoint clientSocket = new TrackingEndpoint(testname.getMethodName());
ClientUpgradeRequest upgradeRequest = new ClientUpgradeRequest();
Future<Session> clientConnectFuture = client.connect(clientSocket, wsUri, upgradeRequest);
List<WebSocketFrame> expect = new ArrayList<>();
expect.add(new TextFrame().setPayload("echo1"));
expect.add(new TextFrame().setPayload("echo2"));
expect.add(new CloseFrame());
Session clientSession = clientConnectFuture.get(Defaults.CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
try (LocalFuzzer session = server.newLocalFuzzer())
{
session.sendBulk(send);
session.expect(expect);
}
}
@Test
public void testSuspendResume_SmallBuffers() throws Exception
{
List<WebSocketFrame> send = new ArrayList<>();
send.add(new TextFrame().setPayload("echo1"));
send.add(new TextFrame().setPayload("echo2"));
send.add(new CloseFrame());
// Message
clientSession.getRemote().sendString("echo1");
clientSession.getRemote().sendString("echo2");
List<WebSocketFrame> expect = new ArrayList<>();
expect.add(new TextFrame().setPayload("echo1"));
expect.add(new TextFrame().setPayload("echo2"));
expect.add(new CloseFrame());
// Read message
String incomingMsg;
incomingMsg = clientSocket.messageQueue.poll(5, TimeUnit.SECONDS);
Assert.assertThat("Incoming Message 1", incomingMsg, is("echo1"));
incomingMsg = clientSocket.messageQueue.poll(5, TimeUnit.SECONDS);
Assert.assertThat("Incoming Message 2", incomingMsg, is("echo2"));
clientSession.close();
try (LocalFuzzer session = server.newLocalFuzzer())
{
session.sendSegmented(send, 2);
session.expect(expect);
}
}
}

View File

@ -18,42 +18,43 @@
package org.eclipse.jetty.websocket.tests.server;
import static org.hamcrest.Matchers.anything;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertThat;
import java.net.URI;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Future;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.log.StacklessLogging;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.StatusCode;
import org.eclipse.jetty.websocket.api.WebSocketAdapter;
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
import org.eclipse.jetty.websocket.client.WebSocketClient;
import org.eclipse.jetty.websocket.api.WebSocketConstants;
import org.eclipse.jetty.websocket.common.CloseInfo;
import org.eclipse.jetty.websocket.common.OpCode;
import org.eclipse.jetty.websocket.common.WebSocketFrame;
import org.eclipse.jetty.websocket.common.WebSocketSession;
import org.eclipse.jetty.websocket.common.frames.TextFrame;
import org.eclipse.jetty.websocket.server.WebSocketServerFactory;
import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest;
import org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse;
import org.eclipse.jetty.websocket.servlet.WebSocketCreator;
import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
import org.eclipse.jetty.websocket.tests.Defaults;
import org.eclipse.jetty.websocket.tests.LocalFuzzer;
import org.eclipse.jetty.websocket.tests.SimpleServletServer;
import org.eclipse.jetty.websocket.tests.TrackingEndpoint;
import org.eclipse.jetty.websocket.tests.UpgradeUtils;
import org.hamcrest.Matchers;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestName;
/**
* Tests various close scenarios
@ -61,310 +62,254 @@ import org.junit.rules.TestName;
@Ignore
public class WebSocketCloseTest
{
static class AbstractCloseSocket extends WebSocketAdapter
/**
* On Message, return container information
*/
public static class ContainerSocket extends WebSocketAdapter
{
public CountDownLatch closeLatch = new CountDownLatch(1);
public String closeReason = null;
public int closeStatusCode = -1;
public List<Throwable> errors = new ArrayList<>();
@Override
public void onWebSocketClose(int statusCode, String reason)
private static final Logger LOG = Log.getLogger(WebSocketCloseTest.ContainerSocket.class);
private final WebSocketServerFactory container;
private Session session;
public ContainerSocket(WebSocketServerFactory container)
{
LOG.debug("onWebSocketClose({}, {})",statusCode,reason);
this.closeStatusCode = statusCode;
this.closeReason = reason;
closeLatch.countDown();
this.container = container;
}
@Override
public void onWebSocketError(Throwable cause)
public void onWebSocketText(String message)
{
errors.add(cause);
LOG.debug("onWebSocketText({})", message);
if (message.equalsIgnoreCase("openSessions"))
{
try
{
Collection<WebSocketSession> sessions = container.getOpenSessions();
StringBuilder ret = new StringBuilder();
ret.append("openSessions.size=").append(sessions.size()).append('\n');
int idx = 0;
for (WebSocketSession sess : sessions)
{
ret.append('[').append(idx++).append("] ").append(sess.toString()).append('\n');
}
session.getRemote().sendString(ret.toString());
}
catch (IOException e)
{
LOG.warn(e);
}
}
session.close(StatusCode.NORMAL, "ContainerSocket");
}
@Override
public void onWebSocketConnect(Session sess)
{
LOG.debug("onWebSocketConnect({})", sess);
this.session = sess;
}
}
@SuppressWarnings("serial")
/**
* On Connect, close socket
*/
public static class FastCloseSocket extends WebSocketAdapter
{
private static final Logger LOG = Log.getLogger(WebSocketCloseTest.FastCloseSocket.class);
@Override
public void onWebSocketConnect(Session sess)
{
LOG.debug("onWebSocketConnect({})", sess);
sess.close(StatusCode.NORMAL, "FastCloseServer");
}
}
/**
* On Connect, throw unhandled exception
*/
public static class FastFailSocket extends WebSocketAdapter
{
private static final Logger LOG = Log.getLogger(WebSocketCloseTest.FastFailSocket.class);
@Override
public void onWebSocketConnect(Session sess)
{
LOG.debug("onWebSocketConnect({})", sess);
// Test failure due to unhandled exception
// this should trigger a fast-fail closure during open/connect
throw new RuntimeException("Intentional FastFail");
}
}
/**
* On Message, drop connection
*/
public static class DropServerConnectionSocket extends WebSocketAdapter
{
@Override
public void onWebSocketText(String message)
{
try
{
getSession().disconnect();
}
catch (IOException ignore)
{
}
}
}
public static class CloseServlet extends WebSocketServlet implements WebSocketCreator
{
private WebSocketServerFactory serverFactory;
@Override
public void configure(WebSocketServletFactory factory)
{
factory.setCreator(this);
if (factory instanceof WebSocketServerFactory)
{
this.serverFactory = (WebSocketServerFactory)factory;
this.serverFactory = (WebSocketServerFactory) factory;
}
}
@Override
public Object createWebSocket(ServletUpgradeRequest req, ServletUpgradeResponse resp)
{
if (req.hasSubProtocol("fastclose"))
{
closeSocket = new FastCloseSocket();
return closeSocket;
return new FastCloseSocket();
}
if (req.hasSubProtocol("fastfail"))
{
closeSocket = new FastFailSocket();
return closeSocket;
return new FastFailSocket();
}
if (req.hasSubProtocol("drop"))
{
return new DropServerConnectionSocket();
}
if (req.hasSubProtocol("container"))
{
closeSocket = new ContainerSocket(serverFactory);
return closeSocket;
return new ContainerSocket(serverFactory);
}
return new RFC6455Socket();
}
}
/**
* On Message, return container information
*/
public static class ContainerSocket extends AbstractCloseSocket
{
private static final Logger LOG = Log.getLogger(WebSocketCloseTest.ContainerSocket.class);
private final WebSocketServerFactory container;
private Session session;
public ContainerSocket(WebSocketServerFactory container)
{
this.container = container;
}
@Override
public void onWebSocketText(String message)
{
LOG.debug("onWebSocketText({})",message);
if (message.equalsIgnoreCase("openSessions"))
{
Collection<WebSocketSession> sessions = container.getOpenSessions();
StringBuilder ret = new StringBuilder();
ret.append("openSessions.size=").append(sessions.size()).append('\n');
int idx = 0;
for (WebSocketSession sess : sessions)
{
ret.append('[').append(idx++).append("] ").append(sess.toString()).append('\n');
}
session.getRemote().sendStringByFuture(ret.toString());
}
session.close(StatusCode.NORMAL,"ContainerSocket");
}
@Override
public void onWebSocketConnect(Session sess)
{
LOG.debug("onWebSocketConnect({})",sess);
this.session = sess;
}
}
/**
* On Connect, close socket
*/
public static class FastCloseSocket extends AbstractCloseSocket
{
private static final Logger LOG = Log.getLogger(WebSocketCloseTest.FastCloseSocket.class);
@Override
public void onWebSocketConnect(Session sess)
{
LOG.debug("onWebSocketConnect({})",sess);
sess.close(StatusCode.NORMAL,"FastCloseServer");
}
}
/**
* On Connect, throw unhandled exception
*/
public static class FastFailSocket extends AbstractCloseSocket
{
private static final Logger LOG = Log.getLogger(WebSocketCloseTest.FastFailSocket.class);
@Override
public void onWebSocketConnect(Session sess)
{
LOG.debug("onWebSocketConnect({})",sess);
// Test failure due to unhandled exception
// this should trigger a fast-fail closure during open/connect
throw new RuntimeException("Intentional FastFail");
}
}
private static final Logger LOG = Log.getLogger(WebSocketCloseTest.class);
private static SimpleServletServer server;
private static AbstractCloseSocket closeSocket;
@BeforeClass
public static void startServer() throws Exception
private SimpleServletServer server;
@Before
public void startServer() throws Exception
{
server = new SimpleServletServer(new CloseServlet());
server.start();
}
@AfterClass
public static void stopServer() throws Exception
@After
public void stopServer() throws Exception
{
server.stop();
}
@Rule
public TestName testname = new TestName();
private WebSocketClient client;
@Before
public void startClient() throws Exception
{
client = new WebSocketClient();
client.start();
}
@After
public void stopClient() throws Exception
{
client.stop();
}
/**
* Test fast close (bug #403817)
*
* @throws Exception
* on test failure
*
* @throws Exception on test failure
*/
@Test
public void testFastClose() throws Exception
public void fastClose() throws Exception
{
client.setMaxIdleTimeout(5000);
URI wsUri = server.getServerUri();
TrackingEndpoint clientSocket = new TrackingEndpoint(testname.getMethodName());
ClientUpgradeRequest upgradeRequest = new ClientUpgradeRequest();
upgradeRequest.setSubProtocols("fastclose");
Future<Session> clientConnectFuture = client.connect(clientSocket, wsUri, upgradeRequest);
Session clientSession = clientConnectFuture.get(Defaults.CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
clientSocket.awaitCloseEvent("Client");
clientSocket.assertCloseInfo("Client", StatusCode.NORMAL, anything());
Map<String, String> upgradeHeaders = UpgradeUtils.newDefaultUpgradeRequestHeaders();
upgradeHeaders.put(WebSocketConstants.SEC_WEBSOCKET_PROTOCOL, "fastclose");
clientSession.close();
List<WebSocketFrame> expect = new ArrayList<>();
expect.add(new CloseInfo(StatusCode.NORMAL, "FastCloseServer").asFrame());
try (LocalFuzzer session = server.newLocalFuzzer("/", upgradeHeaders))
{
session.sendFrames(new CloseInfo(StatusCode.NORMAL).asFrame());
session.expect(expect);
}
}
/**
* Test fast fail (bug #410537)
*
* @throws Exception
* on test failure
*
* @throws Exception on test failure
*/
@Test
public void testFastFail() throws Exception
public void fastFail() throws Exception
{
client.setMaxIdleTimeout(1000);
URI wsUri = server.getServerUri();
TrackingEndpoint clientSocket = new TrackingEndpoint(testname.getMethodName());
ClientUpgradeRequest upgradeRequest = new ClientUpgradeRequest();
upgradeRequest.setSubProtocols("fastfail");
Future<Session> clientConnectFuture = client.connect(clientSocket, wsUri, upgradeRequest);
Session clientSession = clientConnectFuture.get(Defaults.CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
clientSocket.awaitCloseEvent("Client");
clientSocket.assertCloseInfo("Client", StatusCode.SERVER_ERROR, anything());
clientSession.close();
Map<String, String> upgradeHeaders = UpgradeUtils.newDefaultUpgradeRequestHeaders();
upgradeHeaders.put(WebSocketConstants.SEC_WEBSOCKET_PROTOCOL, "fastfail");
List<WebSocketFrame> expect = new ArrayList<>();
expect.add(new CloseInfo(StatusCode.SERVER_ERROR).asFrame());
try (StacklessLogging ignore = new StacklessLogging(FastFailSocket.class);
LocalFuzzer session = server.newLocalFuzzer("/", upgradeHeaders))
{
session.expect(expect);
}
}
@Test
public void dropServerConnection() throws Exception
{
Map<String, String> upgradeHeaders = UpgradeUtils.newDefaultUpgradeRequestHeaders();
upgradeHeaders.put(WebSocketConstants.SEC_WEBSOCKET_PROTOCOL, "drop");
try (LocalFuzzer session = server.newLocalFuzzer("/", upgradeHeaders))
{
session.sendFrames(new TextFrame().setPayload("drop"));
BlockingQueue<WebSocketFrame> framesQueue = session.getOutputFrames();
assertThat("No frames as output", framesQueue.size(), Matchers.is(0));
}
}
/**
* Test session open session cleanup (bug #474936)
*
* @throws Exception
* on test failure
*
* @throws Exception on test failure
*/
@Test
public void testOpenSessionCleanup() throws Exception
{
fastFail();
fastClose();
dropConnection();
client.setMaxIdleTimeout(1000);
URI wsUri = server.getServerUri();
TrackingEndpoint clientSocket = new TrackingEndpoint(testname.getMethodName());
ClientUpgradeRequest upgradeRequest = new ClientUpgradeRequest();
upgradeRequest.setSubProtocols("container");
Future<Session> clientConnectFuture = client.connect(clientSocket, wsUri, upgradeRequest);
Session clientSession = clientConnectFuture.get(Defaults.CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
dropClientConnection();
clientSession.getRemote().sendString("openSessions");
Map<String, String> upgradeHeaders = UpgradeUtils.newDefaultUpgradeRequestHeaders();
upgradeHeaders.put(WebSocketConstants.SEC_WEBSOCKET_PROTOCOL, "container");
String incomingMessage = clientSocket.messageQueue.poll(5, TimeUnit.SECONDS);
assertThat("Incoming Message", incomingMessage, containsString("openSessions.size=1\n"));
clientSocket.awaitCloseEvent("Client");
clientSocket.assertCloseInfo("Client", StatusCode.NORMAL, anything());
}
@SuppressWarnings("Duplicates")
private void fastClose() throws Exception
{
client.setMaxIdleTimeout(1000);
URI wsUri = server.getServerUri();
TrackingEndpoint clientSocket = new TrackingEndpoint(testname.getMethodName());
ClientUpgradeRequest upgradeRequest = new ClientUpgradeRequest();
upgradeRequest.setSubProtocols("fastclose");
Future<Session> clientConnectFuture = client.connect(clientSocket, wsUri, upgradeRequest);
Session clientSession = clientConnectFuture.get(Defaults.CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
clientSocket.awaitCloseEvent("Client");
clientSocket.assertCloseInfo("Client", StatusCode.NORMAL, anything());
clientSession.close();
}
private void fastFail() throws Exception
{
client.setMaxIdleTimeout(1000);
URI wsUri = server.getServerUri();
TrackingEndpoint clientSocket = new TrackingEndpoint(testname.getMethodName());
ClientUpgradeRequest upgradeRequest = new ClientUpgradeRequest();
upgradeRequest.setSubProtocols("fastfail");
Future<Session> clientConnectFuture = client.connect(clientSocket, wsUri, upgradeRequest);
Session clientSession = clientConnectFuture.get(Defaults.CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
clientSocket.awaitCloseEvent("Client");
clientSocket.assertCloseInfo("Client", StatusCode.SERVER_ERROR, anything());
clientSession.close();
try (LocalFuzzer session = server.newLocalFuzzer("/?openSessions", upgradeHeaders))
{
session.sendFrames(
new TextFrame().setPayload("openSessions"),
new CloseInfo(StatusCode.NORMAL).asFrame()
);
BlockingQueue<WebSocketFrame> framesQueue = session.getOutputFrames();
WebSocketFrame frame = framesQueue.poll(1, TimeUnit.SECONDS);
assertThat("Frame.opCode", frame.getOpCode(), is(OpCode.TEXT));
assertThat("Frame.text-payload", frame.getPayloadAsUTF8(), containsString("openSessions.size=1\n"));
}
}
@SuppressWarnings("Duplicates")
private void dropConnection() throws Exception
private void dropClientConnection() throws Exception
{
client.setMaxIdleTimeout(1000);
URI wsUri = server.getServerUri();
TrackingEndpoint clientSocket = new TrackingEndpoint(testname.getMethodName());
ClientUpgradeRequest upgradeRequest = new ClientUpgradeRequest();
upgradeRequest.setSubProtocols("container");
Future<Session> clientConnectFuture = client.connect(clientSocket, wsUri, upgradeRequest);
Session clientSession = clientConnectFuture.get(Defaults.CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
clientSession.close();
Map<String, String> upgradeHeaders = UpgradeUtils.newDefaultUpgradeRequestHeaders();
upgradeHeaders.put(WebSocketConstants.SEC_WEBSOCKET_PROTOCOL, "container");
try (LocalFuzzer ignored = server.newLocalFuzzer("/", upgradeHeaders))
{
// do nothing, just let endpoint close
}
}
}

View File

@ -18,17 +18,11 @@
package org.eclipse.jetty.websocket.tests.server;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.toolchain.test.AdvancedRunner;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.websocket.api.BatchMode;
@ -37,26 +31,20 @@ import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
import org.eclipse.jetty.websocket.client.WebSocketClient;
import org.eclipse.jetty.websocket.common.WebSocketFrame;
import org.eclipse.jetty.websocket.common.frames.CloseFrame;
import org.eclipse.jetty.websocket.common.frames.TextFrame;
import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
import org.eclipse.jetty.websocket.tests.Defaults;
import org.eclipse.jetty.websocket.tests.LocalFuzzer;
import org.eclipse.jetty.websocket.tests.SimpleServletServer;
import org.eclipse.jetty.websocket.tests.TrackingEndpoint;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestName;
import org.junit.runner.RunWith;
/**
* Testing various aspects of the server side support for WebSocket {@link org.eclipse.jetty.websocket.api.Session}
*/
@RunWith(AdvancedRunner.class)
public class WebSocketServerSessionTest
{
public static class SessionServlet extends WebSocketServlet
@ -83,7 +71,7 @@ public class WebSocketServerSessionTest
@OnWebSocketMessage
public void onText(String message)
{
LOG.debug("onText({})",message);
LOG.debug("onText({})", message);
if (message == null)
{
return;
@ -125,24 +113,18 @@ public class WebSocketServerSessionTest
if ("session.isSecure".equals(message))
{
String issecure = String.format("session.isSecure=%b",session.isSecure());
String issecure = String.format("session.isSecure=%b", session.isSecure());
sendString(issecure);
return;
}
if ("session.upgradeRequest.requestURI".equals(message))
{
String response = String.format("session.upgradeRequest.requestURI=%s",session.getUpgradeRequest().getRequestURI().toASCIIString());
String response = String.format("session.upgradeRequest.requestURI=%s", session.getUpgradeRequest().getRequestURI().toASCIIString());
sendString(response);
return;
}
if ("harsh-disconnect".equals(message))
{
session.disconnect();
return;
}
// echo the message back.
sendString(message);
}
@ -162,77 +144,43 @@ public class WebSocketServerSessionTest
}
private static SimpleServletServer server;
@BeforeClass
public static void startServer() throws Exception
{
server = new SimpleServletServer(new SessionServlet());
server.start();
}
@AfterClass
public static void stopServer() throws Exception
{
server.stop();
}
@Rule
public TestName testname = new TestName();
private WebSocketClient client;
@Before
public void startClient() throws Exception
{
client = new WebSocketClient();
client.start();
}
@After
public void stopClient() throws Exception
{
client.stop();
}
@Test
public void testDisconnect() throws Exception
{
URI wsUri = server.getServerUri().resolve("/test/disconnect");
TrackingEndpoint clientSocket = new TrackingEndpoint(testname.getMethodName());
ClientUpgradeRequest upgradeRequest = new ClientUpgradeRequest();
Future<Session> clientConnectFuture = client.connect(clientSocket, wsUri, upgradeRequest);
Session clientSession = clientConnectFuture.get(Defaults.CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
clientSession.getRemote().sendString("harsh-disconnect");
// TODO: or onError(EOF)
clientSocket.awaitCloseEvent("Client");
}
@Test
public void testUpgradeRequestResponse() throws Exception
{
URI wsUri = server.getServerUri().resolve("/test?snack=cashews&amount=handful&brand=off");
TrackingEndpoint clientSocket = new TrackingEndpoint(testname.getMethodName());
ClientUpgradeRequest upgradeRequest = new ClientUpgradeRequest();
Future<Session> clientConnectFuture = client.connect(clientSocket, wsUri, upgradeRequest);
Session clientSession = clientConnectFuture.get(Defaults.CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
clientSession.getRemote().sendString("getParameterMap|snack");
clientSession.getRemote().sendString("getParameterMap|amount");
clientSession.getRemote().sendString("getParameterMap|brand");
clientSession.getRemote().sendString("getParameterMap|cost");
String requestPath = "/test?snack=cashews&amount=handful&brand=off";
String incomingMessage;
incomingMessage = clientSocket.messageQueue.poll(5, TimeUnit.SECONDS);
assertThat("Parameter Map[snack]", incomingMessage, is("[cashews]"));
incomingMessage = clientSocket.messageQueue.poll(5, TimeUnit.SECONDS);
assertThat("Parameter Map[amount]", incomingMessage, is("[handful]"));
incomingMessage = clientSocket.messageQueue.poll(5, TimeUnit.SECONDS);
assertThat("Parameter Map[brand]", incomingMessage, is("[off]"));
incomingMessage = clientSocket.messageQueue.poll(5, TimeUnit.SECONDS);
assertThat("Parameter Map[cost]", incomingMessage, is("<null>"));
List<WebSocketFrame> send = new ArrayList<>();
send.add(new TextFrame().setPayload("getParameterMap|snack"));
send.add(new TextFrame().setPayload("getParameterMap|amount"));
send.add(new TextFrame().setPayload("getParameterMap|brand"));
send.add(new TextFrame().setPayload("getParameterMap|cost"));
send.add(new CloseFrame());
List<WebSocketFrame> expect = new ArrayList<>();
expect.add(new TextFrame().setPayload("[cashews]"));
expect.add(new TextFrame().setPayload("[handful]"));
expect.add(new TextFrame().setPayload("[off]"));
expect.add(new TextFrame().setPayload("<null>"));
send.add(new CloseFrame());
try (LocalFuzzer session = server.newLocalFuzzer(requestPath))
{
session.sendFrames(send);
session.expect(expect);
}
}
}

View File

@ -0,0 +1,134 @@
//
// ========================================================================
// Copyright (c) 1995-2017 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.server;
import static org.hamcrest.Matchers.notNullValue;
import static org.junit.Assert.assertThat;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import javax.servlet.DispatcherType;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.websocket.server.NativeWebSocketConfiguration;
import org.eclipse.jetty.websocket.server.WebSocketUpgradeFilter;
import org.eclipse.jetty.websocket.servlet.WebSocketCreator;
import org.eclipse.jetty.websocket.tests.LocalServer;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@RunWith(Parameterized.class)
public class WebSocketUpgradeFilterEmbeddedTest extends WebSocketUpgradeFilterTest
{
private interface Case
{
void customize(ServletContextHandler context) throws Exception;
}
@Parameterized.Parameters(name = "{0}")
public static List<Object[]> data()
{
final WebSocketCreator infoCreator = (req, resp) -> new InfoSocket();
List<Object[]> cases = new ArrayList<>();
// Embedded WSUF.configureContext(), directly app-ws configuration
cases.add(new Object[]
{"wsuf.configureContext/Direct configure", (Case) (context) ->
{
WebSocketUpgradeFilter wsuf = WebSocketUpgradeFilter.configureContext(context);
// direct configuration via WSUF
wsuf.getFactory().getPolicy().setMaxTextMessageSize(10 * 1024 * 1024);
wsuf.addMapping("/info/*", infoCreator);
}});
// Embedded WSUF.configureContext(), apply app-ws configuration via attribute
cases.add(new Object[]{
"wsuf.configureContext/Attribute based configure", (Case) (context) ->
{
WebSocketUpgradeFilter.configureContext(context);
// configuration via attribute
NativeWebSocketConfiguration configuration = (NativeWebSocketConfiguration) context.getServletContext().getAttribute(NativeWebSocketConfiguration.class.getName());
assertThat("NativeWebSocketConfiguration", configuration, notNullValue());
configuration.getFactory().getPolicy().setMaxTextMessageSize(10 * 1024 * 1024);
configuration.addMapping("/info/*", infoCreator);
}});
// Embedded WSUF, added as filter, apply app-ws configuration via attribute
cases.add(new Object[]{
"wsuf/addFilter/Attribute based configure", (Case) (context) ->
{
context.addFilter(WebSocketUpgradeFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST));
NativeWebSocketConfiguration configuration = new NativeWebSocketConfiguration(context.getServletContext());
configuration.getFactory().getPolicy().setMaxTextMessageSize(10 * 1024 * 1024);
configuration.addMapping("/info/*", infoCreator);
context.setAttribute(NativeWebSocketConfiguration.class.getName(), configuration);
}});
// Embedded WSUF, added as filter, apply app-ws configuration via wsuf constructor
cases.add(new Object[]{
"wsuf/addFilter/WSUF Constructor configure", (Case) (context) ->
{
NativeWebSocketConfiguration configuration = new NativeWebSocketConfiguration(context.getServletContext());
configuration.getFactory().getPolicy().setMaxTextMessageSize(10 * 1024 * 1024);
configuration.addMapping("/info/*", infoCreator);
context.addBean(configuration, true);
FilterHolder wsufHolder = new FilterHolder(new WebSocketUpgradeFilter(configuration));
context.addFilter(wsufHolder, "/*", EnumSet.of(DispatcherType.REQUEST));
}});
// Embedded WSUF, added as filter, apply app-ws configuration via ServletContextListener
cases.add(new Object[]{
"wsuf.configureContext/ServletContextListener configure", (Case) (context) ->
{
context.addFilter(WebSocketUpgradeFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST));
context.addEventListener(new InfoContextListener());
}});
return cases;
}
public WebSocketUpgradeFilterEmbeddedTest(String testid, Case testcase) throws Exception
{
super(newServer(testcase));
}
private static LocalServer newServer(Case testcase)
{
return new LocalServer()
{
@Override
protected void configureServletContextHandler(ServletContextHandler context) throws Exception
{
testcase.customize(context);
}
};
}
}

View File

@ -18,361 +18,118 @@
package org.eclipse.jetty.websocket.tests.server;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.notNullValue;
import static org.junit.Assert.assertThat;
import java.io.File;
import java.net.URI;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.concurrent.Future;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import javax.servlet.DispatcherType;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.toolchain.test.FS;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.websocket.api.Session;
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.server.NativeWebSocketConfiguration;
import org.eclipse.jetty.websocket.server.WebSocketUpgradeFilter;
import org.eclipse.jetty.websocket.servlet.WebSocketCreator;
import org.eclipse.jetty.websocket.tests.Defaults;
import org.eclipse.jetty.websocket.tests.TrackingEndpoint;
import org.eclipse.jetty.websocket.tests.WSServer;
import org.eclipse.jetty.websocket.api.StatusCode;
import org.eclipse.jetty.websocket.common.CloseInfo;
import org.eclipse.jetty.websocket.common.OpCode;
import org.eclipse.jetty.websocket.common.WebSocketFrame;
import org.eclipse.jetty.websocket.common.frames.TextFrame;
import org.eclipse.jetty.websocket.tests.LocalFuzzer;
import org.eclipse.jetty.websocket.tests.LocalServer;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestName;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@RunWith(Parameterized.class)
public class WebSocketUpgradeFilterTest
public abstract class WebSocketUpgradeFilterTest
{
interface ServerProvider
{
Server newServer() throws Exception;
}
private static AtomicInteger uniqTestDirId = new AtomicInteger(0);
private static File getNewTestDir()
protected static File getNewTestDir()
{
return MavenTestingUtils.getTargetTestingDir("WSUF-webxml-" + uniqTestDirId.getAndIncrement());
}
@Parameterized.Parameters(name = "{0}")
public static List<Object[]> data()
{
final WebSocketCreator infoCreator = (req, resp) -> new InfoSocket();
List<Object[]> cases = new ArrayList<>();
// Embedded WSUF.configureContext(), directly app-ws configuration
cases.add(new Object[]{"wsuf.configureContext/Direct configure", (ServerProvider) () ->
{
Server server1 = new Server();
ServerConnector connector = new ServerConnector(server1);
connector.setPort(0);
server1.addConnector(connector);
ServletContextHandler context = new ServletContextHandler();
context.setContextPath("/");
server1.setHandler(context);
WebSocketUpgradeFilter wsuf = WebSocketUpgradeFilter.configureContext(context);
// direct configuration via WSUF
wsuf.getFactory().getPolicy().setMaxTextMessageSize(10 * 1024 * 1024);
wsuf.addMapping("/info/*", infoCreator);
server1.start();
return server1;
}});
// Embedded WSUF.configureContext(), apply app-ws configuration via attribute
cases.add(new Object[]{"wsuf.configureContext/Attribute based configure", (ServerProvider) () ->
{
Server server12 = new Server();
ServerConnector connector = new ServerConnector(server12);
connector.setPort(0);
server12.addConnector(connector);
ServletContextHandler context = new ServletContextHandler();
context.setContextPath("/");
server12.setHandler(context);
WebSocketUpgradeFilter.configureContext(context);
// configuration via attribute
NativeWebSocketConfiguration configuration = (NativeWebSocketConfiguration) context.getServletContext().getAttribute(NativeWebSocketConfiguration.class.getName());
assertThat("NativeWebSocketConfiguration", configuration, notNullValue());
configuration.getFactory().getPolicy().setMaxTextMessageSize(10 * 1024 * 1024);
configuration.addMapping("/info/*", infoCreator);
server12.start();
return server12;
}});
// Embedded WSUF, added as filter, apply app-ws configuration via attribute
cases.add(new Object[]{"wsuf/addFilter/Attribute based configure", (ServerProvider) () ->
{
Server server13 = new Server();
ServerConnector connector = new ServerConnector(server13);
connector.setPort(0);
server13.addConnector(connector);
ServletContextHandler context = new ServletContextHandler();
context.setContextPath("/");
server13.setHandler(context);
context.addFilter(WebSocketUpgradeFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST));
NativeWebSocketConfiguration configuration = new NativeWebSocketConfiguration(context.getServletContext());
configuration.getFactory().getPolicy().setMaxTextMessageSize(10 * 1024 * 1024);
configuration.addMapping("/info/*", infoCreator);
context.setAttribute(NativeWebSocketConfiguration.class.getName(), configuration);
server13.start();
return server13;
}});
// Embedded WSUF, added as filter, apply app-ws configuration via wsuf constructor
cases.add(new Object[]{"wsuf/addFilter/WSUF Constructor configure", new ServerProvider()
{
@Override
public Server newServer() throws Exception
{
Server server = new Server();
ServerConnector connector = new ServerConnector(server);
connector.setPort(0);
server.addConnector(connector);
ServletContextHandler context = new ServletContextHandler();
context.setContextPath("/");
server.setHandler(context);
NativeWebSocketConfiguration configuration = new NativeWebSocketConfiguration(context.getServletContext());
configuration.getFactory().getPolicy().setMaxTextMessageSize(10 * 1024 * 1024);
configuration.addMapping("/info/*", infoCreator);
context.addBean(configuration, true);
FilterHolder wsufHolder = new FilterHolder(new WebSocketUpgradeFilter(configuration));
context.addFilter(wsufHolder, "/*", EnumSet.of(DispatcherType.REQUEST));
server.start();
return server;
}
}});
// Embedded WSUF, added as filter, apply app-ws configuration via ServletContextListener
cases.add(new Object[]{"wsuf.configureContext/ServletContextListener configure", (ServerProvider) () ->
{
Server server14 = new Server();
ServerConnector connector = new ServerConnector(server14);
connector.setPort(0);
server14.addConnector(connector);
ServletContextHandler context = new ServletContextHandler();
context.setContextPath("/");
server14.setHandler(context);
context.addFilter(WebSocketUpgradeFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST));
context.addEventListener(new InfoContextListener());
server14.start();
return server14;
}});
// WSUF from web.xml, SCI active, apply app-ws configuration via ServletContextListener
cases.add(new Object[]{"wsuf/WebAppContext/web.xml/ServletContextListener", (ServerProvider) () ->
{
File testDir = getNewTestDir();
WSServer server15 = new WSServer(testDir, "/");
server15.copyWebInf("wsuf-config-via-listener.xml");
server15.copyClass(InfoSocket.class);
server15.copyClass(InfoContextAttributeListener.class);
server15.start();
WebAppContext webapp = server15.createWebAppContext();
server15.deployWebapp(webapp);
return server15.getServer();
}});
// WSUF from web.xml, SCI active, apply app-ws configuration via ServletContextListener with WEB-INF/lib/jetty-http.jar
cases.add(new Object[]{"wsuf/WebAppContext/web.xml/ServletContextListener/jetty-http.jar", new ServerProvider()
{
@Override
public Server newServer() throws Exception
{
File testDir = getNewTestDir();
WSServer server = new WSServer(testDir, "/");
server.copyWebInf("wsuf-config-via-listener.xml");
server.copyClass(InfoSocket.class);
server.copyClass(InfoContextAttributeListener.class);
// Add a jetty-http.jar to ensure that the classloader constraints
// and the WebAppClassloader setup is sane and correct
// The odd version string is present to capture bad regex behavior in Jetty
server.copyLib(org.eclipse.jetty.http.pathmap.PathSpec.class, "jetty-http-9.99.999.jar");
server.start();
WebAppContext webapp = server.createWebAppContext();
server.deployWebapp(webapp);
return server.getServer();
}
}});
// WSUF from web.xml, SCI active, apply app-ws configuration via Servlet.init
cases.add(new Object[]{"wsuf/WebAppContext/web.xml/Servlet.init", (ServerProvider) () ->
{
File testDir = getNewTestDir();
WSServer server16 = new WSServer(testDir, "/");
server16.copyWebInf("wsuf-config-via-servlet-init.xml");
server16.copyClass(InfoSocket.class);
server16.copyClass(InfoServlet.class);
server16.start();
WebAppContext webapp = server16.createWebAppContext();
server16.deployWebapp(webapp);
return server16.getServer();
}});
// xml based, wsuf, on alternate url-pattern and config attribute location
cases.add(new Object[]{"wsuf/WebAppContext/web.xml/ServletContextListener/alt-config", (ServerProvider) () ->
{
File testDir = getNewTestDir();
WSServer server17 = new WSServer(testDir, "/");
server17.copyWebInf("wsuf-alt-config-via-listener.xml");
server17.copyClass(InfoSocket.class);
server17.copyClass(InfoContextAltAttributeListener.class);
server17.start();
WebAppContext webapp = server17.createWebAppContext();
server17.deployWebapp(webapp);
return server17.getServer();
}});
return cases;
File testDir = MavenTestingUtils.getTargetTestingDir("WSUF-webxml-" + uniqTestDirId.getAndIncrement());
FS.ensureDirExists(testDir);
return testDir;
}
@Rule
public TestName testname = new TestName();
private WebSocketClient client;
private LocalServer server;
@Before
public void startClient() throws Exception
public WebSocketUpgradeFilterTest(LocalServer server) throws Exception
{
client = new WebSocketClient();
client.start();
this.server = server;
this.server.start();
}
@After
public void stopClient() throws Exception
public void stopServer() throws Exception
{
client.stop();
}
private final Server server;
private final URI serverUri;
public WebSocketUpgradeFilterTest(String testId, ServerProvider serverProvider) throws Exception
{
this.server = serverProvider.newServer();
serverUri = WSURI.toWebsocket(server.getURI());
server.stop();
}
@Test
public void testNormalConfiguration() throws Exception
{
URI wsUri = serverUri.resolve("/info/");
TrackingEndpoint clientSocket = new TrackingEndpoint(testname.getMethodName());
ClientUpgradeRequest upgradeRequest = new ClientUpgradeRequest();
Future<Session> clientConnectFuture = client.connect(clientSocket, wsUri, upgradeRequest);
Session clientSession = clientConnectFuture.get(Defaults.CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
clientSession.getRemote().sendString("hello");
String incomingMessage = clientSocket.messageQueue.poll(5, TimeUnit.SECONDS);
// If we can connect and send a text message, we know that the endpoint was
// added properly, and the response will help us verify the policy configuration too
assertThat("Client incoming message", incomingMessage, containsString("session.maxTextMessageSize=" + (10 * 1024 * 1024)));
try (LocalFuzzer session = server.newLocalFuzzer("/info/"))
{
session.sendFrames(
new TextFrame().setPayload("hello"),
new CloseInfo(StatusCode.NORMAL).asFrame()
);
BlockingQueue<WebSocketFrame> framesQueue = session.getOutputFrames();
WebSocketFrame frame = framesQueue.poll(1, TimeUnit.SECONDS);
assertThat("Frame.opCode", frame.getOpCode(), is(OpCode.TEXT));
// If we can connect and send a text message, we know that the endpoint was
// added properly, and the response will help us verify the policy configuration too
assertThat("Frame.text-payload", frame.getPayloadAsUTF8(), containsString("session.maxTextMessageSize=" + (10 * 1024 * 1024)));
}
}
@Test
public void testStopStartOfHandler() throws Exception
{
URI wsUri = serverUri.resolve("/info/");
TrackingEndpoint clientSocket = new TrackingEndpoint(testname.getMethodName());
ClientUpgradeRequest upgradeRequest = new ClientUpgradeRequest();
Future<Session> clientConnectFuture = client.connect(clientSocket, wsUri, upgradeRequest);
Session clientSession = clientConnectFuture.get(Defaults.CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
clientSession.getRemote().sendString("hello 1");
String incomingMessage = clientSocket.messageQueue.poll(5, TimeUnit.SECONDS);
// If we can connect and send a text message, we know that the endpoint was
// added properly, and the response will help us verify the policy configuration too
assertThat("Client incoming message", incomingMessage, containsString("session.maxTextMessageSize=" + (10 * 1024 * 1024)));
clientSession.close();
try (LocalFuzzer session = server.newLocalFuzzer("/info/"))
{
session.sendFrames(
new TextFrame().setPayload("hello 1"),
new CloseInfo(StatusCode.NORMAL).asFrame()
);
BlockingQueue<WebSocketFrame> framesQueue = session.getOutputFrames();
WebSocketFrame frame = framesQueue.poll(1, TimeUnit.SECONDS);
assertThat("Frame.opCode", frame.getOpCode(), is(OpCode.TEXT));
// If we can connect and send a text message, we know that the endpoint was
// added properly, and the response will help us verify the policy configuration too
assertThat("Frame.text-payload", frame.getPayloadAsUTF8(), containsString("session.maxTextMessageSize=" + (10 * 1024 * 1024)));
}
server.getHandler().stop();
server.getHandler().start();
server.getServletContextHandler().stop();
server.getServletContextHandler().start();
// Make request again (server should have retained websocket configuration)
clientSocket = new TrackingEndpoint(testname.getMethodName());
upgradeRequest = new ClientUpgradeRequest();
clientConnectFuture = client.connect(clientSocket, wsUri, upgradeRequest);
clientSession = clientConnectFuture.get(Defaults.CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
clientSession.getRemote().sendString("hello 2");
incomingMessage = clientSocket.messageQueue.poll(5, TimeUnit.SECONDS);
// If we can connect and send a text message, we know that the endpoint was
// added properly, and the response will help us verify the policy configuration too
assertThat("Client incoming message", incomingMessage, containsString("session.maxTextMessageSize=" + (10 * 1024 * 1024)));
clientSession.close();
try (LocalFuzzer session = server.newLocalFuzzer("/info/"))
{
session.sendFrames(
new TextFrame().setPayload("hello 2"),
new CloseInfo(StatusCode.NORMAL).asFrame()
);
BlockingQueue<WebSocketFrame> framesQueue = session.getOutputFrames();
WebSocketFrame frame = framesQueue.poll(1, TimeUnit.SECONDS);
assertThat("Frame.opCode", frame.getOpCode(), is(OpCode.TEXT));
// If we can connect and send a text message, we know that the endpoint was
// added properly, and the response will help us verify the policy configuration too
assertThat("Frame.text-payload", frame.getPayloadAsUTF8(), containsString("session.maxTextMessageSize=" + (10 * 1024 * 1024)));
}
}
}

View File

@ -0,0 +1,111 @@
//
// ========================================================================
// Copyright (c) 1995-2017 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.server;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.websocket.tests.WSServer;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@RunWith(Parameterized.class)
public class WebSocketUpgradeFilterWebappTest extends WebSocketUpgradeFilterTest
{
private interface Case
{
void customize(WSServer server) throws Exception;
}
@Parameterized.Parameters(name = "{0}")
public static List<Object[]> data()
{
List<Object[]> cases = new ArrayList<>();
// WSUF from web.xml, SCI active, apply app-ws configuration via ServletContextListener
cases.add(new Object[]{
"From ServletContextListener",
(Case) (server) ->
{
server.copyWebInf("wsuf-config-via-listener.xml");
server.copyClass(InfoSocket.class);
server.copyClass(InfoContextAttributeListener.class);
}
});
// WSUF from web.xml, SCI active, apply app-ws configuration via ServletContextListener with WEB-INF/lib/jetty-http.jar
cases.add(new Object[]{
"From ServletContextListener with jar scanning",
(Case) (server) ->
{
server.copyWebInf("wsuf-config-via-listener.xml");
server.copyClass(InfoSocket.class);
server.copyClass(InfoContextAttributeListener.class);
// Add a jetty-http.jar to ensure that the classloader constraints
// and the WebAppClassloader setup is sane and correct
// The odd version string is present to capture bad regex behavior in Jetty
server.copyLib(org.eclipse.jetty.http.pathmap.PathSpec.class, "jetty-http-9.99.999.jar");
}
});
return cases;
}
public WebSocketUpgradeFilterWebappTest(String testid, Case testcase) throws Exception
{
super(newServer(testcase));
}
private static WSServer newServer(Case testcase)
{
return new WSServer(getNewTestDir(), "")
{
private WebAppContext webapp;
@Override
protected Handler createRootHandler(Server server) throws Exception
{
Handler handler = super.createRootHandler(server);
testcase.customize(this);
return handler;
}
@Override
public ServletContextHandler getServletContextHandler()
{
return this.webapp;
}
@Override
protected void doStart() throws Exception
{
super.doStart();
this.webapp = createWebAppContext();
deployWebapp(webapp);
}
};
}
}

View File

@ -71,7 +71,7 @@ public class AnnotatedServerEndpointTest
}
@AfterClass
public static void stopServer()
public static void stopServer() throws Exception
{
server.stop();
}

View File

@ -0,0 +1,56 @@
//
// ========================================================================
// Copyright (c) 1995-2017 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.server.jsr356;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.websocket.DeploymentException;
import javax.websocket.server.ServerContainer;
import javax.websocket.server.ServerEndpointConfig;
import org.eclipse.jetty.websocket.tests.server.jsr356.sockets.IdleTimeoutOnOpenEndpoint;
/**
* Example of adding a server WebSocket (extending {@link javax.websocket.Endpoint}) programmatically via config
*/
public class IdleTimeoutContextListener implements ServletContextListener
{
@Override
public void contextDestroyed(ServletContextEvent sce)
{
/* do nothing */
}
@Override
public void contextInitialized(ServletContextEvent sce)
{
ServerContainer container = (ServerContainer)sce.getServletContext().getAttribute(ServerContainer.class.getName());
// Build up a configuration with a specific path
String path = "/idle-onopen-endpoint";
ServerEndpointConfig.Builder builder = ServerEndpointConfig.Builder.create(IdleTimeoutOnOpenEndpoint.class,path);
try
{
container.addEndpoint(builder.build());
}
catch (DeploymentException e)
{
throw new RuntimeException("Unable to add endpoint via config file",e);
}
}
}

View File

@ -0,0 +1,106 @@
//
// ========================================================================
// Copyright (c) 1995-2017 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.server.jsr356;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertThat;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.websocket.api.StatusCode;
import org.eclipse.jetty.websocket.common.CloseInfo;
import org.eclipse.jetty.websocket.common.OpCode;
import org.eclipse.jetty.websocket.common.WebSocketFrame;
import org.eclipse.jetty.websocket.common.frames.TextFrame;
import org.eclipse.jetty.websocket.tests.LeakTrackingBufferPoolRule;
import org.eclipse.jetty.websocket.tests.LocalFuzzer;
import org.eclipse.jetty.websocket.tests.WSServer;
import org.eclipse.jetty.websocket.tests.server.jsr356.sockets.IdleTimeoutOnOpenEndpoint;
import org.eclipse.jetty.websocket.tests.server.jsr356.sockets.IdleTimeoutOnOpenSocket;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
public class IdleTimeoutTest
{
@Rule
public LeakTrackingBufferPoolRule bufferPool = new LeakTrackingBufferPoolRule("Test");
private static WSServer server;
@BeforeClass
public static void setupServer() throws Exception
{
server = new WSServer(MavenTestingUtils.getTargetTestingPath(IdleTimeoutTest.class.getName()), "app");
server.copyWebInf("idle-timeout-config-web.xml");
// the endpoint (extends javax.websocket.Endpoint)
server.copyClass(IdleTimeoutOnOpenEndpoint.class);
// the configuration that adds the endpoint
server.copyClass(IdleTimeoutContextListener.class);
// the annotated socket
server.copyClass(IdleTimeoutOnOpenSocket.class);
server.start();
WebAppContext webapp = server.createWebAppContext();
server.deployWebapp(webapp);
// wsb.dump();
}
@AfterClass
public static void stopServer() throws Exception
{
server.stop();
}
private void assertConnectionTimeout(String requestPath) throws Exception
{
try (LocalFuzzer session = server.newLocalFuzzer(requestPath))
{
// wait 1 second to allow timeout to fire off
TimeUnit.SECONDS.sleep(1);
session.sendFrames(new TextFrame().setPayload("You shouldn't be there"));
BlockingQueue<WebSocketFrame> framesQueue = session.getOutputFrames();
WebSocketFrame frame = framesQueue.poll(1, TimeUnit.SECONDS);
assertThat("Frame.opCode", frame.getOpCode(), is(OpCode.CLOSE));
CloseInfo closeInfo = new CloseInfo(frame);
assertThat("Close.statusCode", closeInfo.getStatusCode(), is(StatusCode.SHUTDOWN));
assertThat("Close.reason", closeInfo.getReason(), containsString("Timeout"));
}
}
@Test
public void testAnnotated() throws Exception
{
assertConnectionTimeout("/app/idle-onopen-socket");
}
@Test
public void testEndpoint() throws Exception
{
assertConnectionTimeout("/app/idle-onopen-endpoint");
}
}

View File

@ -0,0 +1,173 @@
//
// ========================================================================
// Copyright (c) 1995-2017 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.server.jsr356;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
import org.eclipse.jetty.websocket.common.WebSocketFrame;
import org.eclipse.jetty.websocket.common.WebSocketSession;
import org.eclipse.jetty.websocket.common.frames.CloseFrame;
import org.eclipse.jetty.websocket.common.frames.TextFrame;
import org.eclipse.jetty.websocket.server.WebSocketServerFactory;
import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest;
import org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse;
import org.eclipse.jetty.websocket.servlet.WebSocketCreator;
import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
import org.eclipse.jetty.websocket.tests.LocalFuzzer;
import org.eclipse.jetty.websocket.tests.SimpleServletServer;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
public class SessionTrackingTest
{
@WebSocket
public static class SessionTrackingSocket
{
private final WebSocketServerFactory container;
public SessionTrackingSocket(WebSocketServerFactory container)
{
this.container = container;
}
@OnWebSocketMessage
public void onMessage(Session session, String msg) throws IOException
{
if (msg == null)
{
session.getRemote().sendString("Unknown command: <null>");
return;
}
String parts[] = msg.split("\\|");
if ("openSessions".equals(parts[0]))
{
Collection<WebSocketSession> sessions = container.getOpenSessions();
String ret = String.format("openSessions(@%s).size=%d", parts[1], sessions.size());
session.getRemote().sendString(ret);
return;
}
session.getRemote().sendString("Unknown command: " + msg);
}
}
public static class SessionTrackingServlet extends WebSocketServlet implements WebSocketCreator
{
private WebSocketServerFactory serverFactory;
@Override
public void configure(WebSocketServletFactory factory)
{
// If this fails, then we have a lot of tests failing.
this.serverFactory = (WebSocketServerFactory) factory;
factory.setCreator(this);
}
@Override
public Object createWebSocket(ServletUpgradeRequest req, ServletUpgradeResponse resp)
{
return new SessionTrackingSocket(serverFactory);
}
}
private static SimpleServletServer server;
@BeforeClass
public static void startServer() throws Exception
{
server = new SimpleServletServer(new SessionTrackingServlet());
server.start();
}
@AfterClass
public static void stopServer() throws Exception
{
server.stop();
}
@Test
public void testAddRemoveSessions() throws Exception
{
try (LocalFuzzer session1 = server.newLocalFuzzer("/1"))
{
sendTextFrameToAll("openSessions|in-1", session1);
try (LocalFuzzer session2 = server.newLocalFuzzer("/2"))
{
sendTextFrameToAll("openSessions|in-2", session1, session2);
try (LocalFuzzer session3 = server.newLocalFuzzer("/3"))
{
sendTextFrameToAll("openSessions|in-3", session1, session2, session3);
sendTextFrameToAll("openSessions|lvl-3", session1, session2, session3);
session3.sendFrames(new CloseFrame());
List<WebSocketFrame> expect3 = new ArrayList<>();
expect3.add(new TextFrame().setPayload("openSessions(@in-3).size=3"));
expect3.add(new TextFrame().setPayload("openSessions(@lvl-3).size=3"));
expect3.add(new CloseFrame());
session3.expect(expect3);
}
sendTextFrameToAll("openSessions|lvl-2", session1, session2);
session2.sendFrames(new CloseFrame());
List<WebSocketFrame> expect2 = new ArrayList<>();
expect2.add(new TextFrame().setPayload("openSessions(@in-2).size=2"));
expect2.add(new TextFrame().setPayload("openSessions(@in-3).size=3"));
expect2.add(new TextFrame().setPayload("openSessions(@lvl-3).size=3"));
expect2.add(new TextFrame().setPayload("openSessions(@lvl-2).size=2"));
expect2.add(new CloseFrame());
session2.expect(expect2);
}
sendTextFrameToAll("openSessions|lvl-1", session1);
session1.sendFrames(new CloseFrame());
List<WebSocketFrame> expect1 = new ArrayList<>();
expect1.add(new TextFrame().setPayload("openSessions(@in-1).size=1"));
expect1.add(new TextFrame().setPayload("openSessions(@in-2).size=2"));
expect1.add(new TextFrame().setPayload("openSessions(@in-3).size=3"));
expect1.add(new TextFrame().setPayload("openSessions(@lvl-3).size=3"));
expect1.add(new TextFrame().setPayload("openSessions(@lvl-2).size=2"));
expect1.add(new TextFrame().setPayload("openSessions(@lvl-1).size=1"));
expect1.add(new CloseFrame());
session1.expect(expect1);
}
}
private void sendTextFrameToAll(String msg, LocalFuzzer... sessions)
{
for (LocalFuzzer session : sessions)
{
session.sendFrames(new TextFrame().setPayload(msg));
}
}
}

View File

@ -16,7 +16,7 @@
// ========================================================================
//
package org.eclipse.jetty.websocket.jsr356.server;
package org.eclipse.jetty.websocket.tests.server.jsr356;
import static org.hamcrest.Matchers.equalToIgnoringCase;
import static org.hamcrest.Matchers.is;
@ -58,9 +58,10 @@ import org.eclipse.jetty.toolchain.test.IO;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.websocket.common.test.LeakTrackingBufferPoolRule;
import org.eclipse.jetty.websocket.common.util.Sha1Sum;
import org.eclipse.jetty.websocket.jsr356.server.ServerContainer;
import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer;
import org.eclipse.jetty.websocket.tests.LeakTrackingBufferPoolRule;
import org.eclipse.jetty.websocket.tests.Sha1Sum;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;

View File

@ -0,0 +1,44 @@
//
// ========================================================================
// Copyright (c) 1995-2017 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.server.jsr356.sockets;
import javax.websocket.Endpoint;
import javax.websocket.EndpointConfig;
import javax.websocket.MessageHandler;
import javax.websocket.Session;
public class IdleTimeoutOnOpenEndpoint extends Endpoint implements MessageHandler.Whole<String>
{
private Session session;
@Override
public void onOpen(Session session, EndpointConfig config)
{
this.session = session;
session.addMessageHandler(this);
session.setMaxIdleTimeout(500);
}
@Override
public void onMessage(String message)
{
// echo message back (this is an indication of timeout failure)
session.getAsyncRemote().sendText(message);
}
}

View File

@ -0,0 +1,40 @@
//
// ========================================================================
// Copyright (c) 1995-2017 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.server.jsr356.sockets;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
@ServerEndpoint(value = "/idle-onopen-socket")
public class IdleTimeoutOnOpenSocket
{
@OnOpen
public void onOpen(Session session)
{
session.setMaxIdleTimeout(500);
}
@OnMessage
public String onMessage(String msg)
{
return msg;
}
}

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<web-app
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
metadata-complete="false"
version="3.0">
<listener>
<listener-class>org.eclipse.jetty.websocket.tests.server.jsr356.IdleTimeoutContextListener</listener-class>
</listener>
</web-app>

View File

@ -22,14 +22,17 @@ org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
org.eclipse.jetty.LEVEL=WARN
# org.eclipse.jetty.util.log.stderr.LONG=true
# org.eclipse.jetty.server.AbstractConnector.LEVEL=DEBUG
# org.eclipse.jetty.io.WriteFlusher.LEVEL=DEBUG
org.eclipse.jetty.io.FillInterest.LEVEL=DEBUG
# org.eclipse.jetty.websocket.LEVEL=DEBUG
# org.eclipse.jetty.websocket.LEVEL=INFO
# org.eclipse.jetty.websocket.tests.LEVEL=DEBUG
org.eclipse.jetty.websocket.tests.LEVEL=DEBUG
# org.eclipse.jetty.websocket.tests.client.LEVEL=DEBUG
# org.eclipse.jetty.websocket.tests.client.jsr356.LEVEL=DEBUG
# org.eclipse.jetty.websocket.tests.server.LEVEL=DEBUG
# org.eclipse.jetty.websocket.tests.server.jsr356.LEVEL=DEBUG
org.eclipse.jetty.websocket.common.LEVEL=DEBUG
# org.eclipse.jetty.websocket.common.io.LEVEL=DEBUG
# org.eclipse.jetty.websocket.common.io.FrameFlusher.LEVEL=DEBUG
# org.eclipse.jetty.websocket.common.io.AbstractWebSocketConnection.LEVEL=DEBUG
@ -40,5 +43,6 @@ org.eclipse.jetty.LEVEL=WARN
# org.eclipse.jetty.websocket.common.message.LEVEL=DEBUG
org.eclipse.jetty.websocket.common.CompletionCallback.LEVEL=ALL
### Disabling intentional error out of RFCSocket
org.eclipse.jetty.websocket.tests.server.RFCSocket.LEVEL=OFF