Merge pull request #3407 from lachlan-roberts/jetty-10.0.x-core-test-cleanup
websocket core test cleanup
This commit is contained in:
commit
15647a742c
|
@ -1,140 +0,0 @@
|
||||||
//
|
|
||||||
// ========================================================================
|
|
||||||
// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
// All rights reserved. This program and the accompanying materials
|
|
||||||
// are made available under the terms of the Eclipse Public License v1.0
|
|
||||||
// and Apache License v2.0 which accompanies this distribution.
|
|
||||||
//
|
|
||||||
// The Eclipse Public License is available at
|
|
||||||
// http://www.eclipse.org/legal/epl-v10.html
|
|
||||||
//
|
|
||||||
// The Apache License v2.0 is available at
|
|
||||||
// http://www.opensource.org/licenses/apache2.0.php
|
|
||||||
//
|
|
||||||
// You may elect to redistribute this code under either of these licenses.
|
|
||||||
// ========================================================================
|
|
||||||
//
|
|
||||||
|
|
||||||
package org.eclipse.jetty.websocket.core;
|
|
||||||
|
|
||||||
import org.eclipse.jetty.util.log.Log;
|
|
||||||
import org.eclipse.jetty.util.log.Logger;
|
|
||||||
import org.hamcrest.Matcher;
|
|
||||||
import org.hamcrest.Matchers;
|
|
||||||
|
|
||||||
import java.util.concurrent.CountDownLatch;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
import static org.junit.jupiter.api.Assertions.fail;
|
|
||||||
|
|
||||||
public abstract class AbstractTrackingEndpoint<T>
|
|
||||||
{
|
|
||||||
public final Logger LOG;
|
|
||||||
|
|
||||||
public T session;
|
|
||||||
|
|
||||||
public CountDownLatch openLatch = new CountDownLatch(1);
|
|
||||||
public CountDownLatch closeLatch = new CountDownLatch(1);
|
|
||||||
public CountDownLatch errorLatch = new CountDownLatch(1);
|
|
||||||
public AtomicReference<CloseStatus> closeInfo = new AtomicReference<>();
|
|
||||||
public AtomicReference<Throwable> closeStack = new AtomicReference<>();
|
|
||||||
public AtomicReference<Throwable> error = new AtomicReference<>();
|
|
||||||
|
|
||||||
public AbstractTrackingEndpoint(String id)
|
|
||||||
{
|
|
||||||
LOG = Log.getLogger(this.getClass().getName() + "." + id);
|
|
||||||
LOG.debug("init");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void assertCloseInfo(String prefix, int expectedCloseStatusCode, Matcher<? super String> reasonMatcher) throws InterruptedException
|
|
||||||
{
|
|
||||||
CloseStatus close = closeInfo.get();
|
|
||||||
assertThat(prefix + " close info", close, Matchers.notNullValue());
|
|
||||||
assertThat(prefix + " received close code", close.getCode(), Matchers.is(expectedCloseStatusCode));
|
|
||||||
assertThat(prefix + " received close reason", close.getReason(), reasonMatcher);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void assertErrorEvent(String prefix, Matcher<Throwable> throwableMatcher, Matcher<? super String> messageMatcher)
|
|
||||||
{
|
|
||||||
assertThat(prefix + " error event type", error.get(), throwableMatcher);
|
|
||||||
assertThat(prefix + " error event message", error.get().getMessage(), messageMatcher);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void assertNoErrorEvents(String prefix)
|
|
||||||
{
|
|
||||||
assertTrue(error.get() == null, prefix + " error event should not have occurred");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void assertNotClosed(String prefix)
|
|
||||||
{
|
|
||||||
assertTrue(closeLatch.getCount() > 0, prefix + " close event should not have occurred: got " + closeInfo.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void assertNotOpened(String prefix)
|
|
||||||
{
|
|
||||||
assertTrue(openLatch.getCount() > 0, prefix + " onOpen event should not have occurred");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void awaitCloseEvent(String prefix) throws InterruptedException
|
|
||||||
{
|
|
||||||
assertTrue(closeLatch.await(Timeouts.CLOSE_EVENT_MS, TimeUnit.MILLISECONDS), prefix + " onClose event should have occurred");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void awaitOpenEvent(String prefix) throws InterruptedException
|
|
||||||
{
|
|
||||||
assertTrue(openLatch.await(Timeouts.OPEN_EVENT_MS, TimeUnit.MILLISECONDS), prefix + " onOpen event should have occurred");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void awaitErrorEvent(String prefix) throws InterruptedException
|
|
||||||
{
|
|
||||||
assertTrue(errorLatch.await(Timeouts.CLOSE_EVENT_MS, TimeUnit.MILLISECONDS), prefix + " onError event should have occurred");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void onWSOpen(T session)
|
|
||||||
{
|
|
||||||
this.session = session;
|
|
||||||
if (LOG.isDebugEnabled())
|
|
||||||
{
|
|
||||||
LOG.debug("onWSOpen()");
|
|
||||||
}
|
|
||||||
this.openLatch.countDown();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void onWSClose(int statusCode, String reason)
|
|
||||||
{
|
|
||||||
if (LOG.isDebugEnabled())
|
|
||||||
{
|
|
||||||
LOG.debug("onWSClose({}, {})", statusCode, reason);
|
|
||||||
}
|
|
||||||
CloseStatus close = new CloseStatus(statusCode, reason);
|
|
||||||
if (closeInfo.compareAndSet(null, close) == false)
|
|
||||||
{
|
|
||||||
LOG.warn("onClose should only happen once - Original Close: " + closeInfo.get(), closeStack.get());
|
|
||||||
LOG.warn("onClose should only happen once - Extra/Excess Close: " + close, new Throwable("extra/excess"));
|
|
||||||
fail("onClose should only happen once!");
|
|
||||||
}
|
|
||||||
closeStack.compareAndSet(null, new Throwable("original"));
|
|
||||||
this.closeLatch.countDown();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void onWSError(Throwable cause)
|
|
||||||
{
|
|
||||||
if (LOG.isDebugEnabled())
|
|
||||||
{
|
|
||||||
LOG.debug("onWSError()", cause);
|
|
||||||
}
|
|
||||||
assertThat("Error must have value", cause, notNullValue());
|
|
||||||
if (error.compareAndSet(null, cause) == false)
|
|
||||||
{
|
|
||||||
LOG.warn("onError should only happen once - Original Cause", error.get());
|
|
||||||
LOG.warn("onError should only happen once - Extra/Excess Cause", cause);
|
|
||||||
fail("onError should only happen once!");
|
|
||||||
}
|
|
||||||
this.errorLatch.countDown();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -18,6 +18,10 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.websocket.core;
|
package org.eclipse.jetty.websocket.core;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import org.eclipse.jetty.io.ByteBufferPool;
|
import org.eclipse.jetty.io.ByteBufferPool;
|
||||||
import org.eclipse.jetty.io.MappedByteBufferPool;
|
import org.eclipse.jetty.io.MappedByteBufferPool;
|
||||||
import org.eclipse.jetty.util.BufferUtil;
|
import org.eclipse.jetty.util.BufferUtil;
|
||||||
|
@ -25,10 +29,6 @@ import org.eclipse.jetty.websocket.core.internal.Generator;
|
||||||
import org.eclipse.jetty.websocket.core.internal.Parser;
|
import org.eclipse.jetty.websocket.core.internal.Parser;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.hamcrest.Matchers.is;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
@ -106,7 +106,7 @@ public class GeneratorParserRoundtripTest
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate
|
// Validate
|
||||||
Frame txt = (Frame)capture.framesQueue.poll(1, TimeUnit.SECONDS);
|
Frame txt = capture.framesQueue.poll(1, TimeUnit.SECONDS);
|
||||||
assertTrue(txt.isMasked(), "Text.isMasked");
|
assertTrue(txt.isMasked(), "Text.isMasked");
|
||||||
assertThat("Text parsed", txt.getPayloadAsUTF8(), is(message));
|
assertThat("Text parsed", txt.getPayloadAsUTF8(), is(message));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,56 +0,0 @@
|
||||||
//
|
|
||||||
// ========================================================================
|
|
||||||
// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
// All rights reserved. This program and the accompanying materials
|
|
||||||
// are made available under the terms of the Eclipse Public License v1.0
|
|
||||||
// and Apache License v2.0 which accompanies this distribution.
|
|
||||||
//
|
|
||||||
// The Eclipse Public License is available at
|
|
||||||
// http://www.eclipse.org/legal/epl-v10.html
|
|
||||||
//
|
|
||||||
// The Apache License v2.0 is available at
|
|
||||||
// http://www.opensource.org/licenses/apache2.0.php
|
|
||||||
//
|
|
||||||
// You may elect to redistribute this code under either of these licenses.
|
|
||||||
// ========================================================================
|
|
||||||
//
|
|
||||||
|
|
||||||
package org.eclipse.jetty.websocket.core;
|
|
||||||
|
|
||||||
import org.eclipse.jetty.util.component.LifeCycle;
|
|
||||||
|
|
||||||
import java.util.function.Supplier;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simple {@link AutoCloseable} to allow Jetty {@link LifeCycle} components to
|
|
||||||
* be managed using {@code try-with-resources} techniques.
|
|
||||||
* <p>
|
|
||||||
* {@link LifeCycle#start()} occurs at constructor.
|
|
||||||
* {@link LifeCycle#stop()} occurs at {@link #close()}.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param <T> the {@link LifeCycle} to have resource managed
|
|
||||||
*/
|
|
||||||
public class LifeCycleScope<T extends LifeCycle> implements AutoCloseable, Supplier<T>
|
|
||||||
{
|
|
||||||
private final T lifecycle;
|
|
||||||
|
|
||||||
public LifeCycleScope(T lifecycle) throws Exception
|
|
||||||
{
|
|
||||||
this.lifecycle = lifecycle;
|
|
||||||
this.lifecycle.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() throws Exception
|
|
||||||
{
|
|
||||||
this.lifecycle.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public T get()
|
|
||||||
{
|
|
||||||
return this.lifecycle;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -43,7 +43,6 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
|
||||||
public class MessageHandlerTest
|
public class MessageHandlerTest
|
||||||
{
|
{
|
||||||
|
|
||||||
// Testing with 4 byte UTF8 character "\uD842\uDF9F"
|
// Testing with 4 byte UTF8 character "\uD842\uDF9F"
|
||||||
static String fourByteUtf8String = "\uD842\uDF9F";
|
static String fourByteUtf8String = "\uD842\uDF9F";
|
||||||
static byte[] fourByteUtf8Bytes = fourByteUtf8String.getBytes(StandardCharsets.UTF_8);
|
static byte[] fourByteUtf8Bytes = fourByteUtf8String.getBytes(StandardCharsets.UTF_8);
|
||||||
|
|
|
@ -29,11 +29,14 @@ import org.eclipse.jetty.util.log.Logger;
|
||||||
|
|
||||||
public class TestFrameHandler implements SynchronousFrameHandler
|
public class TestFrameHandler implements SynchronousFrameHandler
|
||||||
{
|
{
|
||||||
private static Logger LOG = Log.getLogger(SynchronousFrameHandler.class);
|
private static Logger LOG = Log.getLogger(TestFrameHandler.class);
|
||||||
|
|
||||||
private CoreSession session;
|
|
||||||
|
|
||||||
|
protected CoreSession session;
|
||||||
public BlockingQueue<Frame> receivedFrames = new BlockingArrayQueue<>();
|
public BlockingQueue<Frame> receivedFrames = new BlockingArrayQueue<>();
|
||||||
|
protected Throwable failure;
|
||||||
|
|
||||||
|
public CountDownLatch open = new CountDownLatch(1);
|
||||||
|
public CountDownLatch error = new CountDownLatch(1);
|
||||||
public CountDownLatch closed = new CountDownLatch(1);
|
public CountDownLatch closed = new CountDownLatch(1);
|
||||||
|
|
||||||
public CoreSession getCoreSession()
|
public CoreSession getCoreSession()
|
||||||
|
@ -46,19 +49,24 @@ public class TestFrameHandler implements SynchronousFrameHandler
|
||||||
return receivedFrames;
|
return receivedFrames;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Throwable getError()
|
||||||
|
{
|
||||||
|
return failure;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onOpen(CoreSession coreSession)
|
public void onOpen(CoreSession coreSession)
|
||||||
{
|
{
|
||||||
LOG.info("onOpen {}", coreSession);
|
LOG.info("onOpen {}", coreSession);
|
||||||
this.session = coreSession;
|
this.session = coreSession;
|
||||||
|
open.countDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFrame(Frame frame, Callback callback)
|
public void onFrame(Frame frame)
|
||||||
{
|
{
|
||||||
LOG.info("onFrame: " + OpCode.name(frame.getOpCode()) + ":" + BufferUtil.toDetailString(frame.getPayload()));
|
LOG.info("onFrame: " + OpCode.name(frame.getOpCode()) + ":" + BufferUtil.toDetailString(frame.getPayload()));
|
||||||
receivedFrames.offer(Frame.copy(frame));
|
receivedFrames.offer(Frame.copy(frame));
|
||||||
callback.succeeded();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -72,14 +80,27 @@ public class TestFrameHandler implements SynchronousFrameHandler
|
||||||
public void onError(Throwable cause)
|
public void onError(Throwable cause)
|
||||||
{
|
{
|
||||||
LOG.info("onError {} ", cause == null?null:cause.toString());
|
LOG.info("onError {} ", cause == null?null:cause.toString());
|
||||||
|
failure = cause;
|
||||||
|
error.countDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendText(String text)
|
public void sendText(String text)
|
||||||
{
|
{
|
||||||
Frame frame = new Frame(OpCode.TEXT);
|
LOG.info("sendText {} ", text);
|
||||||
frame.setFin(true);
|
Frame frame = new Frame(OpCode.TEXT, text);
|
||||||
frame.setPayload(text);
|
getCoreSession().sendFrame(frame, Callback.NOOP, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendFrame(Frame frame)
|
||||||
|
{
|
||||||
|
LOG.info("sendFrame {} ", frame);
|
||||||
|
getCoreSession().sendFrame(frame, Callback.NOOP, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendClose()
|
||||||
|
{
|
||||||
|
LOG.info("sendClose");
|
||||||
|
Frame frame = new Frame(OpCode.CLOSE);
|
||||||
getCoreSession().sendFrame(frame, Callback.NOOP, false);
|
getCoreSession().sendFrame(frame, Callback.NOOP, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,15 +18,16 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.websocket.core;
|
package org.eclipse.jetty.websocket.core;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.eclipse.jetty.http.HttpHeader;
|
import org.eclipse.jetty.http.HttpHeader;
|
||||||
import org.eclipse.jetty.io.ByteBufferPool;
|
import org.eclipse.jetty.io.ByteBufferPool;
|
||||||
|
import org.eclipse.jetty.io.MappedByteBufferPool;
|
||||||
import org.eclipse.jetty.util.DecoratedObjectFactory;
|
import org.eclipse.jetty.util.DecoratedObjectFactory;
|
||||||
import org.eclipse.jetty.websocket.core.server.Negotiation;
|
import org.eclipse.jetty.websocket.core.server.Negotiation;
|
||||||
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiator;
|
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiator;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class TestWebSocketNegotiator implements WebSocketNegotiator
|
public class TestWebSocketNegotiator implements WebSocketNegotiator
|
||||||
{
|
{
|
||||||
final DecoratedObjectFactory objectFactory;
|
final DecoratedObjectFactory objectFactory;
|
||||||
|
@ -34,6 +35,14 @@ public class TestWebSocketNegotiator implements WebSocketNegotiator
|
||||||
final ByteBufferPool bufferPool;
|
final ByteBufferPool bufferPool;
|
||||||
private final FrameHandler frameHandler;
|
private final FrameHandler frameHandler;
|
||||||
|
|
||||||
|
public TestWebSocketNegotiator(FrameHandler frameHandler)
|
||||||
|
{
|
||||||
|
this.objectFactory = new DecoratedObjectFactory();
|
||||||
|
this.extensionRegistry = new WebSocketExtensionRegistry();
|
||||||
|
this.bufferPool = new MappedByteBufferPool();
|
||||||
|
this.frameHandler = frameHandler;
|
||||||
|
}
|
||||||
|
|
||||||
public TestWebSocketNegotiator(DecoratedObjectFactory objectFactory, WebSocketExtensionRegistry extensionRegistry, ByteBufferPool bufferPool,
|
public TestWebSocketNegotiator(DecoratedObjectFactory objectFactory, WebSocketExtensionRegistry extensionRegistry, ByteBufferPool bufferPool,
|
||||||
FrameHandler frameHandler)
|
FrameHandler frameHandler)
|
||||||
{
|
{
|
||||||
|
|
|
@ -24,24 +24,13 @@ import java.util.concurrent.Exchanger;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
import org.eclipse.jetty.server.HttpConnectionFactory;
|
|
||||||
import org.eclipse.jetty.server.NetworkConnector;
|
|
||||||
import org.eclipse.jetty.server.Server;
|
|
||||||
import org.eclipse.jetty.server.ServerConnector;
|
|
||||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
|
||||||
import org.eclipse.jetty.util.BufferUtil;
|
import org.eclipse.jetty.util.BufferUtil;
|
||||||
import org.eclipse.jetty.util.Callback;
|
import org.eclipse.jetty.util.Callback;
|
||||||
import org.eclipse.jetty.util.DecoratedObjectFactory;
|
|
||||||
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
|
||||||
import org.eclipse.jetty.util.log.Log;
|
import org.eclipse.jetty.util.log.Log;
|
||||||
import org.eclipse.jetty.util.log.Logger;
|
import org.eclipse.jetty.util.log.Logger;
|
||||||
import org.eclipse.jetty.util.log.StacklessLogging;
|
import org.eclipse.jetty.util.log.StacklessLogging;
|
||||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
|
||||||
import org.eclipse.jetty.websocket.core.internal.Parser;
|
import org.eclipse.jetty.websocket.core.internal.Parser;
|
||||||
import org.eclipse.jetty.websocket.core.internal.WebSocketChannel;
|
import org.eclipse.jetty.websocket.core.internal.WebSocketChannel;
|
||||||
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiator;
|
|
||||||
import org.eclipse.jetty.websocket.core.server.WebSocketUpgradeHandler;
|
|
||||||
import org.eclipse.jetty.websocket.core.server.internal.RFC6455Handshaker;
|
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
@ -75,7 +64,7 @@ public class WebSocketOpenTest extends WebSocketTester
|
||||||
public void setup(BiFunction<FrameHandler.CoreSession,Callback,Void> onOpen) throws Exception
|
public void setup(BiFunction<FrameHandler.CoreSession,Callback,Void> onOpen) throws Exception
|
||||||
{
|
{
|
||||||
serverHandler = new TestFrameHandler(onOpen);
|
serverHandler = new TestFrameHandler(onOpen);
|
||||||
server = new WebSocketServer(0, serverHandler);
|
server = new WebSocketServer(serverHandler);
|
||||||
server.start();
|
server.start();
|
||||||
client = newClient(server.getLocalPort());
|
client = newClient(server.getLocalPort());
|
||||||
}
|
}
|
||||||
|
@ -95,7 +84,7 @@ public class WebSocketOpenTest extends WebSocketTester
|
||||||
assertThat(frame.getPayloadAsUTF8(),is("Hello"));
|
assertThat(frame.getPayloadAsUTF8(),is("Hello"));
|
||||||
|
|
||||||
client.getOutputStream().write(RawFrameBuilder.buildClose(new CloseStatus(CloseStatus.NORMAL), true));
|
client.getOutputStream().write(RawFrameBuilder.buildClose(new CloseStatus(CloseStatus.NORMAL), true));
|
||||||
assertTrue(server.handler.onClosed.await(5, TimeUnit.SECONDS));
|
assertTrue(serverHandler.onClosed.await(5, TimeUnit.SECONDS));
|
||||||
assertThat(serverHandler.closeStatus.getCode(),is(CloseStatus.NORMAL));
|
assertThat(serverHandler.closeStatus.getCode(),is(CloseStatus.NORMAL));
|
||||||
|
|
||||||
frame = receiveFrame(client.getInputStream());
|
frame = receiveFrame(client.getInputStream());
|
||||||
|
@ -115,10 +104,10 @@ public class WebSocketOpenTest extends WebSocketTester
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
assertTrue(server.handler.onError.await(5, TimeUnit.SECONDS));
|
assertTrue(serverHandler.onError.await(5, TimeUnit.SECONDS));
|
||||||
assertThat(serverHandler.error, notNullValue());
|
assertThat(serverHandler.error, notNullValue());
|
||||||
|
|
||||||
assertTrue(server.handler.onClosed.await(5, TimeUnit.SECONDS));
|
assertTrue(serverHandler.onClosed.await(5, TimeUnit.SECONDS));
|
||||||
assertThat(serverHandler.closeStatus.getCode(), is(CloseStatus.SERVER_ERROR));
|
assertThat(serverHandler.closeStatus.getCode(), is(CloseStatus.SERVER_ERROR));
|
||||||
|
|
||||||
Parser.ParsedFrame frame = receiveFrame(client.getInputStream());
|
Parser.ParsedFrame frame = receiveFrame(client.getInputStream());
|
||||||
|
@ -144,7 +133,7 @@ public class WebSocketOpenTest extends WebSocketTester
|
||||||
assertThat(new CloseStatus(frame).getCode(),is(CloseStatus.SHUTDOWN));
|
assertThat(new CloseStatus(frame).getCode(),is(CloseStatus.SHUTDOWN));
|
||||||
|
|
||||||
client.getOutputStream().write(RawFrameBuilder.buildClose(new CloseStatus(CloseStatus.NORMAL), true));
|
client.getOutputStream().write(RawFrameBuilder.buildClose(new CloseStatus(CloseStatus.NORMAL), true));
|
||||||
assertTrue(server.handler.onClosed.await(5, TimeUnit.SECONDS));
|
assertTrue(serverHandler.onClosed.await(5, TimeUnit.SECONDS));
|
||||||
assertThat(serverHandler.closeStatus.getCode(),is(CloseStatus.NORMAL));
|
assertThat(serverHandler.closeStatus.getCode(),is(CloseStatus.NORMAL));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,12 +169,12 @@ public class WebSocketOpenTest extends WebSocketTester
|
||||||
|
|
||||||
// But cannot receive
|
// But cannot receive
|
||||||
client.getOutputStream().write(RawFrameBuilder.buildClose(new CloseStatus(CloseStatus.NORMAL), true));
|
client.getOutputStream().write(RawFrameBuilder.buildClose(new CloseStatus(CloseStatus.NORMAL), true));
|
||||||
assertFalse(server.handler.onClosed.await(1, TimeUnit.SECONDS));
|
assertFalse(serverHandler.onClosed.await(1, TimeUnit.SECONDS));
|
||||||
|
|
||||||
// Can't demand until open
|
// Can't demand until open
|
||||||
assertThrows(Throwable.class, () -> session.demand(1));
|
assertThrows(Throwable.class, () -> session.demand(1));
|
||||||
client.getOutputStream().write(RawFrameBuilder.buildClose(new CloseStatus(CloseStatus.NORMAL), true));
|
client.getOutputStream().write(RawFrameBuilder.buildClose(new CloseStatus(CloseStatus.NORMAL), true));
|
||||||
assertFalse(server.handler.onClosed.await(1, TimeUnit.SECONDS));
|
assertFalse(serverHandler.onClosed.await(1, TimeUnit.SECONDS));
|
||||||
|
|
||||||
// Succeeded moves to OPEN state and still does not read CLOSE frame
|
// Succeeded moves to OPEN state and still does not read CLOSE frame
|
||||||
onOpenCallback.succeeded();
|
onOpenCallback.succeeded();
|
||||||
|
@ -194,10 +183,10 @@ public class WebSocketOpenTest extends WebSocketTester
|
||||||
// Demand start receiving frames
|
// Demand start receiving frames
|
||||||
session.demand(1);
|
session.demand(1);
|
||||||
client.getOutputStream().write(RawFrameBuilder.buildClose(new CloseStatus(CloseStatus.NORMAL), true));
|
client.getOutputStream().write(RawFrameBuilder.buildClose(new CloseStatus(CloseStatus.NORMAL), true));
|
||||||
assertTrue(server.handler.onClosed.await(5, TimeUnit.SECONDS));
|
assertTrue(serverHandler.onClosed.await(5, TimeUnit.SECONDS));
|
||||||
|
|
||||||
// Closed handled normally
|
// Closed handled normally
|
||||||
assertTrue(server.handler.onClosed.await(5, TimeUnit.SECONDS));
|
assertTrue(serverHandler.onClosed.await(5, TimeUnit.SECONDS));
|
||||||
assertThat(serverHandler.closeStatus.getCode(),is(CloseStatus.NORMAL));
|
assertThat(serverHandler.closeStatus.getCode(),is(CloseStatus.NORMAL));
|
||||||
frame = receiveFrame(client.getInputStream());
|
frame = receiveFrame(client.getInputStream());
|
||||||
assertThat(frame.getOpCode(),is(OpCode.CLOSE));
|
assertThat(frame.getOpCode(),is(OpCode.CLOSE));
|
||||||
|
@ -302,70 +291,5 @@ public class WebSocketOpenTest extends WebSocketTester
|
||||||
|
|
||||||
session.sendFrame(frame, callback, false);
|
session.sendFrame(frame, callback, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static class WebSocketServer extends AbstractLifeCycle
|
|
||||||
{
|
|
||||||
private static Logger LOG = Log.getLogger(WebSocketServer.class);
|
|
||||||
private final Server server;
|
|
||||||
private final TestFrameHandler handler;
|
|
||||||
|
|
||||||
public void doStart() throws Exception
|
|
||||||
{
|
|
||||||
server.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void doStop() throws Exception
|
|
||||||
{
|
|
||||||
server.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getLocalPort()
|
|
||||||
{
|
|
||||||
return server.getBean(NetworkConnector.class).getLocalPort();
|
|
||||||
}
|
|
||||||
|
|
||||||
public WebSocketServer(int port, TestFrameHandler frameHandler)
|
|
||||||
{
|
|
||||||
this.handler = frameHandler;
|
|
||||||
server = new Server();
|
|
||||||
server.getBean(QueuedThreadPool.class).setName("WSCoreServer");
|
|
||||||
ServerConnector connector = new ServerConnector(server, new HttpConnectionFactory());
|
|
||||||
|
|
||||||
connector.addBean(new RFC6455Handshaker());
|
|
||||||
connector.setPort(port);
|
|
||||||
connector.setIdleTimeout(1000000);
|
|
||||||
server.addConnector(connector);
|
|
||||||
|
|
||||||
ContextHandler context = new ContextHandler("/");
|
|
||||||
server.setHandler(context);
|
|
||||||
WebSocketNegotiator negotiator = new TestWebSocketNegotiator(new DecoratedObjectFactory(), new WebSocketExtensionRegistry(),
|
|
||||||
connector.getByteBufferPool(), frameHandler);
|
|
||||||
|
|
||||||
WebSocketUpgradeHandler upgradeHandler = new TestWebSocketUpgradeHandler(negotiator);
|
|
||||||
context.setHandler(upgradeHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void sendFrame(Frame frame)
|
|
||||||
{
|
|
||||||
handler.getCoreSession().sendFrame(frame, NOOP, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void sendText(String text)
|
|
||||||
{
|
|
||||||
LOG.info("sending {}...", text);
|
|
||||||
WebSocketOpenTest.TestFrameHandler.sendText(handler.session, text);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void close()
|
|
||||||
{
|
|
||||||
handler.getCoreSession().close(CloseStatus.NORMAL, "WebSocketServer Initiated Close", Callback.NOOP);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isOpen()
|
|
||||||
{
|
|
||||||
return handler.getCoreSession().isOutputOpen();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// All rights reserved. This program and the accompanying materials
|
||||||
|
// are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
// and Apache License v2.0 which accompanies this distribution.
|
||||||
|
//
|
||||||
|
// The Eclipse Public License is available at
|
||||||
|
// http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
//
|
||||||
|
// The Apache License v2.0 is available at
|
||||||
|
// http://www.opensource.org/licenses/apache2.0.php
|
||||||
|
//
|
||||||
|
// You may elect to redistribute this code under either of these licenses.
|
||||||
|
// ========================================================================
|
||||||
|
//
|
||||||
|
|
||||||
|
package org.eclipse.jetty.websocket.core;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.server.NetworkConnector;
|
||||||
|
import org.eclipse.jetty.server.Server;
|
||||||
|
import org.eclipse.jetty.server.ServerConnector;
|
||||||
|
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||||
|
import org.eclipse.jetty.util.log.Log;
|
||||||
|
import org.eclipse.jetty.util.log.Logger;
|
||||||
|
import org.eclipse.jetty.websocket.core.server.Negotiation;
|
||||||
|
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiator;
|
||||||
|
import org.eclipse.jetty.websocket.core.server.WebSocketUpgradeHandler;
|
||||||
|
|
||||||
|
public class WebSocketServer
|
||||||
|
{
|
||||||
|
private static Logger LOG = Log.getLogger(WebSocketServer.class);
|
||||||
|
private final Server server;
|
||||||
|
|
||||||
|
public void start() throws Exception
|
||||||
|
{
|
||||||
|
server.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop() throws Exception
|
||||||
|
{
|
||||||
|
server.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getLocalPort()
|
||||||
|
{
|
||||||
|
return server.getBean(NetworkConnector.class).getLocalPort();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Server getServer()
|
||||||
|
{
|
||||||
|
return server;
|
||||||
|
}
|
||||||
|
|
||||||
|
public WebSocketServer(FrameHandler frameHandler)
|
||||||
|
{
|
||||||
|
this(new DefaultNegotiator(frameHandler));
|
||||||
|
}
|
||||||
|
|
||||||
|
public WebSocketServer(WebSocketNegotiator negotiator)
|
||||||
|
{
|
||||||
|
server = new Server();
|
||||||
|
ServerConnector connector = new ServerConnector(server);
|
||||||
|
connector.setPort(0);
|
||||||
|
server.addConnector(connector);
|
||||||
|
|
||||||
|
ContextHandler context = new ContextHandler("/");
|
||||||
|
server.setHandler(context);
|
||||||
|
|
||||||
|
WebSocketUpgradeHandler upgradeHandler = new WebSocketUpgradeHandler(negotiator);
|
||||||
|
context.setHandler(upgradeHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class DefaultNegotiator extends WebSocketNegotiator.AbstractNegotiator
|
||||||
|
{
|
||||||
|
private final FrameHandler frameHandler;
|
||||||
|
|
||||||
|
public DefaultNegotiator(FrameHandler frameHandler)
|
||||||
|
{
|
||||||
|
this.frameHandler = frameHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FrameHandler negotiate(Negotiation negotiation) throws IOException
|
||||||
|
{
|
||||||
|
List<String> offeredSubprotocols = negotiation.getOfferedSubprotocols();
|
||||||
|
if (!offeredSubprotocols.isEmpty())
|
||||||
|
negotiation.setSubprotocol(offeredSubprotocols.get(0));
|
||||||
|
|
||||||
|
return frameHandler;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -34,6 +34,8 @@ import org.eclipse.jetty.util.B64Code;
|
||||||
import org.eclipse.jetty.util.BufferUtil;
|
import org.eclipse.jetty.util.BufferUtil;
|
||||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||||
import org.eclipse.jetty.websocket.core.internal.Parser;
|
import org.eclipse.jetty.websocket.core.internal.Parser;
|
||||||
|
import org.junit.jupiter.api.AfterAll;
|
||||||
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
@ -43,9 +45,24 @@ import static org.hamcrest.Matchers.startsWith;
|
||||||
public class WebSocketTester
|
public class WebSocketTester
|
||||||
{
|
{
|
||||||
private static String NON_RANDOM_KEY = new String(B64Code.encode("0123456701234567".getBytes()));
|
private static String NON_RANDOM_KEY = new String(B64Code.encode("0123456701234567".getBytes()));
|
||||||
|
private static SslContextFactory sslContextFactory;
|
||||||
protected ByteBufferPool bufferPool;
|
protected ByteBufferPool bufferPool;
|
||||||
protected Parser parser;
|
protected Parser parser;
|
||||||
|
|
||||||
|
@BeforeAll
|
||||||
|
public static void startSslContextFactory() throws Exception
|
||||||
|
{
|
||||||
|
sslContextFactory = new SslContextFactory(true);
|
||||||
|
sslContextFactory.setEndpointIdentificationAlgorithm("");
|
||||||
|
sslContextFactory.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterAll
|
||||||
|
public static void stopSslContextFactory() throws Exception
|
||||||
|
{
|
||||||
|
sslContextFactory.stop();
|
||||||
|
}
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void before()
|
public void before()
|
||||||
{
|
{
|
||||||
|
@ -55,24 +72,26 @@ public class WebSocketTester
|
||||||
|
|
||||||
protected Socket newClient(int port) throws Exception
|
protected Socket newClient(int port) throws Exception
|
||||||
{
|
{
|
||||||
return newClient(port, false);
|
return newClient(port, false, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Socket newClient(int port, boolean tls) throws Exception
|
protected Socket newClient(int port, boolean tls) throws Exception
|
||||||
|
{
|
||||||
|
return newClient(port, tls, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Socket newClient(int port, String extensions) throws Exception
|
||||||
|
{
|
||||||
|
return newClient(port, false, extensions);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Socket newClient(int port, boolean tls, String extensions) throws Exception
|
||||||
{
|
{
|
||||||
Socket client;
|
Socket client;
|
||||||
|
|
||||||
if (!tls)
|
if (!tls)
|
||||||
{
|
|
||||||
client = new Socket();
|
client = new Socket();
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
SslContextFactory sslContextFactory = new SslContextFactory(true);
|
|
||||||
sslContextFactory.start();
|
|
||||||
client = sslContextFactory.newSslSocket();
|
client = sslContextFactory.newSslSocket();
|
||||||
sslContextFactory.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
client.connect(new InetSocketAddress("127.0.0.1", port));
|
client.connect(new InetSocketAddress("127.0.0.1", port));
|
||||||
|
|
||||||
|
@ -85,6 +104,8 @@ public class WebSocketTester
|
||||||
fields.add(HttpHeader.PRAGMA, "no-cache");
|
fields.add(HttpHeader.PRAGMA, "no-cache");
|
||||||
fields.add(HttpHeader.CACHE_CONTROL, "no-cache");
|
fields.add(HttpHeader.CACHE_CONTROL, "no-cache");
|
||||||
fields.add(HttpHeader.SEC_WEBSOCKET_SUBPROTOCOL, "test");
|
fields.add(HttpHeader.SEC_WEBSOCKET_SUBPROTOCOL, "test");
|
||||||
|
if (extensions != null)
|
||||||
|
fields.add(HttpHeader.SEC_WEBSOCKET_EXTENSIONS, extensions);
|
||||||
|
|
||||||
client.getOutputStream().write(("GET / HTTP/1.1\r\n" + fields.toString()).getBytes(StandardCharsets.ISO_8859_1));
|
client.getOutputStream().write(("GET / HTTP/1.1\r\n" + fields.toString()).getBytes(StandardCharsets.ISO_8859_1));
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,6 @@ import org.eclipse.jetty.websocket.core.TestUpgradeHandler;
|
||||||
import org.eclipse.jetty.websocket.core.WebSocketExtensionRegistry;
|
import org.eclipse.jetty.websocket.core.WebSocketExtensionRegistry;
|
||||||
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiator;
|
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiator;
|
||||||
import org.eclipse.jetty.websocket.core.server.WebSocketUpgradeHandler;
|
import org.eclipse.jetty.websocket.core.server.WebSocketUpgradeHandler;
|
||||||
import org.eclipse.jetty.websocket.core.server.internal.RFC6455Handshaker;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WebSocket Server for use with <a href="https://github.com/crossbario/autobahn-testsuite">autobahn websocket testsuite</a> (wstest).
|
* WebSocket Server for use with <a href="https://github.com/crossbario/autobahn-testsuite">autobahn websocket testsuite</a> (wstest).
|
||||||
|
@ -78,9 +77,7 @@ public class AutobahnWebSocketServer
|
||||||
server,
|
server,
|
||||||
new HttpConnectionFactory()
|
new HttpConnectionFactory()
|
||||||
);
|
);
|
||||||
connector.addBean(new RFC6455Handshaker());
|
|
||||||
|
|
||||||
//connector.setPort(9001);
|
|
||||||
connector.setIdleTimeout(10000);
|
connector.setIdleTimeout(10000);
|
||||||
server.addConnector(connector);
|
server.addConnector(connector);
|
||||||
|
|
||||||
|
|
|
@ -19,33 +19,19 @@
|
||||||
package org.eclipse.jetty.websocket.core.client;
|
package org.eclipse.jetty.websocket.core.client;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.concurrent.BlockingQueue;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.Future;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import org.eclipse.jetty.server.HttpConnectionFactory;
|
|
||||||
import org.eclipse.jetty.server.NetworkConnector;
|
|
||||||
import org.eclipse.jetty.server.Server;
|
|
||||||
import org.eclipse.jetty.server.ServerConnector;
|
|
||||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
|
||||||
import org.eclipse.jetty.util.BufferUtil;
|
import org.eclipse.jetty.util.BufferUtil;
|
||||||
import org.eclipse.jetty.util.Callback;
|
import org.eclipse.jetty.util.Callback;
|
||||||
import org.eclipse.jetty.util.DecoratedObjectFactory;
|
|
||||||
import org.eclipse.jetty.util.log.Log;
|
import org.eclipse.jetty.util.log.Log;
|
||||||
import org.eclipse.jetty.util.log.Logger;
|
import org.eclipse.jetty.util.log.Logger;
|
||||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
|
||||||
import org.eclipse.jetty.websocket.core.CloseStatus;
|
|
||||||
import org.eclipse.jetty.websocket.core.Frame;
|
import org.eclipse.jetty.websocket.core.Frame;
|
||||||
import org.eclipse.jetty.websocket.core.FrameHandler;
|
import org.eclipse.jetty.websocket.core.FrameHandler.CoreSession;
|
||||||
import org.eclipse.jetty.websocket.core.OpCode;
|
import org.eclipse.jetty.websocket.core.OpCode;
|
||||||
import org.eclipse.jetty.websocket.core.TestFrameHandler;
|
import org.eclipse.jetty.websocket.core.TestFrameHandler;
|
||||||
import org.eclipse.jetty.websocket.core.TestWebSocketNegotiator;
|
import org.eclipse.jetty.websocket.core.WebSocketServer;
|
||||||
import org.eclipse.jetty.websocket.core.TestWebSocketUpgradeHandler;
|
|
||||||
import org.eclipse.jetty.websocket.core.WebSocketExtensionRegistry;
|
|
||||||
import org.eclipse.jetty.websocket.core.internal.WebSocketChannel;
|
import org.eclipse.jetty.websocket.core.internal.WebSocketChannel;
|
||||||
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiator;
|
|
||||||
import org.eclipse.jetty.websocket.core.server.WebSocketUpgradeHandler;
|
|
||||||
import org.eclipse.jetty.websocket.core.server.internal.RFC6455Handshaker;
|
|
||||||
import org.hamcrest.Matchers;
|
import org.hamcrest.Matchers;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
@ -62,46 +48,51 @@ public class WebSocketClientServerTest
|
||||||
private static Logger LOG = Log.getLogger(WebSocketClientServerTest.class);
|
private static Logger LOG = Log.getLogger(WebSocketClientServerTest.class);
|
||||||
|
|
||||||
private WebSocketServer server;
|
private WebSocketServer server;
|
||||||
private WebSocketClient client;
|
private TestFrameHandler serverHandler;
|
||||||
|
private URI serverUri;
|
||||||
|
|
||||||
|
private WebSocketCoreClient client;
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void setup() throws Exception
|
public void setup() throws Exception
|
||||||
{
|
{
|
||||||
|
serverHandler = new TestFrameHandler();
|
||||||
|
server = new WebSocketServer(serverHandler);
|
||||||
|
server.start();
|
||||||
|
serverUri = new URI("ws://localhost:" + server.getLocalPort());
|
||||||
|
|
||||||
|
client = new WebSocketCoreClient();
|
||||||
|
client.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testHello() throws Exception
|
public void testHello() throws Exception
|
||||||
{
|
{
|
||||||
TestFrameHandler serverHandler = new TestFrameHandler();
|
|
||||||
TestFrameHandler clientHandler = new TestFrameHandler();
|
TestFrameHandler clientHandler = new TestFrameHandler();
|
||||||
|
CompletableFuture<CoreSession> connect = client.connect(clientHandler, serverUri);
|
||||||
server = new WebSocketServer(0, serverHandler);
|
connect.get(5, TimeUnit.SECONDS);
|
||||||
server.start();
|
|
||||||
client = new WebSocketClient("localhost", server.getLocalPort(), clientHandler);
|
|
||||||
client.start();
|
|
||||||
|
|
||||||
String message = "hello world";
|
String message = "hello world";
|
||||||
client.sendText(message);
|
clientHandler.sendText(message);
|
||||||
Frame recv = server.getFrames().poll(5, TimeUnit.SECONDS);
|
Frame recv = serverHandler.getFrames().poll(5, TimeUnit.SECONDS);
|
||||||
assertNotNull(recv);
|
assertNotNull(recv);
|
||||||
assertThat(recv.getPayloadAsUTF8(), Matchers.equalTo(message));
|
assertThat(recv.getPayloadAsUTF8(), Matchers.equalTo(message));
|
||||||
|
|
||||||
message = "back at ya!";
|
message = "back at ya!";
|
||||||
server.sendText(message);
|
serverHandler.sendText(message);
|
||||||
recv = client.getFrames().poll(5, TimeUnit.SECONDS);
|
recv = clientHandler.getFrames().poll(5, TimeUnit.SECONDS);
|
||||||
assertNotNull(recv);
|
assertNotNull(recv);
|
||||||
assertThat(recv.getPayloadAsUTF8(), Matchers.equalTo(message));
|
assertThat(recv.getPayloadAsUTF8(), Matchers.equalTo(message));
|
||||||
|
|
||||||
client.close();
|
clientHandler.sendClose();
|
||||||
|
|
||||||
assertTrue(server.handler.closed.await(5, TimeUnit.SECONDS));
|
assertTrue(serverHandler.closed.await(5, TimeUnit.SECONDS));
|
||||||
assertTrue(client.handler.closed.await(5, TimeUnit.SECONDS));
|
assertTrue(clientHandler.closed.await(5, TimeUnit.SECONDS));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testClientSocketClosedInCloseHandshake() throws Exception
|
public void testClientSocketClosedInCloseHandshake() throws Exception
|
||||||
{
|
{
|
||||||
TestFrameHandler serverHandler = new TestFrameHandler();
|
|
||||||
TestFrameHandler clientHandler = new TestFrameHandler()
|
TestFrameHandler clientHandler = new TestFrameHandler()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
|
@ -121,160 +112,37 @@ public class WebSocketClientServerTest
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
CompletableFuture<CoreSession> connect = client.connect(clientHandler, serverUri);
|
||||||
server = new WebSocketServer(0, serverHandler);
|
connect.get(5, TimeUnit.SECONDS);
|
||||||
server.start();
|
|
||||||
client = new WebSocketClient("localhost", server.getLocalPort(), clientHandler);
|
|
||||||
client.start();
|
|
||||||
|
|
||||||
String message = "hello world";
|
String message = "hello world";
|
||||||
server.sendText(message);
|
serverHandler.sendText(message);
|
||||||
Frame recv = client.getFrames().poll(5, TimeUnit.SECONDS);
|
Frame recv = clientHandler.getFrames().poll(5, TimeUnit.SECONDS);
|
||||||
assertNotNull(recv);
|
assertNotNull(recv);
|
||||||
assertThat(recv.getPayloadAsUTF8(), Matchers.equalTo(message));
|
assertThat(recv.getPayloadAsUTF8(), Matchers.equalTo(message));
|
||||||
|
|
||||||
server.close();
|
serverHandler.sendClose();
|
||||||
|
|
||||||
assertTrue(server.handler.closed.await(5, TimeUnit.SECONDS));
|
assertTrue(serverHandler.closed.await(5, TimeUnit.SECONDS));
|
||||||
assertTrue(client.handler.closed.await(5, TimeUnit.SECONDS));
|
assertTrue(clientHandler.closed.await(5, TimeUnit.SECONDS));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testClientSocketClosed() throws Exception
|
public void testClientSocketClosed() throws Exception
|
||||||
{
|
{
|
||||||
TestFrameHandler serverHandler = new TestFrameHandler();
|
|
||||||
TestFrameHandler clientHandler = new TestFrameHandler();
|
TestFrameHandler clientHandler = new TestFrameHandler();
|
||||||
|
CompletableFuture<CoreSession> connect = client.connect(clientHandler, serverUri);
|
||||||
server = new WebSocketServer(0, serverHandler);
|
connect.get(5, TimeUnit.SECONDS);
|
||||||
server.start();
|
|
||||||
client = new WebSocketClient("localhost", server.getLocalPort(), clientHandler);
|
|
||||||
client.start();
|
|
||||||
|
|
||||||
String message = "hello world";
|
String message = "hello world";
|
||||||
client.sendText(message);
|
clientHandler.sendText(message);
|
||||||
Frame recv = server.getFrames().poll(2, TimeUnit.SECONDS);
|
Frame recv = serverHandler.getFrames().poll(2, TimeUnit.SECONDS);
|
||||||
assertNotNull(recv);
|
assertNotNull(recv);
|
||||||
assertThat(recv.getPayloadAsUTF8(), Matchers.equalTo(message));
|
assertThat(recv.getPayloadAsUTF8(), Matchers.equalTo(message));
|
||||||
|
|
||||||
((WebSocketChannel)client.handler.getCoreSession()).getConnection().getEndPoint().close();
|
((WebSocketChannel)clientHandler.getCoreSession()).getConnection().getEndPoint().close();
|
||||||
|
|
||||||
assertTrue(client.handler.closed.await(5, TimeUnit.SECONDS));
|
|
||||||
assertTrue(server.handler.closed.await(5, TimeUnit.SECONDS));
|
|
||||||
}
|
|
||||||
|
|
||||||
static class WebSocketClient
|
|
||||||
{
|
|
||||||
private static Logger LOG = Log.getLogger(WebSocketClient.class);
|
|
||||||
|
|
||||||
private URI baseWebSocketUri;
|
|
||||||
private WebSocketCoreClient client;
|
|
||||||
private TestFrameHandler handler;
|
|
||||||
|
|
||||||
public WebSocketClient(String hostname, int port, TestFrameHandler frameHandler) throws Exception
|
|
||||||
{
|
|
||||||
this.baseWebSocketUri = new URI("ws://" + hostname + ":" + port);
|
|
||||||
this.client = new WebSocketCoreClient();
|
|
||||||
this.handler = frameHandler;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void start() throws Exception
|
|
||||||
{
|
|
||||||
ClientUpgradeRequest request = ClientUpgradeRequest.from(client, baseWebSocketUri.resolve("/test"), handler);
|
|
||||||
request.setSubProtocols("test");
|
|
||||||
this.client.start();
|
|
||||||
Future<FrameHandler.CoreSession> response = client.connect(request);
|
|
||||||
response.get(5, TimeUnit.SECONDS);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void sendFrame(Frame frame)
|
|
||||||
{
|
|
||||||
handler.getCoreSession().sendFrame(frame, Callback.NOOP, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void sendText(String line)
|
|
||||||
{
|
|
||||||
LOG.info("sending {}...", line);
|
|
||||||
handler.sendText(line);
|
|
||||||
}
|
|
||||||
|
|
||||||
public BlockingQueue<Frame> getFrames()
|
|
||||||
{
|
|
||||||
return handler.getFrames();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void close()
|
|
||||||
{
|
|
||||||
handler.getCoreSession().close(CloseStatus.NORMAL, "WebSocketClient Initiated Close", Callback.NOOP);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isOpen()
|
|
||||||
{
|
|
||||||
return handler.getCoreSession().isOutputOpen();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class WebSocketServer
|
|
||||||
{
|
|
||||||
private static Logger LOG = Log.getLogger(WebSocketServer.class);
|
|
||||||
private final Server server;
|
|
||||||
private final TestFrameHandler handler;
|
|
||||||
|
|
||||||
public void start() throws Exception
|
|
||||||
{
|
|
||||||
server.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getLocalPort()
|
|
||||||
{
|
|
||||||
return server.getBean(NetworkConnector.class).getLocalPort();
|
|
||||||
}
|
|
||||||
|
|
||||||
public WebSocketServer(int port, TestFrameHandler frameHandler)
|
|
||||||
{
|
|
||||||
this.handler = frameHandler;
|
|
||||||
server = new Server();
|
|
||||||
server.getBean(QueuedThreadPool.class).setName("WSCoreServer");
|
|
||||||
ServerConnector connector = new ServerConnector(server, new HttpConnectionFactory());
|
|
||||||
|
|
||||||
connector.addBean(new RFC6455Handshaker());
|
|
||||||
connector.setPort(port);
|
|
||||||
connector.setIdleTimeout(1000000);
|
|
||||||
server.addConnector(connector);
|
|
||||||
|
|
||||||
ContextHandler context = new ContextHandler("/");
|
|
||||||
server.setHandler(context);
|
|
||||||
WebSocketNegotiator negotiator = new TestWebSocketNegotiator(new DecoratedObjectFactory(), new WebSocketExtensionRegistry(),
|
|
||||||
connector.getByteBufferPool(), frameHandler);
|
|
||||||
|
|
||||||
WebSocketUpgradeHandler upgradeHandler = new TestWebSocketUpgradeHandler(negotiator);
|
|
||||||
context.setHandler(upgradeHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void sendFrame(Frame frame)
|
|
||||||
{
|
|
||||||
handler.getCoreSession().sendFrame(frame, Callback.NOOP, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void sendText(String line)
|
|
||||||
{
|
|
||||||
LOG.info("sending {}...", line);
|
|
||||||
handler.sendText(line);
|
|
||||||
}
|
|
||||||
|
|
||||||
public BlockingQueue<Frame> getFrames()
|
|
||||||
{
|
|
||||||
return handler.getFrames();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void close()
|
|
||||||
{
|
|
||||||
handler.getCoreSession().close(CloseStatus.NORMAL, "WebSocketServer Initiated Close", Callback.NOOP);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isOpen()
|
|
||||||
{
|
|
||||||
return handler.getCoreSession().isOutputOpen();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
assertTrue(clientHandler.closed.await(5, TimeUnit.SECONDS));
|
||||||
|
assertTrue(serverHandler.closed.await(5, TimeUnit.SECONDS));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,10 +44,8 @@ import org.eclipse.jetty.websocket.core.Behavior;
|
||||||
import org.eclipse.jetty.websocket.core.CapturedHexPayloads;
|
import org.eclipse.jetty.websocket.core.CapturedHexPayloads;
|
||||||
import org.eclipse.jetty.websocket.core.ExtensionConfig;
|
import org.eclipse.jetty.websocket.core.ExtensionConfig;
|
||||||
import org.eclipse.jetty.websocket.core.Frame;
|
import org.eclipse.jetty.websocket.core.Frame;
|
||||||
import org.eclipse.jetty.websocket.core.IncomingFrames;
|
|
||||||
import org.eclipse.jetty.websocket.core.IncomingFramesCapture;
|
import org.eclipse.jetty.websocket.core.IncomingFramesCapture;
|
||||||
import org.eclipse.jetty.websocket.core.OpCode;
|
import org.eclipse.jetty.websocket.core.OpCode;
|
||||||
import org.eclipse.jetty.websocket.core.OutgoingFrames;
|
|
||||||
import org.eclipse.jetty.websocket.core.OutgoingNetworkBytesCapture;
|
import org.eclipse.jetty.websocket.core.OutgoingNetworkBytesCapture;
|
||||||
import org.eclipse.jetty.websocket.core.WebSocketExtensionRegistry;
|
import org.eclipse.jetty.websocket.core.WebSocketExtensionRegistry;
|
||||||
import org.eclipse.jetty.websocket.core.internal.ExtensionStack;
|
import org.eclipse.jetty.websocket.core.internal.ExtensionStack;
|
||||||
|
@ -388,32 +386,24 @@ public class DeflateFrameExtensionTest extends AbstractExtensionTest
|
||||||
serverExtension.setWebSocketChannel(channelWithMaxMessageSize(maxMessageSize));
|
serverExtension.setWebSocketChannel(channelWithMaxMessageSize(maxMessageSize));
|
||||||
|
|
||||||
// Chain the next element to decompress.
|
// Chain the next element to decompress.
|
||||||
clientExtension.setNextOutgoingFrames(new OutgoingFrames()
|
clientExtension.setNextOutgoingFrames((frame, callback, batch) ->
|
||||||
{
|
{
|
||||||
@Override
|
LOG.debug("outgoingFrame({})", frame);
|
||||||
public void sendFrame(Frame frame, Callback callback, boolean batch)
|
serverExtension.onFrame(frame, callback);
|
||||||
{
|
callback.succeeded();
|
||||||
LOG.debug("outgoingFrame({})", frame);
|
|
||||||
serverExtension.onFrame(frame, callback);
|
|
||||||
callback.succeeded();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
final ByteArrayOutputStream result = new ByteArrayOutputStream(input.length);
|
final ByteArrayOutputStream result = new ByteArrayOutputStream(input.length);
|
||||||
serverExtension.setNextIncomingFrames(new IncomingFrames()
|
serverExtension.setNextIncomingFrames((frame, callback) ->
|
||||||
{
|
{
|
||||||
@Override
|
LOG.debug("incomingFrame({})", frame);
|
||||||
public void onFrame(Frame frame, Callback callback)
|
try
|
||||||
{
|
{
|
||||||
LOG.debug("incomingFrame({})", frame);
|
result.write(BufferUtil.toArray(frame.getPayload()));
|
||||||
try
|
}
|
||||||
{
|
catch (IOException x)
|
||||||
result.write(BufferUtil.toArray(frame.getPayload()));
|
{
|
||||||
}
|
throw new RuntimeIOException(x);
|
||||||
catch (IOException x)
|
|
||||||
{
|
|
||||||
throw new RuntimeIOException(x);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -19,36 +19,21 @@
|
||||||
package org.eclipse.jetty.websocket.core.extensions;
|
package org.eclipse.jetty.websocket.core.extensions;
|
||||||
|
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.util.concurrent.BlockingQueue;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import org.eclipse.jetty.server.HttpConnectionFactory;
|
|
||||||
import org.eclipse.jetty.server.NetworkConnector;
|
|
||||||
import org.eclipse.jetty.server.Server;
|
|
||||||
import org.eclipse.jetty.server.ServerConnector;
|
|
||||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
|
||||||
import org.eclipse.jetty.util.Callback;
|
|
||||||
import org.eclipse.jetty.util.DecoratedObjectFactory;
|
|
||||||
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
|
||||||
import org.eclipse.jetty.util.log.Log;
|
|
||||||
import org.eclipse.jetty.util.log.Logger;
|
|
||||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
|
||||||
import org.eclipse.jetty.websocket.core.CloseStatus;
|
import org.eclipse.jetty.websocket.core.CloseStatus;
|
||||||
import org.eclipse.jetty.websocket.core.Frame;
|
import org.eclipse.jetty.websocket.core.Frame;
|
||||||
import org.eclipse.jetty.websocket.core.OpCode;
|
import org.eclipse.jetty.websocket.core.OpCode;
|
||||||
import org.eclipse.jetty.websocket.core.RawFrameBuilder;
|
import org.eclipse.jetty.websocket.core.RawFrameBuilder;
|
||||||
import org.eclipse.jetty.websocket.core.TestFrameHandler;
|
import org.eclipse.jetty.websocket.core.TestFrameHandler;
|
||||||
import org.eclipse.jetty.websocket.core.TestWebSocketNegotiator;
|
import org.eclipse.jetty.websocket.core.TestWebSocketNegotiator;
|
||||||
import org.eclipse.jetty.websocket.core.TestWebSocketUpgradeHandler;
|
import org.eclipse.jetty.websocket.core.WebSocketServer;
|
||||||
import org.eclipse.jetty.websocket.core.WebSocketExtensionRegistry;
|
|
||||||
import org.eclipse.jetty.websocket.core.WebSocketTester;
|
import org.eclipse.jetty.websocket.core.WebSocketTester;
|
||||||
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiator;
|
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiator;
|
||||||
import org.eclipse.jetty.websocket.core.server.WebSocketServerTest;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.eclipse.jetty.websocket.core.server.WebSocketUpgradeHandler;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.eclipse.jetty.websocket.core.server.internal.RFC6455Handshaker;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static org.eclipse.jetty.util.Callback.NOOP;
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.hamcrest.Matchers.is;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
@ -56,31 +41,40 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
public class ValidationExtensionTest extends WebSocketTester
|
public class ValidationExtensionTest extends WebSocketTester
|
||||||
{
|
{
|
||||||
private static Logger LOG = Log.getLogger(WebSocketServerTest.class);
|
|
||||||
|
|
||||||
private WebSocketServer server;
|
private WebSocketServer server;
|
||||||
|
TestFrameHandler serverHandler;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void start() throws Exception
|
||||||
|
{
|
||||||
|
serverHandler = new TestFrameHandler();
|
||||||
|
WebSocketNegotiator negotiator = new TestWebSocketNegotiator(serverHandler);
|
||||||
|
server = new WebSocketServer(negotiator);
|
||||||
|
server.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
public void stop() throws Exception
|
||||||
|
{
|
||||||
|
server.stop();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNonUtf8BinaryPayload() throws Exception
|
public void testNonUtf8BinaryPayload() throws Exception
|
||||||
{
|
{
|
||||||
TestFrameHandler serverHandler = new TestFrameHandler();
|
|
||||||
|
|
||||||
server = new WebSocketServer(0, serverHandler);
|
|
||||||
server.start();
|
|
||||||
|
|
||||||
byte[] nonUtf8Payload = { 0x7F, (byte)0xFF, (byte)0xFF };
|
byte[] nonUtf8Payload = { 0x7F, (byte)0xFF, (byte)0xFF };
|
||||||
|
|
||||||
try (Socket client = newClient(server.getLocalPort()))
|
try (Socket client = newClient(server.getLocalPort()))
|
||||||
{
|
{
|
||||||
client.getOutputStream().write(RawFrameBuilder.buildFrame(OpCode.BINARY, nonUtf8Payload, true));
|
client.getOutputStream().write(RawFrameBuilder.buildFrame(OpCode.BINARY, nonUtf8Payload, true));
|
||||||
Frame frame = server.handler.receivedFrames.poll(5, TimeUnit.SECONDS);
|
Frame frame = serverHandler.receivedFrames.poll(5, TimeUnit.SECONDS);
|
||||||
assertNotNull(frame);
|
assertNotNull(frame);
|
||||||
assertThat(frame.getOpCode(), is(OpCode.BINARY));
|
assertThat(frame.getOpCode(), is(OpCode.BINARY));
|
||||||
assertThat(frame.getPayload().array(), is(nonUtf8Payload));
|
assertThat(frame.getPayload().array(), is(nonUtf8Payload));
|
||||||
|
|
||||||
//close normally
|
//close normally
|
||||||
client.getOutputStream().write(RawFrameBuilder.buildClose(CloseStatus.NORMAL_STATUS, true));
|
client.getOutputStream().write(RawFrameBuilder.buildClose(CloseStatus.NORMAL_STATUS, true));
|
||||||
assertTrue(server.handler.closed.await(5, TimeUnit.SECONDS));
|
assertTrue(serverHandler.closed.await(5, TimeUnit.SECONDS));
|
||||||
frame = receiveFrame(client.getInputStream());
|
frame = receiveFrame(client.getInputStream());
|
||||||
assertNotNull(frame);
|
assertNotNull(frame);
|
||||||
assertThat(frame.getOpCode(), is(OpCode.CLOSE));
|
assertThat(frame.getOpCode(), is(OpCode.CLOSE));
|
||||||
|
@ -91,11 +85,6 @@ public class ValidationExtensionTest extends WebSocketTester
|
||||||
@Test
|
@Test
|
||||||
public void testValidContinuationOnNonUtf8Boundary() throws Exception
|
public void testValidContinuationOnNonUtf8Boundary() throws Exception
|
||||||
{
|
{
|
||||||
TestFrameHandler serverHandler = new TestFrameHandler();
|
|
||||||
|
|
||||||
server = new WebSocketServer(0, serverHandler);
|
|
||||||
server.start();
|
|
||||||
|
|
||||||
// Testing with 4 byte UTF8 character "\uD842\uDF9F"
|
// Testing with 4 byte UTF8 character "\uD842\uDF9F"
|
||||||
byte[] initialPayload = new byte[] { (byte)0xF0, (byte)0xA0 };
|
byte[] initialPayload = new byte[] { (byte)0xF0, (byte)0xA0 };
|
||||||
byte[] continuationPayload = new byte[] { (byte)0xAE, (byte)0x9F };
|
byte[] continuationPayload = new byte[] { (byte)0xAE, (byte)0x9F };
|
||||||
|
@ -103,20 +92,20 @@ public class ValidationExtensionTest extends WebSocketTester
|
||||||
try (Socket client = newClient(server.getLocalPort()))
|
try (Socket client = newClient(server.getLocalPort()))
|
||||||
{
|
{
|
||||||
client.getOutputStream().write(RawFrameBuilder.buildFrame(OpCode.TEXT, initialPayload, true, false));
|
client.getOutputStream().write(RawFrameBuilder.buildFrame(OpCode.TEXT, initialPayload, true, false));
|
||||||
Frame frame = server.handler.receivedFrames.poll(5, TimeUnit.SECONDS);
|
Frame frame = serverHandler.receivedFrames.poll(5, TimeUnit.SECONDS);
|
||||||
assertNotNull(frame);
|
assertNotNull(frame);
|
||||||
assertThat(frame.getOpCode(), is(OpCode.TEXT));
|
assertThat(frame.getOpCode(), is(OpCode.TEXT));
|
||||||
assertThat(frame.getPayload().array(), is(initialPayload));
|
assertThat(frame.getPayload().array(), is(initialPayload));
|
||||||
|
|
||||||
client.getOutputStream().write(RawFrameBuilder.buildFrame(OpCode.CONTINUATION, continuationPayload, true));
|
client.getOutputStream().write(RawFrameBuilder.buildFrame(OpCode.CONTINUATION, continuationPayload, true));
|
||||||
frame = server.handler.receivedFrames.poll(5, TimeUnit.SECONDS);
|
frame = serverHandler.receivedFrames.poll(5, TimeUnit.SECONDS);
|
||||||
assertNotNull(frame);
|
assertNotNull(frame);
|
||||||
assertThat(frame.getOpCode(), is(OpCode.CONTINUATION));
|
assertThat(frame.getOpCode(), is(OpCode.CONTINUATION));
|
||||||
assertThat(frame.getPayload().array(), is(continuationPayload));
|
assertThat(frame.getPayload().array(), is(continuationPayload));
|
||||||
|
|
||||||
//close normally
|
//close normally
|
||||||
client.getOutputStream().write(RawFrameBuilder.buildClose(CloseStatus.NORMAL_STATUS, true));
|
client.getOutputStream().write(RawFrameBuilder.buildClose(CloseStatus.NORMAL_STATUS, true));
|
||||||
assertTrue(server.handler.closed.await(5, TimeUnit.SECONDS));
|
assertTrue(serverHandler.closed.await(5, TimeUnit.SECONDS));
|
||||||
frame = receiveFrame(client.getInputStream());
|
frame = receiveFrame(client.getInputStream());
|
||||||
assertNotNull(frame);
|
assertNotNull(frame);
|
||||||
assertThat(frame.getOpCode(), is(OpCode.CLOSE));
|
assertThat(frame.getOpCode(), is(OpCode.CLOSE));
|
||||||
|
@ -127,11 +116,6 @@ public class ValidationExtensionTest extends WebSocketTester
|
||||||
@Test
|
@Test
|
||||||
public void testInvalidContinuationOnNonUtf8Boundary() throws Exception
|
public void testInvalidContinuationOnNonUtf8Boundary() throws Exception
|
||||||
{
|
{
|
||||||
TestFrameHandler serverHandler = new TestFrameHandler();
|
|
||||||
|
|
||||||
server = new WebSocketServer(0, serverHandler);
|
|
||||||
server.start();
|
|
||||||
|
|
||||||
// Testing with 4 byte UTF8 character "\uD842\uDF9F"
|
// Testing with 4 byte UTF8 character "\uD842\uDF9F"
|
||||||
byte[] initialPayload = new byte[] { (byte)0xF0, (byte)0xA0 };
|
byte[] initialPayload = new byte[] { (byte)0xF0, (byte)0xA0 };
|
||||||
byte[] incompleteContinuationPayload = new byte[] { (byte)0xAE };
|
byte[] incompleteContinuationPayload = new byte[] { (byte)0xAE };
|
||||||
|
@ -139,7 +123,7 @@ public class ValidationExtensionTest extends WebSocketTester
|
||||||
try (Socket client = newClient(server.getLocalPort()))
|
try (Socket client = newClient(server.getLocalPort()))
|
||||||
{
|
{
|
||||||
client.getOutputStream().write(RawFrameBuilder.buildFrame(OpCode.TEXT, initialPayload, true, false));
|
client.getOutputStream().write(RawFrameBuilder.buildFrame(OpCode.TEXT, initialPayload, true, false));
|
||||||
Frame frame = server.handler.receivedFrames.poll(5, TimeUnit.SECONDS);
|
Frame frame = serverHandler.receivedFrames.poll(5, TimeUnit.SECONDS);
|
||||||
assertNotNull(frame);
|
assertNotNull(frame);
|
||||||
assertThat(frame.getOpCode(), is(OpCode.TEXT));
|
assertThat(frame.getOpCode(), is(OpCode.TEXT));
|
||||||
assertThat(frame.getPayload().array(), is(initialPayload));
|
assertThat(frame.getPayload().array(), is(initialPayload));
|
||||||
|
@ -151,74 +135,4 @@ public class ValidationExtensionTest extends WebSocketTester
|
||||||
assertThat(new CloseStatus(frame.getPayload()).getCode(), is(CloseStatus.BAD_PAYLOAD));
|
assertThat(new CloseStatus(frame.getPayload()).getCode(), is(CloseStatus.BAD_PAYLOAD));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static class WebSocketServer extends AbstractLifeCycle
|
|
||||||
{
|
|
||||||
private static Logger LOG = Log.getLogger(WebSocketServer.class);
|
|
||||||
private final Server server;
|
|
||||||
private final TestFrameHandler handler;
|
|
||||||
|
|
||||||
public void doStart() throws Exception
|
|
||||||
{
|
|
||||||
server.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void doStop() throws Exception
|
|
||||||
{
|
|
||||||
server.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getLocalPort()
|
|
||||||
{
|
|
||||||
return server.getBean(NetworkConnector.class).getLocalPort();
|
|
||||||
}
|
|
||||||
|
|
||||||
public WebSocketServer(int port, TestFrameHandler frameHandler)
|
|
||||||
{
|
|
||||||
this.handler = frameHandler;
|
|
||||||
server = new Server();
|
|
||||||
server.getBean(QueuedThreadPool.class).setName("WSCoreServer");
|
|
||||||
ServerConnector connector = new ServerConnector(server, new HttpConnectionFactory());
|
|
||||||
|
|
||||||
connector.addBean(new RFC6455Handshaker());
|
|
||||||
connector.setPort(port);
|
|
||||||
connector.setIdleTimeout(1000000);
|
|
||||||
server.addConnector(connector);
|
|
||||||
|
|
||||||
ContextHandler context = new ContextHandler("/");
|
|
||||||
server.setHandler(context);
|
|
||||||
WebSocketNegotiator negotiator = new TestWebSocketNegotiator(new DecoratedObjectFactory(), new WebSocketExtensionRegistry(),
|
|
||||||
connector.getByteBufferPool(), frameHandler);
|
|
||||||
|
|
||||||
WebSocketUpgradeHandler upgradeHandler = new TestWebSocketUpgradeHandler(negotiator);
|
|
||||||
context.setHandler(upgradeHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void sendFrame(Frame frame)
|
|
||||||
{
|
|
||||||
handler.getCoreSession().sendFrame(frame, NOOP, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void sendText(String line)
|
|
||||||
{
|
|
||||||
LOG.info("sending {}...", line);
|
|
||||||
|
|
||||||
handler.sendText(line);
|
|
||||||
}
|
|
||||||
|
|
||||||
public BlockingQueue<Frame> getFrames()
|
|
||||||
{
|
|
||||||
return handler.getFrames();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void close()
|
|
||||||
{
|
|
||||||
handler.getCoreSession().close(CloseStatus.NORMAL, "WebSocketServer Initiated Close", Callback.NOOP);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isOpen()
|
|
||||||
{
|
|
||||||
return handler.getCoreSession().isOutputOpen();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -132,7 +132,6 @@ public class FrameFlusherTest
|
||||||
});
|
});
|
||||||
|
|
||||||
serverTask.get();
|
serverTask.get();
|
||||||
System.out.printf("Received: %,d frames%n", endPoint.incomingFrames.size());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class CapturingEndPoint extends MockEndpoint
|
public static class CapturingEndPoint extends MockEndpoint
|
||||||
|
|
|
@ -25,29 +25,18 @@ import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
import org.eclipse.jetty.io.ByteBufferPool;
|
import org.eclipse.jetty.io.ByteBufferPool;
|
||||||
import org.eclipse.jetty.server.HttpConnectionFactory;
|
|
||||||
import org.eclipse.jetty.server.NetworkConnector;
|
|
||||||
import org.eclipse.jetty.server.Server;
|
|
||||||
import org.eclipse.jetty.server.ServerConnector;
|
|
||||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
|
||||||
import org.eclipse.jetty.util.BlockingArrayQueue;
|
import org.eclipse.jetty.util.BlockingArrayQueue;
|
||||||
import org.eclipse.jetty.util.BufferUtil;
|
import org.eclipse.jetty.util.BufferUtil;
|
||||||
import org.eclipse.jetty.util.Callback;
|
import org.eclipse.jetty.util.Callback;
|
||||||
import org.eclipse.jetty.util.DecoratedObjectFactory;
|
|
||||||
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
|
||||||
import org.eclipse.jetty.util.log.Log;
|
import org.eclipse.jetty.util.log.Log;
|
||||||
import org.eclipse.jetty.util.log.Logger;
|
import org.eclipse.jetty.util.log.Logger;
|
||||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
|
||||||
import org.eclipse.jetty.websocket.core.CloseStatus;
|
import org.eclipse.jetty.websocket.core.CloseStatus;
|
||||||
import org.eclipse.jetty.websocket.core.Frame;
|
import org.eclipse.jetty.websocket.core.Frame;
|
||||||
import org.eclipse.jetty.websocket.core.OpCode;
|
import org.eclipse.jetty.websocket.core.OpCode;
|
||||||
import org.eclipse.jetty.websocket.core.RawFrameBuilder;
|
import org.eclipse.jetty.websocket.core.RawFrameBuilder;
|
||||||
import org.eclipse.jetty.websocket.core.TestFrameHandler;
|
import org.eclipse.jetty.websocket.core.TestFrameHandler;
|
||||||
import org.eclipse.jetty.websocket.core.TestWebSocketNegotiator;
|
import org.eclipse.jetty.websocket.core.WebSocketServer;
|
||||||
import org.eclipse.jetty.websocket.core.TestWebSocketUpgradeHandler;
|
|
||||||
import org.eclipse.jetty.websocket.core.WebSocketExtensionRegistry;
|
|
||||||
import org.eclipse.jetty.websocket.core.WebSocketTester;
|
import org.eclipse.jetty.websocket.core.WebSocketTester;
|
||||||
import org.eclipse.jetty.websocket.core.server.internal.RFC6455Handshaker;
|
|
||||||
import org.hamcrest.MatcherAssert;
|
import org.hamcrest.MatcherAssert;
|
||||||
import org.hamcrest.Matchers;
|
import org.hamcrest.Matchers;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
@ -82,7 +71,7 @@ public class WebSocketServerTest extends WebSocketTester
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
server = new WebSocketServer(0, serverHandler);
|
server = new WebSocketServer(serverHandler);
|
||||||
server.start();
|
server.start();
|
||||||
|
|
||||||
try (Socket client = newClient(server.getLocalPort()))
|
try (Socket client = newClient(server.getLocalPort()))
|
||||||
|
@ -97,7 +86,7 @@ public class WebSocketServerTest extends WebSocketTester
|
||||||
assertThat(frame.getPayloadAsUTF8(), is("Hello!"));
|
assertThat(frame.getPayloadAsUTF8(), is("Hello!"));
|
||||||
|
|
||||||
client.getOutputStream().write(RawFrameBuilder.buildClose(CloseStatus.NORMAL_STATUS, true));
|
client.getOutputStream().write(RawFrameBuilder.buildClose(CloseStatus.NORMAL_STATUS, true));
|
||||||
assertTrue(server.handler.closed.await(5, TimeUnit.SECONDS));
|
assertTrue(serverHandler.closed.await(5, TimeUnit.SECONDS));
|
||||||
frame = receiveFrame(client.getInputStream());
|
frame = receiveFrame(client.getInputStream());
|
||||||
assertNotNull(frame);
|
assertNotNull(frame);
|
||||||
MatcherAssert.assertThat(frame.getOpCode(), Matchers.is(OpCode.CLOSE));
|
MatcherAssert.assertThat(frame.getOpCode(), Matchers.is(OpCode.CLOSE));
|
||||||
|
@ -117,7 +106,7 @@ public class WebSocketServerTest extends WebSocketTester
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
server = new WebSocketServer(0, serverHandler);
|
server = new WebSocketServer(serverHandler);
|
||||||
server.start();
|
server.start();
|
||||||
|
|
||||||
try (Socket client = newClient(server.getLocalPort()))
|
try (Socket client = newClient(server.getLocalPort()))
|
||||||
|
@ -139,10 +128,10 @@ public class WebSocketServerTest extends WebSocketTester
|
||||||
assertThat(frame.getPayloadAsUTF8(), is("World"));
|
assertThat(frame.getPayloadAsUTF8(), is("World"));
|
||||||
|
|
||||||
client.getOutputStream().write(RawFrameBuilder.buildClose(CloseStatus.NORMAL_STATUS, true));
|
client.getOutputStream().write(RawFrameBuilder.buildClose(CloseStatus.NORMAL_STATUS, true));
|
||||||
assertFalse(server.handler.closed.await(250, TimeUnit.MILLISECONDS));
|
assertFalse(serverHandler.closed.await(250, TimeUnit.MILLISECONDS));
|
||||||
|
|
||||||
serverHandler.getCoreSession().demand(1);
|
serverHandler.getCoreSession().demand(1);
|
||||||
assertTrue(server.handler.closed.await(10, TimeUnit.SECONDS));
|
assertTrue(serverHandler.closed.await(10, TimeUnit.SECONDS));
|
||||||
frame = serverHandler.receivedFrames.poll(10, TimeUnit.SECONDS);
|
frame = serverHandler.receivedFrames.poll(10, TimeUnit.SECONDS);
|
||||||
assertNotNull(frame);
|
assertNotNull(frame);
|
||||||
assertThat(frame.getOpCode(), is(OpCode.CLOSE));
|
assertThat(frame.getOpCode(), is(OpCode.CLOSE));
|
||||||
|
@ -185,7 +174,7 @@ public class WebSocketServerTest extends WebSocketTester
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
server = new WebSocketServer(0, serverHandler);
|
server = new WebSocketServer(serverHandler);
|
||||||
server.start();
|
server.start();
|
||||||
|
|
||||||
try (Socket client = newClient(server.getLocalPort()))
|
try (Socket client = newClient(server.getLocalPort()))
|
||||||
|
@ -226,7 +215,7 @@ public class WebSocketServerTest extends WebSocketTester
|
||||||
assertThat(serverHandler.receivedFrames.poll().getPayload().array(), sameInstance(second));
|
assertThat(serverHandler.receivedFrames.poll().getPayload().array(), sameInstance(second));
|
||||||
assertThat(first, not(sameInstance(second)));
|
assertThat(first, not(sameInstance(second)));
|
||||||
|
|
||||||
ByteBufferPool pool = server.server.getConnectors()[0].getByteBufferPool();
|
ByteBufferPool pool = server.getServer().getConnectors()[0].getByteBufferPool();
|
||||||
|
|
||||||
assertThat(pool.acquire(first.length, false).array(), not(sameInstance(first)));
|
assertThat(pool.acquire(first.length, false).array(), not(sameInstance(first)));
|
||||||
receivedCallbacks.poll().succeeded();
|
receivedCallbacks.poll().succeeded();
|
||||||
|
@ -249,13 +238,13 @@ public class WebSocketServerTest extends WebSocketTester
|
||||||
{
|
{
|
||||||
TestFrameHandler serverHandler = new TestFrameHandler();
|
TestFrameHandler serverHandler = new TestFrameHandler();
|
||||||
|
|
||||||
server = new WebSocketServer(0, serverHandler);
|
server = new WebSocketServer(serverHandler);
|
||||||
server.start();
|
server.start();
|
||||||
|
|
||||||
try (Socket client = newClient(server.getLocalPort()))
|
try (Socket client = newClient(server.getLocalPort()))
|
||||||
{
|
{
|
||||||
client.getOutputStream().write(RawFrameBuilder.buildFrame((byte)4, "payload", true));
|
client.getOutputStream().write(RawFrameBuilder.buildFrame((byte)4, "payload", true));
|
||||||
assertTrue(server.handler.closed.await(5, TimeUnit.SECONDS));
|
assertTrue(serverHandler.closed.await(5, TimeUnit.SECONDS));
|
||||||
|
|
||||||
Frame frame = receiveFrame(client.getInputStream());
|
Frame frame = receiveFrame(client.getInputStream());
|
||||||
assertNotNull(frame);
|
assertNotNull(frame);
|
||||||
|
@ -269,14 +258,14 @@ public class WebSocketServerTest extends WebSocketTester
|
||||||
{
|
{
|
||||||
TestFrameHandler serverHandler = new TestFrameHandler();
|
TestFrameHandler serverHandler = new TestFrameHandler();
|
||||||
|
|
||||||
server = new WebSocketServer(0, serverHandler);
|
server = new WebSocketServer(serverHandler);
|
||||||
server.start();
|
server.start();
|
||||||
|
|
||||||
try (Socket client = newClient(server.getLocalPort()))
|
try (Socket client = newClient(server.getLocalPort()))
|
||||||
{
|
{
|
||||||
// Write client close without masking!
|
// Write client close without masking!
|
||||||
client.getOutputStream().write(RawFrameBuilder.buildClose(CloseStatus.NORMAL_STATUS, false));
|
client.getOutputStream().write(RawFrameBuilder.buildClose(CloseStatus.NORMAL_STATUS, false));
|
||||||
assertTrue(server.handler.closed.await(5, TimeUnit.SECONDS));
|
assertTrue(serverHandler.closed.await(5, TimeUnit.SECONDS));
|
||||||
Frame frame = receiveFrame(client.getInputStream());
|
Frame frame = receiveFrame(client.getInputStream());
|
||||||
assertNotNull(frame);
|
assertNotNull(frame);
|
||||||
assertThat(frame.getOpCode(), is(OpCode.CLOSE));
|
assertThat(frame.getOpCode(), is(OpCode.CLOSE));
|
||||||
|
@ -314,7 +303,7 @@ public class WebSocketServerTest extends WebSocketTester
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
server = new WebSocketServer(0, serverHandler);
|
server = new WebSocketServer(serverHandler);
|
||||||
server.start();
|
server.start();
|
||||||
|
|
||||||
try (Socket client = newClient(server.getLocalPort()))
|
try (Socket client = newClient(server.getLocalPort()))
|
||||||
|
@ -380,7 +369,7 @@ public class WebSocketServerTest extends WebSocketTester
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
server = new WebSocketServer(0, serverHandler);
|
server = new WebSocketServer(serverHandler);
|
||||||
server.start();
|
server.start();
|
||||||
|
|
||||||
try (Socket client = newClient(server.getLocalPort()))
|
try (Socket client = newClient(server.getLocalPort()))
|
||||||
|
@ -448,7 +437,7 @@ public class WebSocketServerTest extends WebSocketTester
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
server = new WebSocketServer(0, serverHandler);
|
server = new WebSocketServer(serverHandler);
|
||||||
server.start();
|
server.start();
|
||||||
|
|
||||||
try (Socket client = newClient(server.getLocalPort()))
|
try (Socket client = newClient(server.getLocalPort()))
|
||||||
|
@ -484,74 +473,4 @@ public class WebSocketServerTest extends WebSocketTester
|
||||||
assertThat(frame.getOpCode(), is(OpCode.CLOSE));
|
assertThat(frame.getOpCode(), is(OpCode.CLOSE));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static class WebSocketServer extends AbstractLifeCycle
|
|
||||||
{
|
|
||||||
private static Logger LOG = Log.getLogger(WebSocketServer.class);
|
|
||||||
private final Server server;
|
|
||||||
private final TestFrameHandler handler;
|
|
||||||
|
|
||||||
public void doStart() throws Exception
|
|
||||||
{
|
|
||||||
server.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void doStop() throws Exception
|
|
||||||
{
|
|
||||||
server.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getLocalPort()
|
|
||||||
{
|
|
||||||
return server.getBean(NetworkConnector.class).getLocalPort();
|
|
||||||
}
|
|
||||||
|
|
||||||
public WebSocketServer(int port, TestFrameHandler frameHandler)
|
|
||||||
{
|
|
||||||
this.handler = frameHandler;
|
|
||||||
server = new Server();
|
|
||||||
server.getBean(QueuedThreadPool.class).setName("WSCoreServer");
|
|
||||||
ServerConnector connector = new ServerConnector(server, new HttpConnectionFactory());
|
|
||||||
|
|
||||||
connector.addBean(new RFC6455Handshaker());
|
|
||||||
connector.setPort(port);
|
|
||||||
connector.setIdleTimeout(1000000);
|
|
||||||
server.addConnector(connector);
|
|
||||||
|
|
||||||
ContextHandler context = new ContextHandler("/");
|
|
||||||
server.setHandler(context);
|
|
||||||
WebSocketNegotiator negotiator = new TestWebSocketNegotiator(new DecoratedObjectFactory(), new WebSocketExtensionRegistry(),
|
|
||||||
connector.getByteBufferPool(), frameHandler);
|
|
||||||
|
|
||||||
WebSocketUpgradeHandler upgradeHandler = new TestWebSocketUpgradeHandler(negotiator);
|
|
||||||
context.setHandler(upgradeHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void sendFrame(Frame frame)
|
|
||||||
{
|
|
||||||
handler.getCoreSession().sendFrame(frame, Callback.NOOP, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void sendText(String line)
|
|
||||||
{
|
|
||||||
LOG.info("sending {}...", line);
|
|
||||||
|
|
||||||
handler.sendText(line);
|
|
||||||
}
|
|
||||||
|
|
||||||
public BlockingQueue<Frame> getFrames()
|
|
||||||
{
|
|
||||||
return handler.getFrames();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void close()
|
|
||||||
{
|
|
||||||
handler.getCoreSession().close(CloseStatus.NORMAL, "WebSocketServer Initiated Close", Callback.NOOP);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isOpen()
|
|
||||||
{
|
|
||||||
return handler.getCoreSession().isOutputOpen();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue