From 79f30041a130791b69918e1138b5c7fd746d9f62 Mon Sep 17 00:00:00 2001 From: Joakim Erdfelt Date: Wed, 3 May 2017 16:59:54 -0700 Subject: [PATCH] Issue #207 - More test fixes # Conflicts: # jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/BinaryStreamTest.java # jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/TextStreamTest.java --- .../websocket/jsr356/JsrSessionTest.java | 4 +- .../decoders/AvailableDecodersTest.java | 2 +- .../encoders/AvailableEncodersTest.java | 6 +- .../server/PathParamServerEndpointConfig.java | 5 +- .../jsr356/server/BinaryStreamTest.java | 177 ---- .../websocket/jsr356/server/EchoCase.java | 181 ---- .../websocket/jsr356/server/EchoTest.java | 341 -------- .../websocket/jsr356/server/SessionTest.java | 232 ------ .../jsr356/server/TextStreamTest.java | 179 ---- .../samples/binary/ByteBufferSocket.java | 4 +- .../partial/PartialTextSessionSocket.java | 4 +- .../samples/partial/PartialTextSocket.java | 4 +- .../BooleanObjectTextParamSocket.java | 4 +- .../primitives/BooleanObjectTextSocket.java | 4 +- .../primitives/BooleanTextParamSocket.java | 4 +- .../samples/primitives/BooleanTextSocket.java | 4 +- .../primitives/ByteObjectTextSocket.java | 4 +- .../samples/primitives/ByteTextSocket.java | 4 +- .../samples/primitives/CharTextSocket.java | 4 +- .../primitives/CharacterObjectTextSocket.java | 4 +- .../primitives/DoubleObjectTextSocket.java | 4 +- .../samples/primitives/DoubleTextSocket.java | 4 +- .../primitives/FloatObjectTextSocket.java | 4 +- .../samples/primitives/FloatTextSocket.java | 4 +- .../primitives/IntParamTextSocket.java | 4 +- .../samples/primitives/IntTextSocket.java | 4 +- .../IntegerObjectParamTextSocket.java | 4 +- .../primitives/IntegerObjectTextSocket.java | 4 +- .../primitives/LongObjectTextSocket.java | 4 +- .../samples/primitives/LongTextSocket.java | 4 +- .../primitives/ShortObjectTextSocket.java | 4 +- .../samples/primitives/ShortTextSocket.java | 4 +- .../samples/streaming/InputStreamSocket.java | 4 +- .../samples/streaming/ReaderParamSocket.java | 4 +- .../samples/streaming/ReaderSocket.java | 4 +- .../StringReturnReaderParamSocket.java | 4 +- .../websocket/api/WebSocketConstants.java | 4 + .../io/AbstractWebSocketConnection.java | 6 +- .../common/message/MessageInputStream.java | 14 +- .../common/message/MessageOutputStream.java | 18 +- .../jetty/websocket/common/GeneratorTest.java | 2 +- .../jetty/websocket/common/ParserTest.java | 2 +- .../websocket/common/WebSocketFrameTest.java | 2 +- .../compress/CapturedHexPayloads.java | 2 +- .../io/payload/DeMaskProcessorTest.java | 8 +- .../jetty/websocket/common/util/Hex.java | 80 -- .../jetty/websocket/common/util/Sha1Sum.java | 1 + .../websocket/common/util/StackUtil.java | 42 - .../common/util/Utf8PartialBuilderTest.java | 5 +- .../server/WebSocketServerFactory.java | 3 +- jetty-websocket/websocket-tests/pom.xml | 2 +- .../jetty/websocket/tests/DataUtils.java | 56 ++ .../eclipse/jetty/websocket/tests/Fuzzer.java | 273 ------ .../jetty/websocket/tests/LocalFuzzer.java | 346 ++++++++ .../jetty/websocket/tests/LocalServer.java | 194 +++++ .../websocket/tests/SimpleServletServer.java | 138 +-- .../jetty/websocket/tests/UpgradeUtils.java | 62 ++ .../jetty/websocket/tests/WSServer.java | 166 ++-- .../websocket/tests/server/ABServlet.java | 35 - .../websocket/tests/server/ABSocket.java | 84 -- .../tests/server/AbstractABCase.java | 244 ------ .../tests/server/AbstractLocalServerCase.java | 364 ++------ .../tests/server/BadOpCodesTest.java | 9 +- .../websocket/tests/server/BinaryTest.java | 437 ++++++++++ .../tests/server/CloseHandlingTest.java | 34 +- ... => CloseHandling_BadStatusCodesTest.java} | 26 +- ...=> CloseHandling_GoodStatusCodesTest.java} | 29 +- .../server/ConnectionUpgradeToBufferTest.java | 5 +- .../tests/server/ContinuationTest.java | 71 +- .../tests/server/PayloadLengthTest.java | 26 +- .../websocket/tests/server/PingPongTest.java | 54 +- .../tests/server/ReservedBitTest.java | 21 +- .../websocket/tests/server/TestABCase9.java | 787 ------------------ .../{TextUTF8Test.java => TextTest.java} | 718 ++++++++++++---- ...ValuesTest.java => Text_GoodUtf8Test.java} | 12 +- ...uesTest.java => Text_InvalidUtf8Test.java} | 9 +- .../tests/server/jsr356}/AltFilterTest.java | 48 +- .../jsr356}/AnnotatedServerEndpointTest.java | 103 ++- .../tests/server/jsr356/BinaryStreamTest.java | 164 ++++ .../tests/server/jsr356/ConfiguratorTest.java | 7 + .../server/jsr356/InputStreamEchoTest.java | 153 ++++ .../tests/server/jsr356/JsrEchoTest.java | 226 +++++ .../tests/server/jsr356/PartialEchoTest.java | 176 ++++ .../jsr356/PrimitivesBinaryEchoTest.java | 169 ++++ .../server/jsr356/PrimitivesTextEchoTest.java | 418 ++++++++++ .../tests/server/jsr356/ReaderEchoTest.java | 207 +++++ .../tests/server/jsr356/SessionTest.java | 368 ++++++++ .../tests/server/jsr356/TextStreamTest.java | 156 ++++ .../jsr356/UriTemplateParameterTest.java | 107 +++ .../server/jsr356/coders}/DateDecoder.java | 2 +- .../server/jsr356/coders}/DateEncoder.java | 2 +- .../jsr356/coders}/DateTimeDecoder.java | 2 +- .../jsr356/coders}/DateTimeEncoder.java | 2 +- .../server/jsr356/coders}/TimeDecoder.java | 2 +- .../server/jsr356/coders}/TimeEncoder.java | 2 +- .../configs}/EchoSocketConfigurator.java | 2 +- .../jsr356/sockets/BasicEchoSocket.java} | 25 +- .../jsr356/sockets/ByteBufferSocket.java | 51 ++ .../jsr356/sockets}/ConfiguredEchoSocket.java | 46 +- .../jsr356/sockets}/DateTextSocket.java | 8 +- .../src/test/resources/alt-filter-web.xml | 23 + .../src/test/resources/empty-web.xml | 8 + .../test/resources/jetty-logging.properties | 9 +- 103 files changed, 4431 insertions(+), 3681 deletions(-) delete mode 100644 jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/BinaryStreamTest.java delete mode 100644 jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/EchoCase.java delete mode 100644 jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/EchoTest.java delete mode 100644 jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/SessionTest.java delete mode 100644 jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/TextStreamTest.java delete mode 100644 jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/util/Hex.java delete mode 100644 jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/util/StackUtil.java create mode 100644 jetty-websocket/websocket-tests/src/main/java/org/eclipse/jetty/websocket/tests/DataUtils.java delete mode 100644 jetty-websocket/websocket-tests/src/main/java/org/eclipse/jetty/websocket/tests/Fuzzer.java create mode 100644 jetty-websocket/websocket-tests/src/main/java/org/eclipse/jetty/websocket/tests/LocalFuzzer.java create mode 100644 jetty-websocket/websocket-tests/src/main/java/org/eclipse/jetty/websocket/tests/LocalServer.java create mode 100644 jetty-websocket/websocket-tests/src/main/java/org/eclipse/jetty/websocket/tests/UpgradeUtils.java delete mode 100644 jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/ABServlet.java delete mode 100644 jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/ABSocket.java delete mode 100644 jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/AbstractABCase.java create mode 100644 jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/BinaryTest.java rename jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/{TestABCase7_BadStatusCodes.java => CloseHandling_BadStatusCodesTest.java} (86%) rename jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/{TestABCase7_GoodStatusCodes.java => CloseHandling_GoodStatusCodesTest.java} (83%) delete mode 100644 jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/TestABCase9.java rename jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/{TextUTF8Test.java => TextTest.java} (50%) rename jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/{TextUTF8_GoodValuesTest.java => Text_GoodUtf8Test.java} (94%) rename jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/{TextUTF8_InvalidValuesTest.java => Text_InvalidUtf8Test.java} (96%) rename jetty-websocket/{javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server => websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356}/AltFilterTest.java (64%) rename jetty-websocket/{javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server => websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356}/AnnotatedServerEndpointTest.java (53%) create mode 100644 jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/BinaryStreamTest.java create mode 100644 jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/InputStreamEchoTest.java create mode 100644 jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/JsrEchoTest.java create mode 100644 jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/PartialEchoTest.java create mode 100644 jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/PrimitivesBinaryEchoTest.java create mode 100644 jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/PrimitivesTextEchoTest.java create mode 100644 jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/ReaderEchoTest.java create mode 100644 jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/SessionTest.java create mode 100644 jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/TextStreamTest.java create mode 100644 jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/UriTemplateParameterTest.java rename jetty-websocket/{javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/beans => websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/coders}/DateDecoder.java (96%) rename jetty-websocket/{javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/beans => websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/coders}/DateEncoder.java (95%) rename jetty-websocket/{javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/beans => websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/coders}/DateTimeDecoder.java (96%) rename jetty-websocket/{javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/beans => websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/coders}/DateTimeEncoder.java (95%) rename jetty-websocket/{javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/beans => websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/coders}/TimeDecoder.java (96%) rename jetty-websocket/{javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/beans => websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/coders}/TimeEncoder.java (95%) rename jetty-websocket/{javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/echo => websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/configs}/EchoSocketConfigurator.java (95%) rename jetty-websocket/websocket-tests/src/{main/java/org/eclipse/jetty/websocket/tests/Fuzzed.java => test/java/org/eclipse/jetty/websocket/tests/server/jsr356/sockets/BasicEchoSocket.java} (65%) create mode 100644 jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/sockets/ByteBufferSocket.java rename jetty-websocket/{javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/echo => websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/sockets}/ConfiguredEchoSocket.java (74%) rename jetty-websocket/{javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/beans => websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/sockets}/DateTextSocket.java (87%) create mode 100644 jetty-websocket/websocket-tests/src/test/resources/alt-filter-web.xml create mode 100644 jetty-websocket/websocket-tests/src/test/resources/empty-web.xml diff --git a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/JsrSessionTest.java b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/JsrSessionTest.java index 879c9e540fe..a720d8cfb3f 100644 --- a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/JsrSessionTest.java +++ b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/JsrSessionTest.java @@ -125,6 +125,7 @@ public class JsrSessionTest // Whole Message session.addMessageHandler(String.class, (msg) -> received.add(msg)); + session.connect(); session.open(); FrameCallback callback = new FrameCallback.Adapter(); @@ -155,7 +156,8 @@ public class JsrSessionTest copy.flip(); received.add(new Object[]{copy, isLast}); }); - + + session.connect(); session.open(); FrameCallback callback = new FrameCallback.Adapter(); diff --git a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/decoders/AvailableDecodersTest.java b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/decoders/AvailableDecodersTest.java index 55b1ff205a6..788a7bcd9f5 100644 --- a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/decoders/AvailableDecodersTest.java +++ b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/decoders/AvailableDecodersTest.java @@ -34,8 +34,8 @@ import javax.websocket.DecodeException; import javax.websocket.Decoder; import javax.websocket.EndpointConfig; +import org.eclipse.jetty.toolchain.test.Hex; import org.eclipse.jetty.websocket.api.InvalidWebSocketException; -import org.eclipse.jetty.websocket.common.util.Hex; import org.eclipse.jetty.websocket.jsr356.client.EmptyClientEndpointConfig; import org.junit.BeforeClass; import org.junit.Rule; diff --git a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/encoders/AvailableEncodersTest.java b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/encoders/AvailableEncodersTest.java index c18b195f7fd..36fc88d67d1 100644 --- a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/encoders/AvailableEncodersTest.java +++ b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/encoders/AvailableEncodersTest.java @@ -35,8 +35,8 @@ import javax.websocket.EncodeException; import javax.websocket.Encoder; import javax.websocket.EndpointConfig; +import org.eclipse.jetty.toolchain.test.Hex; import org.eclipse.jetty.websocket.api.InvalidWebSocketException; -import org.eclipse.jetty.websocket.common.util.Hex; import org.eclipse.jetty.websocket.jsr356.client.EmptyClientEndpointConfig; import org.junit.BeforeClass; import org.junit.Rule; @@ -81,7 +81,7 @@ public class AvailableEncodersTest Encoder.Binary encoder = (Encoder.Binary) encoders.getInstanceFor(type); assertThat("Encoder", encoder, notNullValue()); ByteBuffer encoded = encoder.encode(value); - + String hexEncoded = Hex.asHex(encoded); assertThat("Encoded", hexEncoded, is(expectedEncodedHex)); } @@ -92,7 +92,7 @@ public class AvailableEncodersTest assertThat("Encoder", encoder, notNullValue()); ByteArrayOutputStream out = new ByteArrayOutputStream(); encoder.encode(value, out); - + String hexEncoded = Hex.asHex(out.toByteArray()); assertThat("Encoded", hexEncoded, is(expectedEncodedHex)); diff --git a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/PathParamServerEndpointConfig.java b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/PathParamServerEndpointConfig.java index 49001af5b0a..9ad6be4206c 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/PathParamServerEndpointConfig.java +++ b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/PathParamServerEndpointConfig.java @@ -24,6 +24,7 @@ import java.util.Map; import javax.websocket.server.ServerEndpointConfig; import org.eclipse.jetty.http.pathmap.UriTemplatePathSpec; +import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.websocket.jsr356.PathParamProvider; /** @@ -42,7 +43,9 @@ public class PathParamServerEndpointConfig extends ServerEndpointConfigWrapper i pathParamMap = new HashMap<>(); if (pathMap != null) { - pathParamMap.putAll(pathMap); + pathMap.entrySet().stream().forEach( + entry -> pathParamMap.put(entry.getKey(), URIUtil.decodePath(entry.getValue())) + ); } } diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/BinaryStreamTest.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/BinaryStreamTest.java deleted file mode 100644 index a9cbcb1684e..00000000000 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/BinaryStreamTest.java +++ /dev/null @@ -1,177 +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 java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.URI; -import java.util.Random; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import javax.websocket.ClientEndpoint; -import javax.websocket.ContainerProvider; -import javax.websocket.OnMessage; -import javax.websocket.Session; -import javax.websocket.WebSocketContainer; -import javax.websocket.server.ServerEndpoint; -import javax.websocket.server.ServerEndpointConfig; - -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.ServerConnector; -import org.eclipse.jetty.servlet.ServletContextHandler; -import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -public class BinaryStreamTest -{ - private static final String PATH = "/echo"; - - private Server server; - private ServerConnector connector; - private WebSocketContainer wsClient; - - @Before - public void prepare() throws Exception - { - server = new Server(); - connector = new ServerConnector(server); - server.addConnector(connector); - - ServletContextHandler context = new ServletContextHandler(server, "/", true, false); - ServerContainer container = WebSocketServerContainerInitializer.configureContext(context); - ServerEndpointConfig config = ServerEndpointConfig.Builder.create(ServerBinaryStreamer.class, PATH).build(); - container.addEndpoint(config); - - server.start(); - - wsClient = ContainerProvider.getWebSocketContainer(); - } - - @After - public void dispose() throws Exception - { - server.stop(); - } - - @Test - public void testEchoWithMediumMessage() throws Exception - { - testEcho(1024); - } - - @Test - public void testLargestMessage() throws Exception - { - testEcho(wsClient.getDefaultMaxBinaryMessageBufferSize()); - } - - private void testEcho(int size) throws Exception - { - byte[] data = randomBytes(size); - URI uri = URI.create("ws://localhost:" + connector.getLocalPort() + PATH); - ClientBinaryStreamer client = new ClientBinaryStreamer(); - Session session = wsClient.connectToServer(client, uri); - - try (OutputStream output = session.getBasicRemote().getSendStream()) - { - output.write(data); - } - - Assert.assertTrue(client.await(5, TimeUnit.SECONDS)); - Assert.assertArrayEquals(data, client.getEcho()); - } - - @Test - public void testMoreThanLargestMessageOneByteAtATime() throws Exception - { - int size = wsClient.getDefaultMaxBinaryMessageBufferSize() + 16; - byte[] data = randomBytes(size); - URI uri = URI.create("ws://localhost:" + connector.getLocalPort() + PATH); - ClientBinaryStreamer client = new ClientBinaryStreamer(); - Session session = wsClient.connectToServer(client, uri); - - try (OutputStream output = session.getBasicRemote().getSendStream()) - { - for (int i = 0; i < size; ++i) - output.write(data[i]); - } - - Assert.assertTrue(client.await(5, TimeUnit.SECONDS)); - Assert.assertArrayEquals(data, client.getEcho()); - } - - private byte[] randomBytes(int size) - { - byte[] data = new byte[size]; - new Random().nextBytes(data); - return data; - } - - @ClientEndpoint - public static class ClientBinaryStreamer - { - private final CountDownLatch latch = new CountDownLatch(1); - private final ByteArrayOutputStream output = new ByteArrayOutputStream(); - - @OnMessage - public void echoed(InputStream input) throws IOException - { - while (true) - { - int read = input.read(); - if (read < 0) - break; - output.write(read); - } - latch.countDown(); - } - - public byte[] getEcho() - { - return output.toByteArray(); - } - - public boolean await(long timeout, TimeUnit unit) throws InterruptedException - { - return latch.await(timeout, unit); - } - } - - @ServerEndpoint(PATH) - public static class ServerBinaryStreamer - { - @OnMessage - public void echo(Session session, InputStream input) throws IOException - { - byte[] buffer = new byte[128]; - try (OutputStream output = session.getBasicRemote().getSendStream()) - { - int read; - while ((read = input.read(buffer)) >= 0) - output.write(buffer, 0, read); - } - } - } -} diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/EchoCase.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/EchoCase.java deleted file mode 100644 index 6fb14a18af1..00000000000 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/EchoCase.java +++ /dev/null @@ -1,181 +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 java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.List; - -import javax.websocket.server.ServerEndpoint; - -public class EchoCase -{ - public static class PartialBinary - { - ByteBuffer part; - - boolean fin; - public PartialBinary(ByteBuffer part, boolean fin) - { - this.part = part; - this.fin = fin; - } - } - - public static class PartialText - { - String part; - - boolean fin; - public PartialText(String part, boolean fin) - { - this.part = part; - this.fin = fin; - } - } - - public static EchoCase add(List data, Class serverPojo) - { - EchoCase ecase = new EchoCase(); - ecase.serverPojo = serverPojo; - data.add(new EchoCase[] - { ecase }); - ServerEndpoint endpoint = serverPojo.getAnnotation(ServerEndpoint.class); - ecase.path = endpoint.value(); - return ecase; - } - - public static EchoCase add(List data, Class serverPojo, String path) - { - EchoCase ecase = new EchoCase(); - ecase.serverPojo = serverPojo; - ecase.path = path; - data.add(new EchoCase[] - { ecase }); - return ecase; - } - - // The websocket server pojo to test against - public Class serverPojo; - // The (relative) URL path to hit - public String path; - // The messages to transmit - public List messages = new ArrayList<>(); - // The expected Strings (that are echoed back) - public List expectedStrings = new ArrayList<>(); - - public EchoCase addMessage(Object msg) - { - messages.add(msg); - return this; - } - - public EchoCase addSplitMessage(ByteBuffer... parts) - { - int len = parts.length; - for (int i = 0; i < len; i++) - { - addMessage(new PartialBinary(parts[i],(i == (len-1)))); - } - return this; - } - - public EchoCase addSplitMessage(String... parts) - { - int len = parts.length; - for (int i = 0; i < len; i++) - { - addMessage(new PartialText(parts[i],(i == (len-1)))); - } - return this; - } - - public EchoCase expect(String message) - { - expectedStrings.add(message); - return this; - } - - public EchoCase requestPath(String path) - { - this.path = path; - return this; - } - - @Override - public String toString() - { - StringBuilder str = new StringBuilder(); - str.append("EchoCase['"); - str.append(path); - str.append("',").append(serverPojo.getSimpleName()); - str.append(",messages[").append(messages.size()); - str.append("]="); - boolean delim = false; - for (Object msg : messages) - { - if (delim) - { - str.append(","); - } - if (msg instanceof String) - { - str.append("'").append(msg).append("'"); - } - else - { - str.append("(").append(msg.getClass().getName()).append(")"); - str.append(msg); - } - delim = true; - } - str.append("]"); - return str.toString(); - } - - public int getMessageCount() - { - int messageCount = 0; - for (Object msg : messages) - { - if (msg instanceof PartialText) - { - PartialText pt = (PartialText)msg; - if (pt.fin) - { - messageCount++; - } - } - else if (msg instanceof PartialBinary) - { - PartialBinary pb = (PartialBinary)msg; - if (pb.fin) - { - messageCount++; - } - } - else - { - messageCount++; - } - } - - return messageCount; - } -} diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/EchoTest.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/EchoTest.java deleted file mode 100644 index 2f0beb5a01f..00000000000 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/EchoTest.java +++ /dev/null @@ -1,341 +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.junit.Assert.assertThat; - -import java.net.URI; -import java.nio.ByteBuffer; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; - -import javax.websocket.ContainerProvider; -import javax.websocket.WebSocketContainer; - -import org.eclipse.jetty.toolchain.test.MavenTestingUtils; -import org.eclipse.jetty.util.BufferUtil; -import org.eclipse.jetty.webapp.WebAppContext; -import org.eclipse.jetty.websocket.jsr356.server.EchoCase.PartialBinary; -import org.eclipse.jetty.websocket.jsr356.server.EchoCase.PartialText; -import org.eclipse.jetty.websocket.jsr356.server.samples.beans.DateTextSocket; -import org.eclipse.jetty.websocket.jsr356.server.samples.binary.ByteBufferSocket; -import org.eclipse.jetty.websocket.jsr356.server.samples.echo.EchoAsyncTextSocket; -import org.eclipse.jetty.websocket.jsr356.server.samples.echo.EchoBasicTextSocket; -import org.eclipse.jetty.websocket.jsr356.server.samples.echo.EchoReturnTextSocket; -import org.eclipse.jetty.websocket.jsr356.server.samples.echo.EchoStatelessAsyncTextSocket; -import org.eclipse.jetty.websocket.jsr356.server.samples.echo.EchoStatelessBasicTextSocket; -import org.eclipse.jetty.websocket.jsr356.server.samples.partial.PartialTextSessionSocket; -import org.eclipse.jetty.websocket.jsr356.server.samples.partial.PartialTextSocket; -import org.eclipse.jetty.websocket.jsr356.server.samples.primitives.BooleanObjectTextSocket; -import org.eclipse.jetty.websocket.jsr356.server.samples.primitives.BooleanTextSocket; -import org.eclipse.jetty.websocket.jsr356.server.samples.primitives.ByteObjectTextSocket; -import org.eclipse.jetty.websocket.jsr356.server.samples.primitives.ByteTextSocket; -import org.eclipse.jetty.websocket.jsr356.server.samples.primitives.CharTextSocket; -import org.eclipse.jetty.websocket.jsr356.server.samples.primitives.CharacterObjectTextSocket; -import org.eclipse.jetty.websocket.jsr356.server.samples.primitives.DoubleObjectTextSocket; -import org.eclipse.jetty.websocket.jsr356.server.samples.primitives.DoubleTextSocket; -import org.eclipse.jetty.websocket.jsr356.server.samples.primitives.FloatObjectTextSocket; -import org.eclipse.jetty.websocket.jsr356.server.samples.primitives.FloatTextSocket; -import org.eclipse.jetty.websocket.jsr356.server.samples.primitives.IntParamTextSocket; -import org.eclipse.jetty.websocket.jsr356.server.samples.primitives.IntTextSocket; -import org.eclipse.jetty.websocket.jsr356.server.samples.primitives.IntegerObjectTextSocket; -import org.eclipse.jetty.websocket.jsr356.server.samples.primitives.LongObjectTextSocket; -import org.eclipse.jetty.websocket.jsr356.server.samples.primitives.LongTextSocket; -import org.eclipse.jetty.websocket.jsr356.server.samples.primitives.ShortObjectTextSocket; -import org.eclipse.jetty.websocket.jsr356.server.samples.primitives.ShortTextSocket; -import org.eclipse.jetty.websocket.jsr356.server.samples.streaming.InputStreamSocket; -import org.eclipse.jetty.websocket.jsr356.server.samples.streaming.ReaderParamSocket; -import org.eclipse.jetty.websocket.jsr356.server.samples.streaming.ReaderSocket; -import org.eclipse.jetty.websocket.jsr356.server.samples.streaming.StringReturnReaderParamSocket; -import org.hamcrest.Matchers; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; - -@RunWith(Parameterized.class) -public class EchoTest -{ - private static final List TESTCASES = new ArrayList<>(); - - private static WSServer server; - private static URI serverUri; - private static WebSocketContainer client; - - static - { - EchoCase.add(TESTCASES,BooleanTextSocket.class).addMessage(true).expect("true"); - EchoCase.add(TESTCASES,BooleanTextSocket.class).addMessage(false).expect("false"); - EchoCase.add(TESTCASES,BooleanTextSocket.class).addMessage(Boolean.TRUE).expect("true"); - EchoCase.add(TESTCASES,BooleanTextSocket.class).addMessage(Boolean.FALSE).expect("false"); - EchoCase.add(TESTCASES,BooleanTextSocket.class).addMessage("true").expect("true"); - EchoCase.add(TESTCASES,BooleanTextSocket.class).addMessage("TRUe").expect("true"); - EchoCase.add(TESTCASES,BooleanTextSocket.class).addMessage("Apple").expect("false"); - EchoCase.add(TESTCASES,BooleanTextSocket.class).addMessage("false").expect("false"); - - EchoCase.add(TESTCASES,BooleanObjectTextSocket.class).addMessage(true).expect("true"); - EchoCase.add(TESTCASES,BooleanObjectTextSocket.class).addMessage(false).expect("false"); - EchoCase.add(TESTCASES,BooleanObjectTextSocket.class).addMessage(Boolean.TRUE).expect("true"); - EchoCase.add(TESTCASES,BooleanObjectTextSocket.class).addMessage(Boolean.FALSE).expect("false"); - EchoCase.add(TESTCASES,BooleanObjectTextSocket.class).addMessage("true").expect("true"); - EchoCase.add(TESTCASES,BooleanObjectTextSocket.class).addMessage("false").expect("false"); - EchoCase.add(TESTCASES,BooleanObjectTextSocket.class).addMessage("FaLsE").expect("false"); - - EchoCase.add(TESTCASES,ByteTextSocket.class).addMessage((byte)88).expect("0x58"); - EchoCase.add(TESTCASES,ByteTextSocket.class).addMessage((byte)101).expect("0x65"); - EchoCase.add(TESTCASES,ByteTextSocket.class).addMessage((byte)202).expect("0xCA"); - EchoCase.add(TESTCASES,ByteTextSocket.class).addMessage(Byte.valueOf((byte)33)).expect("0x21"); - EchoCase.add(TESTCASES,ByteTextSocket.class).addMessage(Byte.valueOf((byte)131)).expect("0x83"); - EchoCase.add(TESTCASES,ByteTextSocket.class).addMessage(Byte.valueOf((byte)232)).expect("0xE8"); - - EchoCase.add(TESTCASES,ByteObjectTextSocket.class).addMessage((byte)88).expect("0x58"); - EchoCase.add(TESTCASES,ByteObjectTextSocket.class).addMessage((byte)101).expect("0x65"); - EchoCase.add(TESTCASES,ByteObjectTextSocket.class).addMessage((byte)202).expect("0xCA"); - EchoCase.add(TESTCASES,ByteObjectTextSocket.class).addMessage(Byte.valueOf((byte)33)).expect("0x21"); - EchoCase.add(TESTCASES,ByteObjectTextSocket.class).addMessage(Byte.valueOf((byte)131)).expect("0x83"); - EchoCase.add(TESTCASES,ByteObjectTextSocket.class).addMessage(Byte.valueOf((byte)232)).expect("0xE8"); - - EchoCase.add(TESTCASES,CharTextSocket.class).addMessage((char)40).expect("("); - EchoCase.add(TESTCASES,CharTextSocket.class).addMessage((char)106).expect("j"); - EchoCase.add(TESTCASES,CharTextSocket.class).addMessage((char)126).expect("~"); - EchoCase.add(TESTCASES,CharTextSocket.class).addMessage(Character.valueOf((char)41)).expect(")"); - EchoCase.add(TESTCASES,CharTextSocket.class).addMessage(Character.valueOf((char)74)).expect("J"); - EchoCase.add(TESTCASES,CharTextSocket.class).addMessage(Character.valueOf((char)64)).expect("@"); - - EchoCase.add(TESTCASES,CharacterObjectTextSocket.class).addMessage((char)40).expect("("); - EchoCase.add(TESTCASES,CharacterObjectTextSocket.class).addMessage((char)106).expect("j"); - EchoCase.add(TESTCASES,CharacterObjectTextSocket.class).addMessage((char)126).expect("~"); - EchoCase.add(TESTCASES,CharacterObjectTextSocket.class).addMessage("E").expect("E"); - EchoCase.add(TESTCASES,CharacterObjectTextSocket.class).addMessage(Character.valueOf((char)41)).expect(")"); - EchoCase.add(TESTCASES,CharacterObjectTextSocket.class).addMessage(Character.valueOf((char)74)).expect("J"); - EchoCase.add(TESTCASES,CharacterObjectTextSocket.class).addMessage(Character.valueOf((char)64)).expect("@"); - - EchoCase.add(TESTCASES,DoubleTextSocket.class).addMessage((double)3.1459).expect("3.1459"); - EchoCase.add(TESTCASES,DoubleTextSocket.class).addMessage((double)123.456).expect("123.4560"); - EchoCase.add(TESTCASES,DoubleTextSocket.class).addMessage(Double.valueOf(55)).expect("55.0000"); - EchoCase.add(TESTCASES,DoubleTextSocket.class).addMessage(Double.valueOf(1.0E8)).expect("100000000.0000"); - EchoCase.add(TESTCASES,DoubleTextSocket.class).addMessage("42").expect("42.0000"); - EchoCase.add(TESTCASES,DoubleTextSocket.class).addMessage(".123").expect("0.1230"); - - EchoCase.add(TESTCASES,DoubleObjectTextSocket.class).addMessage((double)3.1459).expect("3.1459"); - EchoCase.add(TESTCASES,DoubleObjectTextSocket.class).addMessage((double)123.456).expect("123.4560"); - EchoCase.add(TESTCASES,DoubleObjectTextSocket.class).addMessage(Double.valueOf(55)).expect("55.0000"); - EchoCase.add(TESTCASES,DoubleObjectTextSocket.class).addMessage(Double.valueOf(1.0E8)).expect("100000000.0000"); - EchoCase.add(TESTCASES,DoubleObjectTextSocket.class).addMessage("42").expect("42.0000"); - EchoCase.add(TESTCASES,DoubleObjectTextSocket.class).addMessage(".123").expect("0.1230"); - - EchoCase.add(TESTCASES,FloatTextSocket.class).addMessage((float)3.1459).expect("3.1459"); - EchoCase.add(TESTCASES,FloatTextSocket.class).addMessage((float)123.456).expect("123.4560"); - EchoCase.add(TESTCASES,FloatTextSocket.class).addMessage(Float.valueOf(55)).expect("55.0000"); - EchoCase.add(TESTCASES,FloatTextSocket.class).addMessage(Float.valueOf(1.0E8f)).expect("100000000.0000"); - EchoCase.add(TESTCASES,FloatTextSocket.class).addMessage("42").expect("42.0000"); - EchoCase.add(TESTCASES,FloatTextSocket.class).addMessage(".123").expect("0.1230"); - EchoCase.add(TESTCASES,FloatTextSocket.class).addMessage("50505E-6").expect("0.0505"); - - EchoCase.add(TESTCASES,FloatObjectTextSocket.class).addMessage((float)3.1459).expect("3.1459"); - EchoCase.add(TESTCASES,FloatObjectTextSocket.class).addMessage((float)123.456).expect("123.4560"); - EchoCase.add(TESTCASES,FloatObjectTextSocket.class).addMessage(Float.valueOf(55)).expect("55.0000"); - EchoCase.add(TESTCASES,FloatObjectTextSocket.class).addMessage(Float.valueOf(1.0E8f)).expect("100000000.0000"); - EchoCase.add(TESTCASES,FloatObjectTextSocket.class).addMessage("42").expect("42.0000"); - EchoCase.add(TESTCASES,FloatObjectTextSocket.class).addMessage(".123").expect("0.1230"); - EchoCase.add(TESTCASES,FloatObjectTextSocket.class).addMessage("50505E-6").expect("0.0505"); - - EchoCase.add(TESTCASES,IntTextSocket.class).addMessage((int)8).expect("8"); - EchoCase.add(TESTCASES,IntTextSocket.class).addMessage((int)22).expect("22"); - EchoCase.add(TESTCASES,IntTextSocket.class).addMessage("12345678").expect("12345678"); - - EchoCase.add(TESTCASES,IntegerObjectTextSocket.class).addMessage((int)8).expect("8"); - EchoCase.add(TESTCASES,IntegerObjectTextSocket.class).addMessage((int)22).expect("22"); - EchoCase.add(TESTCASES,IntegerObjectTextSocket.class).addMessage("12345678").expect("12345678"); - - EchoCase.add(TESTCASES,LongTextSocket.class).addMessage((int)789).expect("789"); - EchoCase.add(TESTCASES,LongTextSocket.class).addMessage((long)123456L).expect("123456"); - EchoCase.add(TESTCASES,LongTextSocket.class).addMessage(-456).expect("-456"); - - EchoCase.add(TESTCASES,LongObjectTextSocket.class).addMessage((int)789).expect("789"); - EchoCase.add(TESTCASES,LongObjectTextSocket.class).addMessage((long)123456L).expect("123456"); - EchoCase.add(TESTCASES,LongObjectTextSocket.class).addMessage(-234).expect("-234"); - - EchoCase.add(TESTCASES,ShortTextSocket.class).addMessage((int)4).expect("4"); - EchoCase.add(TESTCASES,ShortTextSocket.class).addMessage((long)987).expect("987"); - EchoCase.add(TESTCASES,ShortTextSocket.class).addMessage("32001").expect("32001"); - - EchoCase.add(TESTCASES,ShortObjectTextSocket.class).addMessage((int)4).expect("4"); - EchoCase.add(TESTCASES,ShortObjectTextSocket.class).addMessage((int)987).expect("987"); - EchoCase.add(TESTCASES,ShortObjectTextSocket.class).addMessage(-32001L).expect("-32001"); - - // PathParam based - EchoCase.add(TESTCASES,IntParamTextSocket.class).requestPath("/echo/primitives/integer/params/5678").addMessage(1234).expect("1234|5678"); - - // Text based - EchoCase.add(TESTCASES,EchoBasicTextSocket.class).addMessage("Hello").expect("Hello"); - EchoCase.add(TESTCASES,EchoStatelessBasicTextSocket.class).addMessage("Hello").expect("Hello"); - EchoCase.add(TESTCASES,EchoAsyncTextSocket.class).addMessage("Hello").expect("Hello"); - EchoCase.add(TESTCASES,EchoStatelessAsyncTextSocket.class).addMessage("Hello").expect("Hello"); - EchoCase.add(TESTCASES,EchoReturnTextSocket.class).addMessage("Hello").expect("Hello"); - - // ByteBuffer based - EchoCase.add(TESTCASES,ByteBufferSocket.class).addMessage(BufferUtil.toBuffer("Hello World")).expect("Hello World"); - - // InputStream based - EchoCase.add(TESTCASES,InputStreamSocket.class).addMessage(BufferUtil.toBuffer("Hello World")).expect("Hello World"); - - // Reader based - EchoCase.add(TESTCASES,ReaderSocket.class).addMessage("Hello World").expect("Hello World"); - EchoCase.add(TESTCASES,ReaderParamSocket.class).requestPath("/echo/streaming/readerparam/OhNo").addMessage("Hello World").expect("Hello World|OhNo"); - EchoCase.add(TESTCASES,StringReturnReaderParamSocket.class).requestPath("/echo/streaming/readerparam2/OhMy").addMessage("Hello World") - .expect("Hello World|OhMy"); - - // Partial message based - EchoCase.add(TESTCASES,PartialTextSocket.class) - .addSplitMessage("Saved"," by ","zero") - .expect("('Saved',false)(' by ',false)('zero',true)"); - EchoCase.add(TESTCASES,PartialTextSessionSocket.class) - .addSplitMessage("Built"," for"," the"," future") - .expect("('Built',false)(' for',false)(' the',false)(' future',true)"); - - // Beans - EchoCase.add(TESTCASES, DateTextSocket.class).addMessage("1995.08.01").expect("[1995/08/01]"); - } - - @BeforeClass - public static void startServer() throws Exception - { - Path testdir = MavenTestingUtils.getTargetTestingPath(EchoTest.class.getName()); - server = new WSServer(testdir,"app"); - server.copyWebInf("empty-web.xml"); - - for (EchoCase cases[] : TESTCASES) - { - for (EchoCase ecase : cases) - { - server.copyClass(ecase.serverPojo); - } - } - - server.start(); - serverUri = server.getServerBaseURI(); - - WebAppContext webapp = server.createWebAppContext(); - server.deployWebapp(webapp); - } - - @BeforeClass - public static void startClient() throws Exception - { - client = ContainerProvider.getWebSocketContainer(); - } - - @AfterClass - public static void stopServer() - { - server.stop(); - } - - @Parameters(name = "{0}") - public static Collection data() throws Exception - { - return TESTCASES; - } - - private EchoCase testcase; - - public EchoTest(EchoCase testcase) - { - this.testcase = testcase; - System.err.println(testcase); - } - - @Test(timeout=10000) - public void testEcho() throws Exception - { - EchoClientSocket socket = new EchoClientSocket(); - URI toUri = serverUri.resolve(testcase.path.substring(1)); - - try - { - Future> clientMessagesFuture = socket.expectedMessages(testcase.expectedStrings.size()); - - // Connect - client.connectToServer(socket,toUri); - - // Send Messages - for (Object msg : testcase.messages) - { - if (msg instanceof PartialText) - { - PartialText pt = (PartialText)msg; - socket.sendPartialText(pt.part,pt.fin); - } - else if (msg instanceof PartialBinary) - { - PartialBinary pb = (PartialBinary)msg; - socket.sendPartialBinary(pb.part,pb.fin); - } - else if (msg instanceof ByteBuffer) - { - socket.sendBinary((ByteBuffer) msg); - } - else if (msg instanceof String) - { - socket.sendText((String) msg); - } - else - { - socket.sendObject(msg); - } - } - - // Collect Responses - List received = clientMessagesFuture.get(5, TimeUnit.SECONDS); - - // Validate Responses - assertOrdered("Received Events", testcase.expectedStrings, received); - } - finally - { - // Close - socket.close(); - } - } - - @SuppressWarnings("Duplicates") - public static void assertOrdered(String msg, List expectedList, List actualList) - { - try - { - Assert.assertEquals(msg, expectedList.size(), actualList.size()); - if (!expectedList.isEmpty()) - assertThat(msg, actualList, Matchers.contains(expectedList.toArray())); - } - catch (AssertionError e) - { - System.err.println("Expected: " + expectedList); - System.err.println("Actual : " + actualList); - throw e; - } - } -} diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/SessionTest.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/SessionTest.java deleted file mode 100644 index e81264aea9c..00000000000 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/SessionTest.java +++ /dev/null @@ -1,232 +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 java.net.URI; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; - -import org.eclipse.jetty.servlet.DefaultServlet; -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.client.WebSocketClient; -import org.eclipse.jetty.websocket.common.test.LeakTrackingBufferPoolRule; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; - -@RunWith(Parameterized.class) -public class SessionTest -{ - private interface Case - { - void customize(WebAppContext context); - } - - @Parameters - public static Collection data() - { - List cases = new ArrayList<>(); - cases.add(new Case[] - {context -> - { - // no customization - }}); - cases.add(new Case[] - {context -> - { - // Test with DefaultServlet only - context.addServlet(DefaultServlet.class,"/"); - }}); - cases.add(new Case[] - {context -> - { - // Test with Servlet mapped to "/*" - context.addServlet(DefaultServlet.class,"/*"); - }}); - cases.add(new Case[] - {context -> - { - // Test with Servlet mapped to "/info/*" - context.addServlet(DefaultServlet.class,"/info/*"); - }}); - return cases; - } - - @Rule - public LeakTrackingBufferPoolRule bufferPool = new LeakTrackingBufferPoolRule("Test"); - - private final Case testcase; - private final static AtomicInteger ID = new AtomicInteger(0); - private WSServer server; - private URI serverUri; - - public SessionTest(Case testcase) - { - this.testcase = testcase; - } - - @Before - public void startServer() throws Exception - { - server = new WSServer(MavenTestingUtils.getTargetTestingPath(SessionTest.class.getSimpleName() + "-" + ID.incrementAndGet()),"app"); - server.copyWebInf("empty-web.xml"); - server.copyClass(SessionInfoSocket.class); - server.copyClass(SessionAltConfig.class); - server.start(); - serverUri = server.getServerBaseURI(); - - WebAppContext webapp = server.createWebAppContext(); - testcase.customize(webapp); - server.deployWebapp(webapp); - } - - @After - public void stopServer() - { - server.stop(); - } - - private void assertResponse(String requestPath, String requestMessage, String expectedResponse) throws Exception - { - WebSocketClient client = new WebSocketClient(bufferPool); - try - { - client.start(); - - JettyEchoSocket clientSocket = new JettyEchoSocket(); - Future clientConnectFuture = client.connect(clientSocket,serverUri.resolve(requestPath)); - // wait for connect - Session clientSession = clientConnectFuture.get(5,TimeUnit.SECONDS); - clientSocket.sendMessage(requestMessage); - - String incomingMessage = clientSocket.messageQueue.poll(5, TimeUnit.SECONDS); - Assert.assertThat("Expected message",incomingMessage,is(expectedResponse)); - - clientSession.close(); - clientSocket.awaitCloseEvent("Client"); - } - finally - { - client.stop(); - } - } - - @Test - public void testPathParams_Annotated_Empty() throws Exception - { - assertResponse("info/","pathParams","pathParams[0]"); - } - - @Test - public void testPathParams_Annotated_Single() throws Exception - { - assertResponse("info/apple/","pathParams","pathParams[1]: 'a'=apple"); - } - - @Test - public void testPathParams_Annotated_Double() throws Exception - { - assertResponse("info/apple/pear/","pathParams","pathParams[2]: 'a'=apple: 'b'=pear"); - } - - @Test - public void testPathParams_Annotated_Triple() throws Exception - { - assertResponse("info/apple/pear/cherry/","pathParams","pathParams[3]: 'a'=apple: 'b'=pear: 'c'=cherry"); - } - - @Test - public void testPathParams_Endpoint_Empty() throws Exception - { - assertResponse("einfo/","pathParams","pathParams[0]"); - } - - @Test - public void testPathParams_Endpoint_Single() throws Exception - { - assertResponse("einfo/apple/","pathParams","pathParams[1]: 'a'=apple"); - } - - @Test - public void testPathParams_Endpoint_Double() throws Exception - { - assertResponse("einfo/apple/pear/","pathParams","pathParams[2]: 'a'=apple: 'b'=pear"); - } - - @Test - public void testPathParams_Endpoint_Triple() throws Exception - { - assertResponse("einfo/apple/pear/cherry/","pathParams","pathParams[3]: 'a'=apple: 'b'=pear: 'c'=cherry"); - } - - @Test - public void testRequestUri_Annotated_Basic() throws Exception - { - URI expectedUri = serverUri.resolve("info/"); - assertResponse("info/","requestUri","requestUri=" + expectedUri.toASCIIString()); - } - - @Test - public void testRequestUri_Annotated_WithPathParam() throws Exception - { - URI expectedUri = serverUri.resolve("info/apple/banana/"); - assertResponse("info/apple/banana/","requestUri","requestUri=" + expectedUri.toASCIIString()); - } - - @Test - public void testRequestUri_Annotated_WithPathParam_WithQuery() throws Exception - { - URI expectedUri = serverUri.resolve("info/apple/banana/?fruit=fresh&store=grandmasfarm"); - assertResponse("info/apple/banana/?fruit=fresh&store=grandmasfarm","requestUri","requestUri=" + expectedUri.toASCIIString()); - } - - @Test - public void testRequestUri_Endpoint_Basic() throws Exception - { - URI expectedUri = serverUri.resolve("einfo/"); - assertResponse("einfo/","requestUri","requestUri=" + expectedUri.toASCIIString()); - } - - @Test - public void testRequestUri_Endpoint_WithPathParam() throws Exception - { - URI expectedUri = serverUri.resolve("einfo/apple/banana/"); - assertResponse("einfo/apple/banana/","requestUri","requestUri=" + expectedUri.toASCIIString()); - } - - @Test - public void testRequestUri_Endpoint_WithPathParam_WithQuery() throws Exception - { - URI expectedUri = serverUri.resolve("einfo/apple/banana/?fruit=fresh&store=grandmasfarm"); - assertResponse("einfo/apple/banana/?fruit=fresh&store=grandmasfarm","requestUri","requestUri=" + expectedUri.toASCIIString()); - } -} diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/TextStreamTest.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/TextStreamTest.java deleted file mode 100644 index f6360b94e60..00000000000 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/TextStreamTest.java +++ /dev/null @@ -1,179 +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 java.io.IOException; -import java.io.Reader; -import java.io.Writer; -import java.net.URI; -import java.util.Random; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import javax.websocket.ClientEndpoint; -import javax.websocket.ContainerProvider; -import javax.websocket.OnMessage; -import javax.websocket.Session; -import javax.websocket.WebSocketContainer; -import javax.websocket.server.ServerEndpoint; -import javax.websocket.server.ServerEndpointConfig; - -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.ServerConnector; -import org.eclipse.jetty.servlet.ServletContextHandler; -import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -public class TextStreamTest -{ - private static final String PATH = "/echo"; - private static final String CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; - - private Server server; - private ServerConnector connector; - private WebSocketContainer wsClient; - - @Before - public void prepare() throws Exception - { - server = new Server(); - connector = new ServerConnector(server); - server.addConnector(connector); - - ServletContextHandler context = new ServletContextHandler(server, "/", true, false); - ServerContainer container = WebSocketServerContainerInitializer.configureContext(context); - ServerEndpointConfig config = ServerEndpointConfig.Builder.create(ServerTextStreamer.class, PATH).build(); - container.addEndpoint(config); - - server.start(); - - wsClient = ContainerProvider.getWebSocketContainer(); - } - - @After - public void dispose() throws Exception - { - server.stop(); - } - - @Test - public void testEchoWithMediumMessage() throws Exception - { - testEcho(1024); - } - - @Test - public void testLargestMessage() throws Exception - { - testEcho(wsClient.getDefaultMaxBinaryMessageBufferSize()); - } - - private void testEcho(int size) throws Exception - { - char[] data = randomChars(size); - URI uri = URI.create("ws://localhost:" + connector.getLocalPort() + PATH); - ClientTextStreamer client = new ClientTextStreamer(); - Session session = wsClient.connectToServer(client, uri); - - try (Writer output = session.getBasicRemote().getSendWriter()) - { - output.write(data); - } - - Assert.assertTrue(client.await(5, TimeUnit.SECONDS)); - Assert.assertArrayEquals(data, client.getEcho()); - } - - @Test - public void testMoreThanLargestMessageOneByteAtATime() throws Exception - { - int size = wsClient.getDefaultMaxBinaryMessageBufferSize() + 16; - char[] data = randomChars(size); - URI uri = URI.create("ws://localhost:" + connector.getLocalPort() + PATH); - ClientTextStreamer client = new ClientTextStreamer(); - Session session = wsClient.connectToServer(client, uri); - - try (Writer output = session.getBasicRemote().getSendWriter()) - { - for (int i = 0; i < size; ++i) - output.write(data[i]); - } - - Assert.assertTrue(client.await(5, TimeUnit.SECONDS)); - Assert.assertArrayEquals(data, client.getEcho()); - } - - private char[] randomChars(int size) - { - char[] data = new char[size]; - Random random = new Random(); - for (int i = 0; i < data.length; ++i) - data[i] = CHARS.charAt(random.nextInt(CHARS.length())); - return data; - } - - @ClientEndpoint - public static class ClientTextStreamer - { - private final CountDownLatch latch = new CountDownLatch(1); - private final StringBuilder output = new StringBuilder(); - - @OnMessage - public void echoed(Reader input) throws IOException - { - while (true) - { - int read = input.read(); - if (read < 0) - break; - output.append((char)read); - } - latch.countDown(); - } - - public char[] getEcho() - { - return output.toString().toCharArray(); - } - - public boolean await(long timeout, TimeUnit unit) throws InterruptedException - { - return latch.await(timeout, unit); - } - } - - @ServerEndpoint(PATH) - public static class ServerTextStreamer - { - @OnMessage - public void echo(Session session, Reader input) throws IOException - { - char[] buffer = new char[128]; - try (Writer output = session.getBasicRemote().getSendWriter()) - { - int read; - while ((read = input.read(buffer)) >= 0) - output.write(buffer, 0, read); - } - } - } -} diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/binary/ByteBufferSocket.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/binary/ByteBufferSocket.java index 09a87877f0e..57ade0359ed 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/binary/ByteBufferSocket.java +++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/binary/ByteBufferSocket.java @@ -26,10 +26,10 @@ import javax.websocket.OnMessage; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; +import org.eclipse.jetty.toolchain.test.StackUtils; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.websocket.common.util.StackUtil; @ServerEndpoint("/echo/binary/bytebuffer") public class ByteBufferSocket @@ -46,6 +46,6 @@ public class ByteBufferSocket public void onError(Session session, Throwable cause) throws IOException { LOG.warn("Error",cause); - session.getBasicRemote().sendText("Exception: " + StackUtil.toString(cause)); + session.getBasicRemote().sendText("Exception: " + StackUtils.toString(cause)); } } diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/partial/PartialTextSessionSocket.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/partial/PartialTextSessionSocket.java index 11ef1b2a34e..d91d37ac211 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/partial/PartialTextSessionSocket.java +++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/partial/PartialTextSessionSocket.java @@ -25,9 +25,9 @@ import javax.websocket.OnMessage; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; +import org.eclipse.jetty.toolchain.test.StackUtils; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.websocket.common.util.StackUtil; @ServerEndpoint("/echo/partial/textsession") public class PartialTextSessionSocket @@ -50,6 +50,6 @@ public class PartialTextSessionSocket public void onError(Throwable cause, Session session) throws IOException { LOG.warn("Error",cause); - session.getBasicRemote().sendText("Exception: " + StackUtil.toString(cause)); + session.getBasicRemote().sendText("Exception: " + StackUtils.toString(cause)); } } diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/partial/PartialTextSocket.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/partial/PartialTextSocket.java index 27f1315eafc..0c048df76b9 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/partial/PartialTextSocket.java +++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/partial/PartialTextSocket.java @@ -26,9 +26,9 @@ import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; +import org.eclipse.jetty.toolchain.test.StackUtils; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.websocket.common.util.StackUtil; @ServerEndpoint("/echo/partial/text") public class PartialTextSocket @@ -58,6 +58,6 @@ public class PartialTextSocket public void onError(Throwable cause) throws IOException { LOG.warn("Error",cause); - session.getBasicRemote().sendText("Exception: " + StackUtil.toString(cause)); + session.getBasicRemote().sendText("Exception: " + StackUtils.toString(cause)); } } diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/BooleanObjectTextParamSocket.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/BooleanObjectTextParamSocket.java index b7620b3a95b..06e8ee55ad0 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/BooleanObjectTextParamSocket.java +++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/BooleanObjectTextParamSocket.java @@ -27,9 +27,9 @@ import javax.websocket.Session; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; +import org.eclipse.jetty.toolchain.test.StackUtils; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.websocket.common.util.StackUtil; @ServerEndpoint("/echo/primitives/booleanobject/params/{a}") public class BooleanObjectTextParamSocket @@ -62,6 +62,6 @@ public class BooleanObjectTextParamSocket public void onError(Throwable cause) throws IOException { LOG.warn("Error",cause); - session.getBasicRemote().sendText("Exception: " + StackUtil.toString(cause)); + session.getBasicRemote().sendText("Exception: " + StackUtils.toString(cause)); } } diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/BooleanObjectTextSocket.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/BooleanObjectTextSocket.java index 7188686a360..dcb7e74086d 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/BooleanObjectTextSocket.java +++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/BooleanObjectTextSocket.java @@ -26,9 +26,9 @@ import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; +import org.eclipse.jetty.toolchain.test.StackUtils; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.websocket.common.util.StackUtil; @ServerEndpoint("/echo/primitives/booleanobject") public class BooleanObjectTextSocket @@ -61,6 +61,6 @@ public class BooleanObjectTextSocket public void onError(Throwable cause) throws IOException { LOG.warn("Error",cause); - session.getBasicRemote().sendText("Exception: " + StackUtil.toString(cause)); + session.getBasicRemote().sendText("Exception: " + StackUtils.toString(cause)); } } diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/BooleanTextParamSocket.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/BooleanTextParamSocket.java index f72f86644cc..4e802c6d6d6 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/BooleanTextParamSocket.java +++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/BooleanTextParamSocket.java @@ -27,9 +27,9 @@ import javax.websocket.Session; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; +import org.eclipse.jetty.toolchain.test.StackUtils; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.websocket.common.util.StackUtil; @ServerEndpoint("/echo/primitives/boolean/params/{a}") public class BooleanTextParamSocket @@ -55,6 +55,6 @@ public class BooleanTextParamSocket public void onError(Throwable cause) throws IOException { LOG.warn("Error",cause); - session.getBasicRemote().sendText("Exception: " + StackUtil.toString(cause)); + session.getBasicRemote().sendText("Exception: " + StackUtils.toString(cause)); } } diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/BooleanTextSocket.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/BooleanTextSocket.java index 41914bb8837..cb98088f269 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/BooleanTextSocket.java +++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/BooleanTextSocket.java @@ -26,9 +26,9 @@ import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; +import org.eclipse.jetty.toolchain.test.StackUtils; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.websocket.common.util.StackUtil; @ServerEndpoint("/echo/primitives/boolean") public class BooleanTextSocket @@ -54,6 +54,6 @@ public class BooleanTextSocket public void onError(Throwable cause) throws IOException { LOG.warn("Error",cause); - session.getBasicRemote().sendText("Exception: " + StackUtil.toString(cause)); + session.getBasicRemote().sendText("Exception: " + StackUtils.toString(cause)); } } diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/ByteObjectTextSocket.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/ByteObjectTextSocket.java index fd33d65a9c9..df1162043fb 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/ByteObjectTextSocket.java +++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/ByteObjectTextSocket.java @@ -26,9 +26,9 @@ import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; +import org.eclipse.jetty.toolchain.test.StackUtils; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.websocket.common.util.StackUtil; @ServerEndpoint("/echo/primitives/byteobject") public class ByteObjectTextSocket @@ -61,6 +61,6 @@ public class ByteObjectTextSocket public void onError(Throwable cause) throws IOException { LOG.warn("Error",cause); - session.getBasicRemote().sendText("Exception: " + StackUtil.toString(cause)); + session.getBasicRemote().sendText("Exception: " + StackUtils.toString(cause)); } } diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/ByteTextSocket.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/ByteTextSocket.java index 88d6de135de..2e67a4272ed 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/ByteTextSocket.java +++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/ByteTextSocket.java @@ -26,9 +26,9 @@ import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; +import org.eclipse.jetty.toolchain.test.StackUtils; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.websocket.common.util.StackUtil; @ServerEndpoint("/echo/primitives/byte") public class ByteTextSocket @@ -54,6 +54,6 @@ public class ByteTextSocket public void onError(Throwable cause) throws IOException { LOG.warn("Error",cause); - session.getBasicRemote().sendText("Exception: " + StackUtil.toString(cause)); + session.getBasicRemote().sendText("Exception: " + StackUtils.toString(cause)); } } diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/CharTextSocket.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/CharTextSocket.java index 90aca188cdb..865d549700b 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/CharTextSocket.java +++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/CharTextSocket.java @@ -26,9 +26,9 @@ import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; +import org.eclipse.jetty.toolchain.test.StackUtils; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.websocket.common.util.StackUtil; @ServerEndpoint("/echo/primitives/char") public class CharTextSocket @@ -54,6 +54,6 @@ public class CharTextSocket public void onError(Throwable cause) throws IOException { LOG.warn("Error",cause); - session.getBasicRemote().sendText("Exception: " + StackUtil.toString(cause)); + session.getBasicRemote().sendText("Exception: " + StackUtils.toString(cause)); } } diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/CharacterObjectTextSocket.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/CharacterObjectTextSocket.java index d1c366185f7..0c2d38bbd5a 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/CharacterObjectTextSocket.java +++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/CharacterObjectTextSocket.java @@ -26,9 +26,9 @@ import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; +import org.eclipse.jetty.toolchain.test.StackUtils; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.websocket.common.util.StackUtil; @ServerEndpoint("/echo/primitives/characterobject") public class CharacterObjectTextSocket @@ -61,6 +61,6 @@ public class CharacterObjectTextSocket public void onError(Throwable cause) throws IOException { LOG.warn("Error",cause); - session.getBasicRemote().sendText("Exception: " + StackUtil.toString(cause)); + session.getBasicRemote().sendText("Exception: " + StackUtils.toString(cause)); } } diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/DoubleObjectTextSocket.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/DoubleObjectTextSocket.java index eef753a5d1b..b3083f6b285 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/DoubleObjectTextSocket.java +++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/DoubleObjectTextSocket.java @@ -27,9 +27,9 @@ import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; +import org.eclipse.jetty.toolchain.test.StackUtils; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.websocket.common.util.StackUtil; @ServerEndpoint("/echo/primitives/doubleobject") public class DoubleObjectTextSocket @@ -62,6 +62,6 @@ public class DoubleObjectTextSocket public void onError(Throwable cause) throws IOException { LOG.warn("Error",cause); - session.getBasicRemote().sendText("Exception: " + StackUtil.toString(cause)); + session.getBasicRemote().sendText("Exception: " + StackUtils.toString(cause)); } } diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/DoubleTextSocket.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/DoubleTextSocket.java index 9de16e5ac08..907631874b4 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/DoubleTextSocket.java +++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/DoubleTextSocket.java @@ -27,9 +27,9 @@ import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; +import org.eclipse.jetty.toolchain.test.StackUtils; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.websocket.common.util.StackUtil; @ServerEndpoint("/echo/primitives/double") public class DoubleTextSocket @@ -55,6 +55,6 @@ public class DoubleTextSocket public void onError(Throwable cause) throws IOException { LOG.warn("Error",cause); - session.getBasicRemote().sendText("Exception: " + StackUtil.toString(cause)); + session.getBasicRemote().sendText("Exception: " + StackUtils.toString(cause)); } } diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/FloatObjectTextSocket.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/FloatObjectTextSocket.java index aba1a4bf45c..98d894de0dc 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/FloatObjectTextSocket.java +++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/FloatObjectTextSocket.java @@ -27,9 +27,9 @@ import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; +import org.eclipse.jetty.toolchain.test.StackUtils; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.websocket.common.util.StackUtil; @ServerEndpoint("/echo/primitives/floatobject") public class FloatObjectTextSocket @@ -62,6 +62,6 @@ public class FloatObjectTextSocket public void onError(Throwable cause) throws IOException { LOG.warn("Error",cause); - session.getBasicRemote().sendText("Exception: " + StackUtil.toString(cause)); + session.getBasicRemote().sendText("Exception: " + StackUtils.toString(cause)); } } diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/FloatTextSocket.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/FloatTextSocket.java index 6bcbf088533..9e7f3572bd1 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/FloatTextSocket.java +++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/FloatTextSocket.java @@ -27,9 +27,9 @@ import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; +import org.eclipse.jetty.toolchain.test.StackUtils; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.websocket.common.util.StackUtil; @ServerEndpoint("/echo/primitives/float") public class FloatTextSocket @@ -55,6 +55,6 @@ public class FloatTextSocket public void onError(Throwable cause) throws IOException { LOG.warn("Error",cause); - session.getBasicRemote().sendText("Exception: " + StackUtil.toString(cause)); + session.getBasicRemote().sendText("Exception: " + StackUtils.toString(cause)); } } diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/IntParamTextSocket.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/IntParamTextSocket.java index 5612ed9eac4..07fbfe4da21 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/IntParamTextSocket.java +++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/IntParamTextSocket.java @@ -27,9 +27,9 @@ import javax.websocket.Session; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; +import org.eclipse.jetty.toolchain.test.StackUtils; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.websocket.common.util.StackUtil; @ServerEndpoint("/echo/primitives/integer/params/{a}") public class IntParamTextSocket @@ -55,6 +55,6 @@ public class IntParamTextSocket public void onError(Throwable cause) throws IOException { LOG.warn("Error",cause); - session.getBasicRemote().sendText("Exception: " + StackUtil.toString(cause)); + session.getBasicRemote().sendText("Exception: " + StackUtils.toString(cause)); } } diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/IntTextSocket.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/IntTextSocket.java index 8c5ba81b34a..309ba3e196e 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/IntTextSocket.java +++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/IntTextSocket.java @@ -26,9 +26,9 @@ import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; +import org.eclipse.jetty.toolchain.test.StackUtils; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.websocket.common.util.StackUtil; @ServerEndpoint("/echo/primitives/integer") public class IntTextSocket @@ -54,6 +54,6 @@ public class IntTextSocket public void onError(Throwable cause) throws IOException { LOG.warn("Error",cause); - session.getBasicRemote().sendText("Exception: " + StackUtil.toString(cause)); + session.getBasicRemote().sendText("Exception: " + StackUtils.toString(cause)); } } diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/IntegerObjectParamTextSocket.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/IntegerObjectParamTextSocket.java index c07f551029c..aa13f1c84d7 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/IntegerObjectParamTextSocket.java +++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/IntegerObjectParamTextSocket.java @@ -27,9 +27,9 @@ import javax.websocket.Session; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; +import org.eclipse.jetty.toolchain.test.StackUtils; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.websocket.common.util.StackUtil; @ServerEndpoint("/echo/primitives/integerobject/params/{a}") public class IntegerObjectParamTextSocket @@ -62,6 +62,6 @@ public class IntegerObjectParamTextSocket public void onError(Throwable cause) throws IOException { LOG.warn("Error",cause); - session.getBasicRemote().sendText("Exception: " + StackUtil.toString(cause)); + session.getBasicRemote().sendText("Exception: " + StackUtils.toString(cause)); } } diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/IntegerObjectTextSocket.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/IntegerObjectTextSocket.java index db7a4bdb163..00aaef26242 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/IntegerObjectTextSocket.java +++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/IntegerObjectTextSocket.java @@ -26,9 +26,9 @@ import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; +import org.eclipse.jetty.toolchain.test.StackUtils; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.websocket.common.util.StackUtil; @ServerEndpoint("/echo/primitives/integerobject") public class IntegerObjectTextSocket @@ -61,6 +61,6 @@ public class IntegerObjectTextSocket public void onError(Throwable cause) throws IOException { LOG.warn("Error",cause); - session.getBasicRemote().sendText("Exception: " + StackUtil.toString(cause)); + session.getBasicRemote().sendText("Exception: " + StackUtils.toString(cause)); } } diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/LongObjectTextSocket.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/LongObjectTextSocket.java index b6a759a7009..21d43aff98d 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/LongObjectTextSocket.java +++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/LongObjectTextSocket.java @@ -26,9 +26,9 @@ import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; +import org.eclipse.jetty.toolchain.test.StackUtils; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.websocket.common.util.StackUtil; @ServerEndpoint("/echo/primitives/longobject") public class LongObjectTextSocket @@ -61,6 +61,6 @@ public class LongObjectTextSocket public void onError(Throwable cause) throws IOException { LOG.warn("Error",cause); - session.getBasicRemote().sendText("Exception: " + StackUtil.toString(cause)); + session.getBasicRemote().sendText("Exception: " + StackUtils.toString(cause)); } } diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/LongTextSocket.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/LongTextSocket.java index 75515e8b27a..b12f598c751 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/LongTextSocket.java +++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/LongTextSocket.java @@ -26,9 +26,9 @@ import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; +import org.eclipse.jetty.toolchain.test.StackUtils; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.websocket.common.util.StackUtil; @ServerEndpoint("/echo/primitives/long") public class LongTextSocket @@ -54,6 +54,6 @@ public class LongTextSocket public void onError(Throwable cause) throws IOException { LOG.warn("Error",cause); - session.getBasicRemote().sendText("Exception: " + StackUtil.toString(cause)); + session.getBasicRemote().sendText("Exception: " + StackUtils.toString(cause)); } } diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/ShortObjectTextSocket.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/ShortObjectTextSocket.java index 3d5aea293e0..182895ebea1 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/ShortObjectTextSocket.java +++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/ShortObjectTextSocket.java @@ -26,9 +26,9 @@ import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; +import org.eclipse.jetty.toolchain.test.StackUtils; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.websocket.common.util.StackUtil; @ServerEndpoint("/echo/primitives/shortobject") public class ShortObjectTextSocket @@ -61,6 +61,6 @@ public class ShortObjectTextSocket public void onError(Throwable cause) throws IOException { LOG.warn("Error",cause); - session.getBasicRemote().sendText("Exception: " + StackUtil.toString(cause)); + session.getBasicRemote().sendText("Exception: " + StackUtils.toString(cause)); } } diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/ShortTextSocket.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/ShortTextSocket.java index 7e3cab52484..05e7fd58f2d 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/ShortTextSocket.java +++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/primitives/ShortTextSocket.java @@ -26,9 +26,9 @@ import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; +import org.eclipse.jetty.toolchain.test.StackUtils; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.websocket.common.util.StackUtil; @ServerEndpoint("/echo/primitives/short") public class ShortTextSocket @@ -54,6 +54,6 @@ public class ShortTextSocket public void onError(Throwable cause) throws IOException { LOG.warn("Error",cause); - session.getBasicRemote().sendText("Exception: " + StackUtil.toString(cause)); + session.getBasicRemote().sendText("Exception: " + StackUtils.toString(cause)); } } diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/streaming/InputStreamSocket.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/streaming/InputStreamSocket.java index 44f92030b1a..fa85aca06db 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/streaming/InputStreamSocket.java +++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/streaming/InputStreamSocket.java @@ -26,11 +26,11 @@ import javax.websocket.OnMessage; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; +import org.eclipse.jetty.toolchain.test.StackUtils; import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.websocket.common.util.StackUtil; @ServerEndpoint("/echo/streaming/inputstream") public class InputStreamSocket @@ -47,6 +47,6 @@ public class InputStreamSocket public void onError(Session session, Throwable cause) throws IOException { LOG.warn("Error",cause); - session.getBasicRemote().sendText("Exception: " + StackUtil.toString(cause)); + session.getBasicRemote().sendText("Exception: " + StackUtils.toString(cause)); } } diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/streaming/ReaderParamSocket.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/streaming/ReaderParamSocket.java index a2794dc0cb6..4450ff70341 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/streaming/ReaderParamSocket.java +++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/streaming/ReaderParamSocket.java @@ -28,10 +28,10 @@ import javax.websocket.Session; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; +import org.eclipse.jetty.toolchain.test.StackUtils; import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.websocket.common.util.StackUtil; @ServerEndpoint("/echo/streaming/readerparam/{param}") public class ReaderParamSocket @@ -60,6 +60,6 @@ public class ReaderParamSocket public void onError(Throwable cause) throws IOException { LOG.warn("Error",cause); - session.getBasicRemote().sendText("Exception: " + StackUtil.toString(cause)); + session.getBasicRemote().sendText("Exception: " + StackUtils.toString(cause)); } } diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/streaming/ReaderSocket.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/streaming/ReaderSocket.java index f22cb41f4a3..e97f4cfab70 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/streaming/ReaderSocket.java +++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/streaming/ReaderSocket.java @@ -26,10 +26,10 @@ import javax.websocket.OnMessage; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; +import org.eclipse.jetty.toolchain.test.StackUtils; import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.websocket.common.util.StackUtil; @ServerEndpoint("/echo/streaming/reader") public class ReaderSocket @@ -46,6 +46,6 @@ public class ReaderSocket public void onError(Session session, Throwable cause) throws IOException { LOG.warn("Error",cause); - session.getBasicRemote().sendText("Exception: " + StackUtil.toString(cause)); + session.getBasicRemote().sendText("Exception: " + StackUtils.toString(cause)); } } diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/streaming/StringReturnReaderParamSocket.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/streaming/StringReturnReaderParamSocket.java index d600e65f68b..956b4aa98de 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/streaming/StringReturnReaderParamSocket.java +++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/streaming/StringReturnReaderParamSocket.java @@ -27,10 +27,10 @@ import javax.websocket.Session; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; +import org.eclipse.jetty.toolchain.test.StackUtils; import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.websocket.common.util.StackUtil; @ServerEndpoint("/echo/streaming/readerparam2/{param}") public class StringReturnReaderParamSocket @@ -51,6 +51,6 @@ public class StringReturnReaderParamSocket public void onError(Session session, Throwable cause) throws IOException { LOG.warn("Error",cause); - session.getBasicRemote().sendText("Exception: " + StackUtil.toString(cause)); + session.getBasicRemote().sendText("Exception: " + StackUtils.toString(cause)); } } diff --git a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/WebSocketConstants.java b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/WebSocketConstants.java index 5e9220b0009..3720da5a3aa 100644 --- a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/WebSocketConstants.java +++ b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/WebSocketConstants.java @@ -23,5 +23,9 @@ public final class WebSocketConstants public static final String SEC_WEBSOCKET_EXTENSIONS = "Sec-WebSocket-Extensions"; public static final String SEC_WEBSOCKET_PROTOCOL = "Sec-WebSocket-Protocol"; public static final String SEC_WEBSOCKET_VERSION = "Sec-WebSocket-Version"; + public static final String SEC_WEBSOCKET_ACCEPT = "Sec-WebSocket-Accept"; + public static final String SEC_WEBSOCKET_ORIGIN = "Sec-WebSocket-Origin"; + public static final String SEC_WEBSOCKET_KEY = "Sec-WebSocket-Key"; public static final int SPEC_VERSION = 13; } + diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/AbstractWebSocketConnection.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/AbstractWebSocketConnection.java index 60927613da9..feee2f9c1a2 100644 --- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/AbstractWebSocketConnection.java +++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/AbstractWebSocketConnection.java @@ -140,13 +140,9 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp // close FrameFlusher, we cannot write anymore at this point. flusher.close(); - EndPoint endPoint = getEndPoint(); // We need to gently close first, to allow // SSL close alerts to be sent by Jetty - if (LOG.isDebugEnabled()) - LOG.debug("Shutting down output {}",endPoint); - - endPoint.close(); + getEndPoint().close(); closed.set(true); } diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/message/MessageInputStream.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/message/MessageInputStream.java index 1e341e75a80..c5cb9974770 100644 --- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/message/MessageInputStream.java +++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/message/MessageInputStream.java @@ -48,9 +48,7 @@ public class MessageInputStream extends InputStream implements MessageSink public void accept(Frame frame, FrameCallback callback) { if (LOG.isDebugEnabled()) - { LOG.debug("accepting {}", frame); - } // If closed, we should just toss incoming payloads into the bit bucket. if (closed.get()) @@ -83,6 +81,9 @@ public class MessageInputStream extends InputStream implements MessageSink @Override public void close() throws IOException { + if(LOG.isDebugEnabled()) + LOG.debug("close()"); + if (closed.compareAndSet(false, true)) { synchronized (buffers) @@ -96,6 +97,8 @@ public class MessageInputStream extends InputStream implements MessageSink private void shutdown() { + if(LOG.isDebugEnabled()) + LOG.debug("shutdown()"); closed.set(true); // Removed buffers that may have remained in the queue. buffers.clear(); @@ -144,7 +147,7 @@ public class MessageInputStream extends InputStream implements MessageSink { try { - while ((result = buffers.poll()) == null) + while ((result = buffers.peek()) == null) { // TODO: handle read timeout here? buffers.wait(); @@ -159,6 +162,8 @@ public class MessageInputStream extends InputStream implements MessageSink if (result == EOF) { + if (LOG.isDebugEnabled()) + LOG.debug("Read EOF"); shutdown(); return -1; } @@ -166,10 +171,11 @@ public class MessageInputStream extends InputStream implements MessageSink // We have content int fillLen = Math.min(result.buffer.remaining(), len); result.buffer.get(b, off, fillLen); - + if (!result.buffer.hasRemaining()) { result.callback.succeed(); + buffers.pop(); } // return number of bytes actually copied into buffer diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/message/MessageOutputStream.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/message/MessageOutputStream.java index 52595d2d4c7..6e4e1df0dd5 100644 --- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/message/MessageOutputStream.java +++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/message/MessageOutputStream.java @@ -45,6 +45,7 @@ public class MessageOutputStream extends OutputStream private final ByteBufferPool bufferPool; private final BlockingWriteCallback blocker; private long frameCount; + private long bytesSent; private BinaryFrame frame; private ByteBuffer buffer; private WriteCallback callback; @@ -118,7 +119,7 @@ public class MessageOutputStream extends OutputStream flush(true); bufferPool.release(buffer); if (LOG.isDebugEnabled()) - LOG.debug("Stream closed, {} frames sent", frameCount); + LOG.debug("Stream closed, {} frames ({} bytes) sent", frameCount, bytesSent); // Notify without holding locks. notifySuccess(); } @@ -160,29 +161,32 @@ public class MessageOutputStream extends OutputStream } } - private void send(byte[] bytes, int offset, int length) throws IOException + private void send(byte[] bytes, final int offset, final int length) throws IOException { synchronized (this) { if (closed) throw new IOException("Stream is closed"); - while (length > 0) + int remaining = length; + int off = offset; + while (remaining > 0) { // There may be no space available, we want // to handle correctly when space == 0. int space = buffer.remaining(); int size = Math.min(space, length); - buffer.put(bytes, offset, size); - offset += size; - length -= size; - if (length > 0) + buffer.put(bytes, off, size); + off += size; + remaining -= size; + if (remaining > 0) { // If we could not write everything, it means // that the buffer was full, so flush it. flush(false); } } + bytesSent += length; } } diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/GeneratorTest.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/GeneratorTest.java index 878318ee99e..c028eec628d 100644 --- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/GeneratorTest.java +++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/GeneratorTest.java @@ -24,6 +24,7 @@ import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.util.Arrays; +import org.eclipse.jetty.toolchain.test.Hex; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.log.Log; @@ -43,7 +44,6 @@ import org.eclipse.jetty.websocket.common.test.ByteBufferAssert; import org.eclipse.jetty.websocket.common.test.ParserCapture; import org.eclipse.jetty.websocket.common.test.UnitGenerator; import org.eclipse.jetty.websocket.common.test.UnitParser; -import org.eclipse.jetty.websocket.common.util.Hex; import org.junit.Assert; import org.junit.Rule; import org.junit.Test; diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/ParserTest.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/ParserTest.java index d1c7e5dd1c6..ccd59c7395e 100644 --- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/ParserTest.java +++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/ParserTest.java @@ -31,6 +31,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import org.eclipse.jetty.toolchain.test.Hex; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.websocket.api.MessageTooLargeException; @@ -47,7 +48,6 @@ import org.eclipse.jetty.websocket.common.frames.TextFrame; import org.eclipse.jetty.websocket.common.test.ParserCapture; import org.eclipse.jetty.websocket.common.test.UnitGenerator; import org.eclipse.jetty.websocket.common.test.UnitParser; -import org.eclipse.jetty.websocket.common.util.Hex; import org.eclipse.jetty.websocket.common.util.MaskedByteBuffer; import org.hamcrest.CoreMatchers; import org.junit.Assert; diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/WebSocketFrameTest.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/WebSocketFrameTest.java index 04f2b98f368..8acbae4a4a2 100644 --- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/WebSocketFrameTest.java +++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/WebSocketFrameTest.java @@ -22,6 +22,7 @@ import static org.hamcrest.Matchers.is; import java.nio.ByteBuffer; +import org.eclipse.jetty.toolchain.test.Hex; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.websocket.api.StatusCode; import org.eclipse.jetty.websocket.api.WebSocketPolicy; @@ -30,7 +31,6 @@ import org.eclipse.jetty.websocket.common.frames.CloseFrame; import org.eclipse.jetty.websocket.common.frames.PingFrame; import org.eclipse.jetty.websocket.common.frames.TextFrame; import org.eclipse.jetty.websocket.common.test.LeakTrackingBufferPoolRule; -import org.eclipse.jetty.websocket.common.util.Hex; import org.junit.Assert; import org.junit.Before; import org.junit.Rule; diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/compress/CapturedHexPayloads.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/compress/CapturedHexPayloads.java index 8381c5e04a6..fda9677819d 100644 --- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/compress/CapturedHexPayloads.java +++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/compress/CapturedHexPayloads.java @@ -21,11 +21,11 @@ package org.eclipse.jetty.websocket.common.extensions.compress; import java.util.ArrayList; import java.util.List; +import org.eclipse.jetty.toolchain.test.Hex; import org.eclipse.jetty.websocket.api.BatchMode; import org.eclipse.jetty.websocket.api.FrameCallback; import org.eclipse.jetty.websocket.api.extensions.Frame; import org.eclipse.jetty.websocket.api.extensions.OutgoingFrames; -import org.eclipse.jetty.websocket.common.util.Hex; public class CapturedHexPayloads implements OutgoingFrames { diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/io/payload/DeMaskProcessorTest.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/io/payload/DeMaskProcessorTest.java index 520c60e2b6b..6734d6918db 100644 --- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/io/payload/DeMaskProcessorTest.java +++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/io/payload/DeMaskProcessorTest.java @@ -23,6 +23,7 @@ import static org.hamcrest.Matchers.is; import java.nio.ByteBuffer; import java.util.Arrays; +import org.eclipse.jetty.toolchain.test.Hex; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.log.Log; @@ -31,7 +32,6 @@ import org.eclipse.jetty.websocket.common.WebSocketFrame; import org.eclipse.jetty.websocket.common.frames.TextFrame; import org.eclipse.jetty.websocket.common.test.ByteBufferAssert; import org.eclipse.jetty.websocket.common.test.UnitGenerator; -import org.eclipse.jetty.websocket.common.util.Hex; import org.junit.Assert; import org.junit.Test; @@ -80,7 +80,7 @@ public class DeMaskProcessorTest payload.position(6); // where payload starts LOG.debug("Payload: {}",BufferUtil.toDetailString(payload)); - LOG.debug("Pre-Processed: {}",Hex.asHex(payload)); + LOG.debug("Pre-Processed: {}", Hex.asHex(payload)); DeMaskProcessor demask = new DeMaskProcessor(); demask.reset(frame); @@ -97,8 +97,8 @@ public class DeMaskProcessorTest demask.process(slice1); demask.process(slice2); - - LOG.debug("Post-Processed: {}",Hex.asHex(payload)); + + LOG.debug("Post-Processed: {}", Hex.asHex(payload)); Assert.assertThat("Payload.remaining",payload.remaining(),is(messageSize)); for (int i = payload.position(); i < payload.limit(); i++) diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/util/Hex.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/util/Hex.java deleted file mode 100644 index 02b2bba0d53..00000000000 --- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/util/Hex.java +++ /dev/null @@ -1,80 +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.common.util; - -import java.nio.ByteBuffer; - -import org.eclipse.jetty.util.BufferUtil; - -public final class Hex -{ - private static final char[] hexcodes = "0123456789ABCDEF".toCharArray(); - - public static byte[] asByteArray(String hstr) - { - if ((hstr.length() < 0) || ((hstr.length() % 2) != 0)) - { - throw new IllegalArgumentException(String.format("Invalid string length of <%d>",hstr.length())); - } - - int size = hstr.length() / 2; - byte buf[] = new byte[size]; - byte hex; - int len = hstr.length(); - - int idx = (int)Math.floor(((size * 2) - (double)len) / 2); - for (int i = 0; i < len; i++) - { - hex = 0; - if (i >= 0) - { - hex = (byte)(Character.digit(hstr.charAt(i),16) << 4); - } - i++; - hex += (byte)(Character.digit(hstr.charAt(i),16)); - - buf[idx] = hex; - idx++; - } - - return buf; - } - - public static ByteBuffer asByteBuffer(String hstr) - { - return ByteBuffer.wrap(asByteArray(hstr)); - } - - public static String asHex(byte buf[]) - { - int len = buf.length; - char out[] = new char[len * 2]; - for (int i = 0; i < len; i++) - { - out[i * 2] = hexcodes[(buf[i] & 0xF0) >> 4]; - out[(i * 2) + 1] = hexcodes[(buf[i] & 0x0F)]; - } - return String.valueOf(out); - } - - public static String asHex(ByteBuffer buffer) - { - return asHex(BufferUtil.toArray(buffer)); - } -} diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/util/Sha1Sum.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/util/Sha1Sum.java index f2f5050e6d7..abede169a95 100644 --- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/util/Sha1Sum.java +++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/util/Sha1Sum.java @@ -31,6 +31,7 @@ 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; diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/util/StackUtil.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/util/StackUtil.java deleted file mode 100644 index 14dcad626bd..00000000000 --- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/util/StackUtil.java +++ /dev/null @@ -1,42 +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.common.util; - -import java.io.IOException; -import java.io.PrintWriter; -import java.io.StringWriter; - -public final class StackUtil -{ - public static String toString(Throwable t) - { - try (StringWriter w = new StringWriter()) - { - try (PrintWriter out = new PrintWriter(w)) - { - t.printStackTrace(out); - return w.toString(); - } - } - catch (IOException e) - { - return "Unable to get stacktrace for: " + t; - } - } -} diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/util/Utf8PartialBuilderTest.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/util/Utf8PartialBuilderTest.java index 0d0ac000851..2fc77218560 100644 --- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/util/Utf8PartialBuilderTest.java +++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/util/Utf8PartialBuilderTest.java @@ -18,12 +18,13 @@ package org.eclipse.jetty.websocket.common.util; -import static org.hamcrest.Matchers.*; -import static org.junit.Assert.*; +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; +import org.eclipse.jetty.toolchain.test.Hex; import org.eclipse.jetty.util.BufferUtil; import org.junit.Test; diff --git a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketServerFactory.java b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketServerFactory.java index 85f7a0728e0..af672adfdb1 100644 --- a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketServerFactory.java +++ b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketServerFactory.java @@ -488,9 +488,10 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc /** * Upgrade the request/response to a WebSocket Connection. - *

+ *

* This method will not normally return, but will instead throw a UpgradeConnectionException, to exit HTTP handling and initiate WebSocket handling of the * connection. + *

* * @param http the raw http connection * @param request the request to upgrade diff --git a/jetty-websocket/websocket-tests/pom.xml b/jetty-websocket/websocket-tests/pom.xml index 07b541ffd4e..3acfa0e5574 100644 --- a/jetty-websocket/websocket-tests/pom.xml +++ b/jetty-websocket/websocket-tests/pom.xml @@ -55,7 +55,7 @@ jetty-http ${project.version} tests - test + compile org.eclipse.jetty.toolchain diff --git a/jetty-websocket/websocket-tests/src/main/java/org/eclipse/jetty/websocket/tests/DataUtils.java b/jetty-websocket/websocket-tests/src/main/java/org/eclipse/jetty/websocket/tests/DataUtils.java new file mode 100644 index 00000000000..489fca5a20c --- /dev/null +++ b/jetty-websocket/websocket-tests/src/main/java/org/eclipse/jetty/websocket/tests/DataUtils.java @@ -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; + +import java.nio.ByteBuffer; +import java.util.Arrays; + +public final class DataUtils +{ + /** + * Make a copy of a byte buffer. + *

+ * This is important in some tests, as the underlying byte buffer contained in a Frame can be modified through + * masking and make it difficult to compare the results in the fuzzer. + * + * @param payload the payload to copy + * @return a new byte array of the payload contents + */ + public static ByteBuffer copyOf(ByteBuffer payload) + { + ByteBuffer copy = ByteBuffer.allocate(payload.remaining()); + copy.put(payload.slice()); + copy.flip(); + return copy; + } + + /** + * Make a copy of a byte buffer. + *

+ * This is important in some tests, as the underlying byte buffer contained in a Frame can be modified through + * masking and make it difficult to compare the results in the fuzzer. + * + * @param payload the payload to copy + * @return a new byte array of the payload contents + */ + public static ByteBuffer copyOf(byte[] payload) + { + return ByteBuffer.wrap(Arrays.copyOf(payload, payload.length)); + } +} diff --git a/jetty-websocket/websocket-tests/src/main/java/org/eclipse/jetty/websocket/tests/Fuzzer.java b/jetty-websocket/websocket-tests/src/main/java/org/eclipse/jetty/websocket/tests/Fuzzer.java deleted file mode 100644 index 4cf8e5c11b4..00000000000 --- a/jetty-websocket/websocket-tests/src/main/java/org/eclipse/jetty/websocket/tests/Fuzzer.java +++ /dev/null @@ -1,273 +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; - -import static org.eclipse.jetty.websocket.tests.Fuzzer.SendMode.BULK; -import static org.eclipse.jetty.websocket.tests.Fuzzer.SendMode.PER_FRAME; -import static org.eclipse.jetty.websocket.tests.Fuzzer.SendMode.SLOW; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; -import static org.junit.Assert.assertThat; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.TimeUnit; - -import org.eclipse.jetty.toolchain.test.ByteBufferAssert; -import org.eclipse.jetty.util.BufferUtil; -import org.eclipse.jetty.util.component.ContainerLifeCycle; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.websocket.api.BatchMode; -import org.eclipse.jetty.websocket.api.extensions.Frame; -import org.eclipse.jetty.websocket.client.ClientUpgradeRequest; -import org.eclipse.jetty.websocket.common.CloseInfo; -import org.eclipse.jetty.websocket.common.Generator; -import org.eclipse.jetty.websocket.common.OpCode; -import org.eclipse.jetty.websocket.common.WebSocketFrame; - -/** - * Fuzzing utility for the AB tests. - */ -public class Fuzzer extends ContainerLifeCycle -{ - public static class Session implements AutoCloseable - { - // Client side framing mask - private static final byte[] MASK = {0x11, 0x22, 0x33, 0x44}; - - private final Fuzzed testcase; - private final UntrustedWSSession session; - private final Generator generator; - private SendMode sendMode = SendMode.BULK; - private int slowSendSegmentSize = 5; - - public Session(Fuzzed testcase, UntrustedWSSession session) - { - this.testcase = testcase; - this.session = session; - this.generator = testcase.getLaxGenerator(); - } - - @Override - public void close() throws Exception - { - session.close(); - } - - public Session slowMode(int slowSendSegmentSize) - { - this.sendMode = SLOW; - this.slowSendSegmentSize = slowSendSegmentSize; - return this; - } - - public Session bulkMode() - { - this.sendMode = BULK; - return this; - } - - public Session perFrameMode() - { - this.sendMode = PER_FRAME; - return this; - } - - private void assertIsOpen() throws Exception - { - assertThat("Session exists", session, notNullValue()); - assertThat("Session is open", session.isOpen(), is(true)); - assertThat("Endpoint is open", session.getUntrustedEndpoint().openLatch.await(5, TimeUnit.SECONDS), is(true)); - } - - public ByteBuffer asNetworkBuffer(List send) - { - int buflen = 0; - for (Frame f : send) - { - buflen += f.getPayloadLength() + Generator.MAX_HEADER_LENGTH; - } - ByteBuffer buf = session.getBufferPool().acquire(buflen, false); - BufferUtil.clearToFill(buf); - - // Generate frames - for (WebSocketFrame f : send) - { - setClientMask(f); - generator.generateWholeFrame(f, buf); - } - buf.flip(); - return buf; - } - - private void setClientMask(WebSocketFrame f) - { - if (LOG.isDebugEnabled()) - { - f.setMask(new byte[] - {0x00, 0x00, 0x00, 0x00}); - } - else - { - f.setMask(MASK); // make sure we have mask set - } - } - - public void expect(List expect) throws Exception - { - expect(expect, 10, TimeUnit.SECONDS); - } - - public void expect(List expect, int duration, TimeUnit unit) throws Exception - { - int expectedCount = expect.size(); - LOG.debug("expect() {} frame(s)", expect.size()); - - // Read frames - UntrustedWSEndpoint endpoint = session.getUntrustedEndpoint(); - - String prefix = ""; - for (int i = 0; i < expectedCount; i++) - { - WebSocketFrame expected = expect.get(i); - WebSocketFrame actual = endpoint.framesQueue.poll(5, TimeUnit.SECONDS); - - prefix = "Frame[" + i + "]"; - - LOG.debug("{} {}", prefix, actual); - - assertThat(prefix + ".opcode", OpCode.name(actual.getOpCode()), is(OpCode.name(expected.getOpCode()))); - prefix += "/" + actual.getOpCode(); - if (expected.getOpCode() == OpCode.CLOSE) - { - CloseInfo expectedClose = new CloseInfo(expected); - CloseInfo actualClose = new CloseInfo(actual); - assertThat(prefix + ".statusCode", actualClose.getStatusCode(), is(expectedClose.getStatusCode())); - } - else - { - assertThat(prefix + ".payloadLength", actual.getPayloadLength(), is(expected.getPayloadLength())); - ByteBufferAssert.assertEquals(prefix + ".payload", expected.getPayload(), actual.getPayload()); - } - } - } - - public void expect(WebSocketFrame expect) throws Exception - { - expect(Collections.singletonList(expect)); - } - - public Session send(WebSocketFrame send) throws Exception - { - send(Collections.singletonList(send)); - return this; - } - - public Session send(ByteBuffer buf) throws Exception - { - assertIsOpen(); - LOG.debug("Sending bytes {}", BufferUtil.toDetailString(buf)); - if (sendMode == SLOW) - { - session.getUntrustedConnection().writeRawSlowly(buf, slowSendSegmentSize); - } - else - { - session.getUntrustedConnection().writeRaw(buf); - } - return this; - } - - public Session send(ByteBuffer buf, int numBytes) throws IOException - { - session.getUntrustedConnection().writeRaw(buf, numBytes); - return this; - } - - public Session send(List send) throws Exception - { - assertIsOpen(); - LOG.debug("[{}] Sending {} frames (mode {})", testcase.getTestMethodName(), send.size(), sendMode); - - session.getUntrustedConnection(); - - for (WebSocketFrame f : send) - { - BlockerFrameCallback blocker = new BlockerFrameCallback(); - session.getOutgoingHandler().outgoingFrame(f, blocker, BatchMode.OFF); - blocker.block(); - } - - return this; - } - } - - public enum SendMode - { - BULK, - PER_FRAME, - SLOW - } - - private static final int KBYTE = 1024; - private static final int MBYTE = KBYTE * KBYTE; - - private static final Logger LOG = Log.getLogger(Fuzzer.class); - - private final UntrustedWSClient client; - - private long connectTimeout = 2; - private TimeUnit connectTimeoutUnit = TimeUnit.SECONDS; - - public Fuzzer() throws Exception - { - this.client = new UntrustedWSClient(); - - int bigMessageSize = 20 * MBYTE; - - this.client.getPolicy().setMaxTextMessageSize(bigMessageSize); - this.client.getPolicy().setMaxBinaryMessageSize(bigMessageSize); - this.client.getPolicy().setIdleTimeout(5000); - - this.client.setMaxIdleTimeout(TimeUnit.SECONDS.toMillis(2)); - - addBean(this.client); - } - - public UntrustedWSClient getWSClient() - { - return this.client; - } - - public Fuzzer.Session connect(Fuzzed testcase) throws Exception - { - // TODO: handle EndPoint behavior here. (BULK/SLOW/FRAME) - // BULK = AggregatingEndpoint write (aggregate until .flush() call) - // SLOW = FixedBufferEndpoint write (send fixed buffer size) - // PERFRAME = No change to Endpoint - - ClientUpgradeRequest upgradeRequest = new ClientUpgradeRequest(); - upgradeRequest.setHeader("X-TestCase", testcase.getTestMethodName()); - UntrustedWSSession session = client.connect(testcase.getServerURI(), upgradeRequest).get(connectTimeout, connectTimeoutUnit); - return new Fuzzer.Session(testcase, session); - } -} diff --git a/jetty-websocket/websocket-tests/src/main/java/org/eclipse/jetty/websocket/tests/LocalFuzzer.java b/jetty-websocket/websocket-tests/src/main/java/org/eclipse/jetty/websocket/tests/LocalFuzzer.java new file mode 100644 index 00000000000..85a715b5b50 --- /dev/null +++ b/jetty-websocket/websocket-tests/src/main/java/org/eclipse/jetty/websocket/tests/LocalFuzzer.java @@ -0,0 +1,346 @@ +// +// ======================================================================== +// 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 static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.junit.Assert.assertThat; + +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.Map; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.TimeUnit; + +import org.eclipse.jetty.http.HttpTester; +import org.eclipse.jetty.server.LocalConnector; +import org.eclipse.jetty.toolchain.test.ByteBufferAssert; +import org.eclipse.jetty.util.BufferUtil; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.websocket.api.WebSocketConstants; +import org.eclipse.jetty.websocket.api.WebSocketPolicy; +import org.eclipse.jetty.websocket.common.CloseInfo; +import org.eclipse.jetty.websocket.common.Generator; +import org.eclipse.jetty.websocket.common.OpCode; +import org.eclipse.jetty.websocket.common.Parser; +import org.eclipse.jetty.websocket.common.WebSocketFrame; +import org.hamcrest.Matchers; + +public class LocalFuzzer implements AutoCloseable +{ + private static final Logger LOG = Log.getLogger(LocalFuzzer.class); + public final LocalFuzzer.Provider provider; + public final UnitGenerator generator; + public final LocalConnector.LocalEndPoint endPoint; + + public LocalFuzzer(LocalFuzzer.Provider provider) throws Exception + { + this(provider, null); + } + + public LocalFuzzer(LocalFuzzer.Provider provider, CharSequence requestPath) throws Exception + { + this(provider, requestPath, UpgradeUtils.newDefaultUpgradeRequestHeaders()); + } + + public LocalFuzzer(LocalFuzzer.Provider provider, CharSequence requestPath, Map headers) throws Exception + { + this.provider = provider; + String upgradeRequest = UpgradeUtils.generateUpgradeRequest(requestPath, headers); + LOG.debug("Request: {}", upgradeRequest); + ByteBuffer upgradeRequestBytes = BufferUtil.toBuffer(upgradeRequest.toString(), StandardCharsets.UTF_8); + this.endPoint = this.provider.newLocalConnection(); + performUpgrade(endPoint, upgradeRequestBytes); + this.generator = new UnitGenerator(WebSocketPolicy.newClientPolicy()); + } + + public void addInputInSegments(LocalConnector.LocalEndPoint endPoint, ByteBuffer outgoing, int segmentSize) + { + while (outgoing.remaining() > 0) + { + int len = Math.min(segmentSize, outgoing.remaining()); + ByteBuffer slice = outgoing.slice(); + slice.limit(len); + endPoint.addInput(slice); + outgoing.position(outgoing.position() + len); + } + } + + public void expectMessage(BlockingQueue framesQueue, byte expectedDataOp, ByteBuffer expectedMessage) throws InterruptedException + { + ByteBuffer actualPayload = ByteBuffer.allocate(expectedMessage.remaining()); + + WebSocketFrame frame = framesQueue.poll(1, TimeUnit.SECONDS); + assertThat("Initial Frame.opCode", frame.getOpCode(), is(expectedDataOp)); + + actualPayload.put(frame.getPayload()); + while (!frame.isFin()) + { + frame = framesQueue.poll(1, TimeUnit.SECONDS); + assertThat("Frame.opCode", frame.getOpCode(), is(OpCode.CONTINUATION)); + actualPayload.put(frame.getPayload()); + } + actualPayload.flip(); + ByteBufferAssert.assertEquals("Actual Message Payload", actualPayload, expectedMessage); + } + + public ByteBuffer asNetworkBuffer(List frames) + { + int bufferLength = 0; + for (WebSocketFrame f : frames) + { + bufferLength += f.getPayloadLength() + Generator.MAX_HEADER_LENGTH; + } + + ByteBuffer buffer = ByteBuffer.allocate(bufferLength); + + for (WebSocketFrame f : frames) + { + generator.generate(buffer, f); + } + BufferUtil.flipToFlush(buffer, 0); + return buffer; + } + + public void assertExpected(BlockingQueue framesQueue, List expect) throws InterruptedException + { + int expectedCount = expect.size(); + + String prefix; + for (int i = 0; i < expectedCount; i++) + { + prefix = "Frame[" + i + "]"; + + WebSocketFrame expected = expect.get(i); + WebSocketFrame actual = framesQueue.poll(1, TimeUnit.SECONDS); + assertThat(prefix + ".poll", actual, notNullValue()); + + if (LOG.isDebugEnabled()) + { + if (actual.getOpCode() == OpCode.CLOSE) + LOG.debug("{} CloseFrame: {}", prefix, new CloseInfo(actual)); + else + LOG.debug("{} {}", prefix, actual); + } + + assertThat(prefix + ".opcode", OpCode.name(actual.getOpCode()), Matchers.is(OpCode.name(expected.getOpCode()))); + prefix += "(op=" + actual.getOpCode() + "," + (actual.isFin() ? "" : "!") + "fin)"; + if (expected.getOpCode() == OpCode.CLOSE) + { + CloseInfo expectedClose = new CloseInfo(expected); + CloseInfo actualClose = new CloseInfo(actual); + assertThat(prefix + ".statusCode", actualClose.getStatusCode(), Matchers.is(expectedClose.getStatusCode())); + } + else if (expected.hasPayload()) + { + if (expected.getOpCode() == OpCode.TEXT) + { + String expectedText = expected.getPayloadAsUTF8(); + String actualText = actual.getPayloadAsUTF8(); + assertThat(prefix + ".text-payload", actualText, is(expectedText)); + } + else + { + assertThat(prefix + ".payloadLength", actual.getPayloadLength(), Matchers.is(expected.getPayloadLength())); + ByteBufferAssert.assertEquals(prefix + ".payload", expected.getPayload(), actual.getPayload()); + } + } + else + { + assertThat(prefix + ".payloadLength", actual.getPayloadLength(), Matchers.is(0)); + } + } + } + + + public void close() throws Exception + { + endPoint.close(); + } + + /** + * Send the EOF signal + */ + public void eof() + { + endPoint.addInputEOF(); + } + + public void expect(List expected) throws InterruptedException + { + // Get incoming frames + // Wait for server to close + endPoint.waitUntilClosed(); + + // Get the server send echo bytes + ByteBuffer incoming = endPoint.getOutput(); + + // Parse those bytes into frames + ParserCapture capture = new ParserCapture(); + Parser parser = provider.newClientParser(capture); + parser.parse(incoming); + + assertExpected(capture.framesQueue, expected); + } + + public BlockingQueue getOutputFrames() + { + // Get incoming frames + // Wait for server to close + endPoint.waitUntilClosed(); + + // Get the server send echo bytes + ByteBuffer incoming = endPoint.getOutput(); + + // Parse those bytes into frames + ParserCapture capture = new ParserCapture(); + Parser parser = provider.newClientParser(capture); + parser.parse(incoming); + + return capture.framesQueue; + } + + /** + * Send raw bytes + */ + public void send(ByteBuffer buffer) + { + endPoint.addInput(buffer); + } + + /** + * Send some of the raw bytes + * + * @param buffer the buffer + * @param length the number of bytes to send from buffer + */ + public void send(ByteBuffer buffer, int length) + { + int limit = Math.min(length, buffer.remaining()); + ByteBuffer sliced = buffer.slice(); + sliced.limit(limit); + endPoint.addInput(sliced); + buffer.position(buffer.position() + limit); + } + + /** + * Generate a single ByteBuffer representing the entire + * list of generated frames, and submit it to {@link org.eclipse.jetty.server.LocalConnector.LocalEndPoint#addInput(ByteBuffer)} + * + * @param frames the list of frames to send + */ + public void sendBulk(List frames) + { + int bufferLength = 0; + for (WebSocketFrame f : frames) + { + bufferLength += f.getPayloadLength() + Generator.MAX_HEADER_LENGTH; + } + + ByteBuffer outgoing = ByteBuffer.allocate(bufferLength); + + boolean eof = false; + for (WebSocketFrame f : frames) + { + generator.generate(outgoing, f); + if (f.getOpCode() == OpCode.CLOSE) + eof = true; + } + BufferUtil.flipToFlush(outgoing, 0); + endPoint.addInput(outgoing); + if (eof) + 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(List 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)} + * + * @param frames the list of frames to send + */ + public void sendSegmented(List frames, int segmentSize) + { + int bufferLength = 0; + for (WebSocketFrame f : frames) + { + bufferLength += f.getPayloadLength() + Generator.MAX_HEADER_LENGTH; + } + + ByteBuffer outgoing = ByteBuffer.allocate(bufferLength); + + boolean eof = false; + for (WebSocketFrame f : frames) + { + generator.generate(outgoing, f); + if (f.getOpCode() == OpCode.CLOSE) + eof = true; + } + BufferUtil.flipToFlush(outgoing, 0); + addInputInSegments(endPoint, outgoing, segmentSize); + if (eof) + endPoint.addInputEOF(); + } + + private HttpTester.Response performUpgrade(LocalConnector.LocalEndPoint endPoint, ByteBuffer buf) throws Exception + { + endPoint.addInput(buf); + + // Get response + ByteBuffer response = endPoint.waitForResponse(false, 1, TimeUnit.SECONDS); + HttpTester.Response parsedResponse = HttpTester.parseResponse(response); + + LOG.debug("Response: {}", parsedResponse); + + assertThat("Is Switching Protocols", parsedResponse.getStatus(), is(101)); + assertThat("Is Connection Upgrade", parsedResponse.get(WebSocketConstants.SEC_WEBSOCKET_ACCEPT), notNullValue()); + assertThat("Is Connection Upgrade", parsedResponse.get("Connection"), is("Upgrade")); + assertThat("Is WebSocket Upgrade", parsedResponse.get("Upgrade"), is("WebSocket")); + return parsedResponse; + } + + public interface Provider + { + Parser newClientParser(Parser.Handler parserHandler); + + LocalConnector.LocalEndPoint newLocalConnection(); + } +} \ No newline at end of file diff --git a/jetty-websocket/websocket-tests/src/main/java/org/eclipse/jetty/websocket/tests/LocalServer.java b/jetty-websocket/websocket-tests/src/main/java/org/eclipse/jetty/websocket/tests/LocalServer.java new file mode 100644 index 00000000000..4f344d399b4 --- /dev/null +++ b/jetty-websocket/websocket-tests/src/main/java/org/eclipse/jetty/websocket/tests/LocalServer.java @@ -0,0 +1,194 @@ +// +// ======================================================================== +// 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.net.URI; +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.HttpConfiguration; +import org.eclipse.jetty.server.HttpConnectionFactory; +import org.eclipse.jetty.server.LocalConnector; +import org.eclipse.jetty.server.SecureRequestCustomizer; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.server.SslConnectionFactory; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.toolchain.test.MavenTestingUtils; +import org.eclipse.jetty.util.component.ContainerLifeCycle; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.util.ssl.SslContextFactory; +import org.eclipse.jetty.websocket.api.WebSocketPolicy; +import org.eclipse.jetty.websocket.common.Parser; + +public class LocalServer extends ContainerLifeCycle implements LocalFuzzer.Provider +{ + private static final Logger LOG = Log.getLogger(LocalServer.class); + private final ByteBufferPool bufferPool = new MappedByteBufferPool(); + private final WebSocketPolicy serverPolicy = WebSocketPolicy.newServerPolicy(); + private Server server; + private ServerConnector connector; + private LocalConnector localConnector; + private ServletContextHandler servletContextHandler; + private URI serverUri; + private boolean ssl = false; + private SslContextFactory sslContextFactory; + + public void enableSsl(boolean ssl) + { + this.ssl = ssl; + } + + public LocalConnector getLocalConnector() + { + return localConnector; + } + + public WebSocketPolicy getServerDefaultPolicy() + { + return serverPolicy; + } + + public URI getServerUri() + { + return serverUri; + } + + public ServletContextHandler getServletContextHandler() + { + return servletContextHandler; + } + + public SslContextFactory getSslContextFactory() + { + return sslContextFactory; + } + + public boolean isSslEnabled() + { + return ssl; + } + + @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 upgradeRequest) throws Exception + { + return new LocalFuzzer(this, requestPath, upgradeRequest); + } + + protected void configureServletContextHandler(ServletContextHandler context) throws Exception + { + /* override to change context handler */ + } + + @Override + protected void doStart() throws Exception + { + // Configure Server + server = new Server(); + if (ssl) + { + // HTTP Configuration + HttpConfiguration http_config = new HttpConfiguration(); + http_config.setSecureScheme("https"); + http_config.setSecurePort(0); + http_config.setOutputBufferSize(32768); + http_config.setRequestHeaderSize(8192); + http_config.setResponseHeaderSize(8192); + http_config.setSendServerVersion(true); + http_config.setSendDateHeader(false); + + sslContextFactory = new SslContextFactory(); + sslContextFactory.setKeyStorePath(MavenTestingUtils.getTestResourceFile("keystore").getAbsolutePath()); + sslContextFactory.setKeyStorePassword("storepwd"); + sslContextFactory.setKeyManagerPassword("keypwd"); + sslContextFactory.setExcludeCipherSuites("SSL_RSA_WITH_DES_CBC_SHA", "SSL_DHE_RSA_WITH_DES_CBC_SHA", "SSL_DHE_DSS_WITH_DES_CBC_SHA", + "SSL_RSA_EXPORT_WITH_RC4_40_MD5", "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA", "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", + "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"); + + // SSL HTTP Configuration + HttpConfiguration https_config = new HttpConfiguration(http_config); + https_config.addCustomizer(new SecureRequestCustomizer()); + + // SSL Connector + connector = new ServerConnector(server, new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString()), new HttpConnectionFactory(https_config)); + connector.setPort(0); + } + else + { + // Basic HTTP connector + connector = new ServerConnector(server); + connector.setPort(0); + } + // Add network connector + server.addConnector(connector); + + // Add Local Connector + localConnector = new LocalConnector(server); + server.addConnector(localConnector); + + servletContextHandler = new ServletContextHandler(server, "/", true, false); + servletContextHandler.setContextPath("/"); + configureServletContextHandler(servletContextHandler); + server.setHandler(servletContextHandler); + + // Start Server + addBean(server); + + super.doStart(); + + // Establish the Server URI + String host = connector.getHost(); + if (host == null) + { + host = "localhost"; + } + int port = connector.getLocalPort(); + serverUri = new URI(String.format("%s://%s:%d/", ssl ? "wss" : "ws", host, port)); + + // Some debugging + if (LOG.isDebugEnabled()) + { + LOG.debug(server.dump()); + } + } +} diff --git a/jetty-websocket/websocket-tests/src/main/java/org/eclipse/jetty/websocket/tests/SimpleServletServer.java b/jetty-websocket/websocket-tests/src/main/java/org/eclipse/jetty/websocket/tests/SimpleServletServer.java index 3271fd8d5f0..ea42baa8a34 100644 --- a/jetty-websocket/websocket-tests/src/main/java/org/eclipse/jetty/websocket/tests/SimpleServletServer.java +++ b/jetty-websocket/websocket-tests/src/main/java/org/eclipse/jetty/websocket/tests/SimpleServletServer.java @@ -18,159 +18,39 @@ package org.eclipse.jetty.websocket.tests; -import java.net.URI; - import javax.servlet.http.HttpServlet; -import org.eclipse.jetty.http.HttpVersion; -import org.eclipse.jetty.server.HttpConfiguration; -import org.eclipse.jetty.server.HttpConnectionFactory; -import org.eclipse.jetty.server.LocalConnector; -import org.eclipse.jetty.server.SecureRequestCustomizer; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.ServerConnector; -import org.eclipse.jetty.server.SslConnectionFactory; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; -import org.eclipse.jetty.toolchain.test.MavenTestingUtils; -import org.eclipse.jetty.util.component.ContainerLifeCycle; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.websocket.server.WebSocketUpgradeFilter; import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory; -public class SimpleServletServer extends ContainerLifeCycle +public class SimpleServletServer extends LocalServer implements LocalFuzzer.Provider { - private static final Logger LOG = Log.getLogger(SimpleServletServer.class); - private Server server; - private ServerConnector connector; - private LocalConnector localConnector; - private URI serverUri; - private HttpServlet servlet; - private boolean ssl = false; - private SslContextFactory sslContextFactory; + private final HttpServlet servlet; public SimpleServletServer(HttpServlet servlet) { + super(); this.servlet = servlet; } - public void enableSsl(boolean ssl) - { - this.ssl = ssl; - } - - public LocalConnector getLocalConnector() - { - return localConnector; - } - - public URI getServerUri() - { - return serverUri; - } - - public SslContextFactory getSslContextFactory() - { - return sslContextFactory; - } - - public boolean isSslEnabled() - { - return ssl; - } - - @Override - protected void doStart() throws Exception - { - // Configure Server - server = new Server(); - if (ssl) - { - // HTTP Configuration - HttpConfiguration http_config = new HttpConfiguration(); - http_config.setSecureScheme("https"); - http_config.setSecurePort(0); - http_config.setOutputBufferSize(32768); - http_config.setRequestHeaderSize(8192); - http_config.setResponseHeaderSize(8192); - http_config.setSendServerVersion(true); - http_config.setSendDateHeader(false); - - sslContextFactory = new SslContextFactory(); - sslContextFactory.setKeyStorePath(MavenTestingUtils.getTestResourceFile("keystore").getAbsolutePath()); - sslContextFactory.setKeyStorePassword("storepwd"); - sslContextFactory.setKeyManagerPassword("keypwd"); - sslContextFactory.setExcludeCipherSuites("SSL_RSA_WITH_DES_CBC_SHA","SSL_DHE_RSA_WITH_DES_CBC_SHA","SSL_DHE_DSS_WITH_DES_CBC_SHA", - "SSL_RSA_EXPORT_WITH_RC4_40_MD5","SSL_RSA_EXPORT_WITH_DES40_CBC_SHA","SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", - "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"); - - // SSL HTTP Configuration - HttpConfiguration https_config = new HttpConfiguration(http_config); - https_config.addCustomizer(new SecureRequestCustomizer()); - - // SSL Connector - connector = new ServerConnector(server,new SslConnectionFactory(sslContextFactory,HttpVersion.HTTP_1_1.asString()),new HttpConnectionFactory(https_config)); - connector.setPort(0); - } - else - { - // Basic HTTP connector - connector = new ServerConnector(server); - connector.setPort(0); - } - // Add network connector - server.addConnector(connector); - - // Add Local Connector - localConnector = new LocalConnector(server); - server.addConnector(localConnector); - - ServletContextHandler context = new ServletContextHandler(); - context.setContextPath("/"); - configureServletContextHandler(context); - server.setHandler(context); - - // Serve capture servlet - context.addServlet(new ServletHolder(servlet),"/*"); - - // Start Server - addBean(server); - - super.doStart(); - - // Establish the Server URI - String host = connector.getHost(); - if (host == null) - { - host = "localhost"; - } - int port = connector.getLocalPort(); - serverUri = new URI(String.format("%s://%s:%d/",ssl?"wss":"ws",host,port)); - - // Some debugging - if (LOG.isDebugEnabled()) - { - LOG.debug(server.dump()); - } - } - protected void configureServletContextHandler(ServletContextHandler context) { - /* override to change context handler */ + // Serve capture servlet + context.addServlet(new ServletHolder(servlet),"/*"); } - + public WebSocketServletFactory getWebSocketServletFactory() { // Try filter approach first - WebSocketUpgradeFilter filter = (WebSocketUpgradeFilter)this.servlet.getServletContext().getAttribute(WebSocketUpgradeFilter.class.getName()); + WebSocketUpgradeFilter filter = (WebSocketUpgradeFilter) this.servlet.getServletContext().getAttribute(WebSocketUpgradeFilter.class.getName()); if (filter != null) { return filter.getFactory(); } - + // Try servlet next - return (WebSocketServletFactory)this.servlet.getServletContext().getAttribute(WebSocketServletFactory.class.getName()); + return (WebSocketServletFactory) this.servlet.getServletContext().getAttribute(WebSocketServletFactory.class.getName()); } } diff --git a/jetty-websocket/websocket-tests/src/main/java/org/eclipse/jetty/websocket/tests/UpgradeUtils.java b/jetty-websocket/websocket-tests/src/main/java/org/eclipse/jetty/websocket/tests/UpgradeUtils.java new file mode 100644 index 00000000000..36b58b84db4 --- /dev/null +++ b/jetty-websocket/websocket-tests/src/main/java/org/eclipse/jetty/websocket/tests/UpgradeUtils.java @@ -0,0 +1,62 @@ +// +// ======================================================================== +// 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.Map; +import java.util.TreeMap; + +import org.eclipse.jetty.websocket.api.WebSocketConstants; + +public class UpgradeUtils +{ + public static String generateUpgradeRequest(CharSequence requestPath, Map headers) + { + StringBuilder upgradeRequest = new StringBuilder(); + upgradeRequest.append("GET "); + upgradeRequest.append(requestPath == null ? "/" : requestPath); + upgradeRequest.append(" HTTP/1.1\r\n"); + headers.entrySet().stream().forEach(e -> + upgradeRequest.append(e.getKey()).append(": ").append(e.getValue()).append("\r\n")); + upgradeRequest.append("\r\n"); + return upgradeRequest.toString(); + } + + public static String generateUpgradeRequest() + { + return generateUpgradeRequest("/", newDefaultUpgradeRequestHeaders()); + } + + public static String generateUpgradeRequest(CharSequence requestPath) + { + return generateUpgradeRequest(requestPath, newDefaultUpgradeRequestHeaders()); + } + + public static Map newDefaultUpgradeRequestHeaders() + { + Map headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); + headers.put("Host", "local"); + headers.put("Connection", "Upgrade"); + headers.put("Upgrade", "WebSocket"); + headers.put(WebSocketConstants.SEC_WEBSOCKET_KEY, "dGhlIHNhbXBsZSBub25jZQ=="); + headers.put(WebSocketConstants.SEC_WEBSOCKET_ORIGIN, "ws://local/"); + // headers.put(WebSocketConstants.SEC_WEBSOCKET_PROTOCOL, "echo"); + headers.put(WebSocketConstants.SEC_WEBSOCKET_VERSION, "13"); + return headers; + } +} diff --git a/jetty-websocket/websocket-tests/src/main/java/org/eclipse/jetty/websocket/tests/WSServer.java b/jetty-websocket/websocket-tests/src/main/java/org/eclipse/jetty/websocket/tests/WSServer.java index 5206ca1ae8c..4fa3e1edfe3 100644 --- a/jetty-websocket/websocket-tests/src/main/java/org/eclipse/jetty/websocket/tests/WSServer.java +++ b/jetty-websocket/websocket-tests/src/main/java/org/eclipse/jetty/websocket/tests/WSServer.java @@ -24,14 +24,18 @@ import static org.junit.Assert.assertThat; import java.io.File; import java.io.IOException; -import java.net.MalformedURLException; 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.Server; import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.server.handler.ContextHandlerCollection; @@ -40,58 +44,66 @@ import org.eclipse.jetty.toolchain.test.FS; import org.eclipse.jetty.toolchain.test.IO; import org.eclipse.jetty.toolchain.test.JAR; import org.eclipse.jetty.toolchain.test.MavenTestingUtils; -import org.eclipse.jetty.toolchain.test.OS; import org.eclipse.jetty.toolchain.test.TestingDir; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.util.resource.Resource; +import org.eclipse.jetty.util.resource.PathResource; import org.eclipse.jetty.webapp.Configuration; import org.eclipse.jetty.webapp.FragmentConfiguration; 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. *

* This is particularly useful when the WebSocket endpoints are discovered via the javax.websocket annotation scanning. */ -public class WSServer +public class WSServer implements LocalFuzzer.Provider { private static final Logger LOG = Log.getLogger(WSServer.class); - private final File contextDir; + private final Path contextDir; private final String contextPath; + private final ByteBufferPool bufferPool = new MappedByteBufferPool(); private Server server; private URI serverUri; private ContextHandlerCollection contexts; - private File webinf; - private File classesDir; - + private LocalConnector localConnector; + private Path webinf; + private Path classesDir; + public WSServer(TestingDir testdir, String contextName) { - this(testdir.getPath().toFile(),contextName); + this(testdir.getPath(), contextName); } - + public WSServer(File testdir, String contextName) { - this.contextDir = new File(testdir,contextName); + this(testdir.toPath(), contextName); + } + + public WSServer(Path testdir, String contextName) + { + this.contextDir = testdir.resolve(contextName); this.contextPath = "/" + contextName; FS.ensureEmpty(contextDir); } - + public void copyClass(Class clazz) throws Exception { ClassLoader cl = Thread.currentThread().getContextClassLoader(); - String endpointPath = clazz.getName().replace('.','/') + ".class"; + String endpointPath = clazz.getName().replace('.', '/') + ".class"; URL classUrl = cl.getResource(endpointPath); - assertThat("Class URL for: " + clazz,classUrl,notNullValue()); - File destFile = new File(classesDir,OS.separators(endpointPath)); - FS.ensureDirExists(destFile.getParentFile()); + assertThat("Class URL for: " + clazz, classUrl, notNullValue()); + Path destFile = classesDir.resolve(endpointPath); + FS.ensureDirExists(destFile.getParent()); File srcFile = new File(classUrl.toURI()); - IO.copy(srcFile,destFile); + IO.copy(srcFile, destFile.toFile()); } - + public void copyEndpoint(Class endpointClass) throws Exception { copyClass(endpointClass); @@ -99,65 +111,65 @@ public class WSServer public void copyLib(Class clazz, String jarFileName) throws URISyntaxException, IOException { - webinf = new File(contextDir,"WEB-INF"); + webinf = contextDir.resolve("WEB-INF"); FS.ensureDirExists(webinf); - File libDir = new File(webinf,"lib"); + Path libDir = webinf.resolve("lib"); FS.ensureDirExists(libDir); - File jarFile = new File(libDir, jarFileName); + Path jarFile = libDir.resolve(jarFileName); URL codeSourceURL = clazz.getProtectionDomain().getCodeSource().getLocation(); assertThat("Class CodeSource URL is file scheme", codeSourceURL.getProtocol(), is("file")); - + File sourceCodeSourceFile = new File(codeSourceURL.toURI()); if (sourceCodeSourceFile.isDirectory()) { LOG.info("Creating " + jarFile + " from " + sourceCodeSourceFile); - JAR.create(sourceCodeSourceFile, jarFile); + JAR.create(sourceCodeSourceFile, jarFile.toFile()); } else { LOG.info("Copying " + sourceCodeSourceFile + " to " + jarFile); - IO.copy(sourceCodeSourceFile, jarFile); + IO.copy(sourceCodeSourceFile, jarFile.toFile()); } } public void copyWebInf(String testResourceName) throws IOException { - webinf = new File(contextDir,"WEB-INF"); + webinf = contextDir.resolve("WEB-INF"); FS.ensureDirExists(webinf); - classesDir = new File(webinf,"classes"); + classesDir = webinf.resolve("classes"); FS.ensureDirExists(classesDir); - File webxml = new File(webinf,"web.xml"); + Path webxml = webinf.resolve("web.xml"); File testWebXml = MavenTestingUtils.getTestResourceFile(testResourceName); - IO.copy(testWebXml,webxml); + IO.copy(testWebXml, webxml.toFile()); } - - public WebAppContext createWebAppContext() throws MalformedURLException, IOException + + public WebAppContext createWebAppContext() throws IOException { WebAppContext context = new WebAppContext(); context.setContextPath(this.contextPath); - context.setBaseResource(Resource.newResource(this.contextDir)); - context.setAttribute("org.eclipse.jetty.websocket.jsr356",Boolean.TRUE); - + context.setBaseResource(new PathResource(this.contextDir)); + context.setAttribute("org.eclipse.jetty.websocket.jsr356", Boolean.TRUE); + // @formatter:off - context.setConfigurations(new Configuration[] { + context.setConfigurations(new Configuration[]{ new AnnotationConfiguration(), new WebXmlConfiguration(), new WebInfConfiguration(), - new PlusConfiguration(), + new PlusConfiguration(), new MetaInfConfiguration(), - new FragmentConfiguration(), + new FragmentConfiguration(), new EnvConfiguration()}); // @formatter:on - + return context; } - + public void createWebInf() throws IOException { copyWebInf("empty-web.xml"); } - + public void deployWebapp(WebAppContext webapp) throws Exception { contexts.addHandler(webapp); @@ -169,12 +181,44 @@ public class WSServer webapp.dump(System.err); } } - + 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 upgradeRequest) throws Exception + { + return new LocalFuzzer(this, requestPath, upgradeRequest); + } + public URI getServerBaseURI() { return serverUri; @@ -184,49 +228,57 @@ public class WSServer { return server; } - - public File getWebAppDir() + + public Path getWebAppDir() { return this.contextDir; } - + public void start() 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)); + serverUri = new URI(String.format("ws://%s:%d%s/", host, port, contextPath)); if (LOG.isDebugEnabled()) - LOG.debug("Server started on {}",serverUri); + LOG.debug("Server started on {}", serverUri); } - + public void stop() { - if (server != null) + if (server == null) { - try - { - server.stop(); - } - catch (Exception e) - { - e.printStackTrace(System.err); - } + return; + } + + try + { + server.stop(); + } + catch (Exception e) + { + e.printStackTrace(System.err); } } } diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/ABServlet.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/ABServlet.java deleted file mode 100644 index 912d7cea73c..00000000000 --- a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/ABServlet.java +++ /dev/null @@ -1,35 +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 org.eclipse.jetty.websocket.servlet.WebSocketServlet; -import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory; - -/** - * Servlet with bigger message policy sizes, with registered simple echo socket. - */ -@SuppressWarnings("serial") -public class ABServlet extends WebSocketServlet -{ - @Override - public void configure(WebSocketServletFactory factory) - { - factory.register(ABSocket.class); - } -} diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/ABSocket.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/ABSocket.java deleted file mode 100644 index 93f2f97cca1..00000000000 --- a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/ABSocket.java +++ /dev/null @@ -1,84 +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 java.nio.ByteBuffer; - -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.websocket.api.Session; -import org.eclipse.jetty.websocket.api.WebSocketException; -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.common.util.TextUtil; - -/** - * Simple Echo WebSocket, using async writes of echo - */ -@WebSocket(maxTextMessageSize = 20 * 1024 * 1024, - maxBinaryMessageSize = 20 * 1024 * 1024) -public class ABSocket -{ - private static Logger LOG = Log.getLogger(ABSocket.class); - - private Session session; - - @OnWebSocketMessage - public void onBinary(byte buf[], int offset, int len) - { - LOG.debug("onBinary(byte[{}],{},{})",buf.length,offset,len); - - // echo the message back. - ByteBuffer data = ByteBuffer.wrap(buf,offset,len); - this.session.getRemote().sendBytes(data,null); - } - - @OnWebSocketConnect - public void onOpen(Session sess) - { - this.session = sess; - } - - @OnWebSocketMessage - public void onText(String message) - { - if (LOG.isDebugEnabled()) - { - if (message == null) - { - LOG.debug("onText() msg=null"); - } - else - { - LOG.debug("onText() size={}, msg={}",message.length(),TextUtil.hint(message)); - } - } - - try - { - // echo the message back. - this.session.getRemote().sendString(message,null); - } - catch (WebSocketException e) - { - LOG.warn("Unable to echo TEXT message",e); - } - } -} diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/AbstractABCase.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/AbstractABCase.java deleted file mode 100644 index 566307f1d68..00000000000 --- a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/AbstractABCase.java +++ /dev/null @@ -1,244 +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 java.net.URI; -import java.nio.ByteBuffer; -import java.util.Arrays; - -import org.eclipse.jetty.util.BufferUtil; -import org.eclipse.jetty.util.StringUtil; -import org.eclipse.jetty.util.log.StacklessLogging; -import org.eclipse.jetty.util.log.StdErrLog; -import org.eclipse.jetty.websocket.api.WebSocketPolicy; -import org.eclipse.jetty.websocket.common.Generator; -import org.eclipse.jetty.websocket.common.OpCode; -import org.eclipse.jetty.websocket.common.WebSocketFrame; -import org.eclipse.jetty.websocket.tests.Fuzzed; -import org.eclipse.jetty.websocket.tests.Fuzzer; -import org.eclipse.jetty.websocket.tests.LeakTrackingBufferPoolRule; -import org.eclipse.jetty.websocket.tests.RawFrameBuilder; -import org.eclipse.jetty.websocket.tests.SimpleServletServer; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Rule; -import org.junit.rules.TestName; - -public abstract class AbstractABCase implements Fuzzed -{ - // Allow Fuzzer / Generator to create bad frames for testing frame validation - protected static class BadFrame extends WebSocketFrame - { - public BadFrame(byte opcode) - { - super(OpCode.CONTINUATION); - super.finRsvOp = (byte)((finRsvOp & 0xF0) | (opcode & 0x0F)); - // NOTE: Not setting Frame.Type intentionally - } - - @Override - public void assertValid() - { - } - - @Override - public boolean isControlFrame() - { - return false; - } - - @Override - public boolean isDataFrame() - { - return false; - } - } - - protected static final byte FIN = (byte)0x80; - protected static final byte NOFIN = 0x00; - protected static final byte[] MASK = - { 0x12, 0x34, 0x56, 0x78 }; - - protected Generator strictGenerator; - protected Generator laxGenerator; - protected static SimpleServletServer server; - protected Fuzzer fuzzer; - - @Rule - public LeakTrackingBufferPoolRule bufferPool = new LeakTrackingBufferPoolRule("Test"); - - @Before - public void setup() throws Exception - { - fuzzer = new Fuzzer(); - fuzzer.getWSClient().setBufferPool(bufferPool); - fuzzer.start(); - - WebSocketPolicy policy = WebSocketPolicy.newClientPolicy(); - strictGenerator = new Generator(policy,bufferPool,true); - laxGenerator = new Generator(policy,bufferPool,false); - } - - @After - public void tearDown() throws Exception - { - fuzzer.stop(); - } - - @BeforeClass - public static void startEnv() throws Exception - { - server = new SimpleServletServer(new ABServlet()); - server.start(); - } - - @AfterClass - public static void stopEnv() throws Exception - { - server.stop(); - } - - /** - * Make a copy of a byte buffer. - *

- * This is important in some tests, as the underlying byte buffer contained in a Frame can be modified through - * masking and make it difficult to compare the results in the fuzzer. - * - * @param payload the payload to copy - * @return a new byte array of the payload contents - */ - protected ByteBuffer copyOf(byte[] payload) - { - return ByteBuffer.wrap(Arrays.copyOf(payload,payload.length)); - } - - /** - * Make a copy of a byte buffer. - *

- * This is important in some tests, as the underlying byte buffer contained in a Frame can be modified through - * masking and make it difficult to compare the results in the fuzzer. - * - * @param payload the payload to copy - * @return a new byte array of the payload contents - */ - protected ByteBuffer clone(ByteBuffer payload) - { - ByteBuffer copy = ByteBuffer.allocate(payload.remaining()); - copy.put(payload.slice()); - copy.flip(); - return copy; - } - - /** - * Make a copy of a byte buffer. - *

- * This is important in some tests, as the underlying byte buffer contained in a Frame can be modified through - * masking and make it difficult to compare the results in the fuzzer. - * - * @param payload the payload to copy - * @return a new byte array of the payload contents - */ - protected ByteBuffer copyOf(ByteBuffer payload) - { - ByteBuffer copy = ByteBuffer.allocate(payload.remaining()); - BufferUtil.clearToFill(copy); - BufferUtil.put(payload,copy); - BufferUtil.flipToFlush(copy,0); - return copy; - } - - public static String toUtf8String(byte[] buf) - { - String raw = StringUtil.toUTF8String(buf,0,buf.length); - StringBuilder ret = new StringBuilder(); - int len = raw.length(); - for (int i = 0; i < len; i++) - { - int codepoint = raw.codePointAt(i); - if (Character.isUnicodeIdentifierPart(codepoint)) - { - ret.append(String.format("\\u%04X",codepoint)); - } - else - { - ret.append(Character.toChars(codepoint)); - } - } - return ret.toString(); - } - - @Rule - public TestName testname = new TestName(); - - /** - * @param clazz the class to enable - * @param enabled true to enable the stack traces (or not) - * @deprecated use {@link StacklessLogging} in a try-with-resources block instead - */ - @Deprecated - protected void enableStacks(Class clazz, boolean enabled) - { - StdErrLog log = StdErrLog.getLogger(clazz); - log.setHideStacks(!enabled); - } - - public Generator getLaxGenerator() - { - return laxGenerator; - } - - public SimpleServletServer getServer() - { - return server; - } - - @Override - public URI getServerURI() - { - return server.getServerUri(); - } - - @Override - public String getTestMethodName() - { - return testname.getMethodName(); - } - - public static byte[] masked(final byte[] data) - { - return RawFrameBuilder.mask(data,MASK); - } - - public static void putLength(ByteBuffer buf, int length, boolean masked) - { - RawFrameBuilder.putLength(buf,length,masked); - } - - public static void putMask(ByteBuffer buf) - { - buf.put(MASK); - } - - public static void putPayloadLength(ByteBuffer buf, int length) - { - putLength(buf,length,true); - } -} diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/AbstractLocalServerCase.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/AbstractLocalServerCase.java index c372bc6b1f4..f7ce7d82b2e 100644 --- a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/AbstractLocalServerCase.java +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/AbstractLocalServerCase.java @@ -19,36 +19,29 @@ package org.eclipse.jetty.websocket.tests.server; import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.notNullValue; import static org.junit.Assert.assertThat; import java.nio.ByteBuffer; -import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.List; -import java.util.Map; -import java.util.TreeMap; -import java.util.concurrent.BlockingQueue; import java.util.concurrent.TimeUnit; import org.eclipse.jetty.http.HttpTester; import org.eclipse.jetty.io.MappedByteBufferPool; import org.eclipse.jetty.server.LocalConnector; -import org.eclipse.jetty.toolchain.test.ByteBufferAssert; -import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.websocket.api.WebSocketPolicy; -import org.eclipse.jetty.websocket.common.CloseInfo; -import org.eclipse.jetty.websocket.common.Generator; import org.eclipse.jetty.websocket.common.OpCode; import org.eclipse.jetty.websocket.common.Parser; import org.eclipse.jetty.websocket.common.WebSocketFrame; -import org.eclipse.jetty.websocket.tests.ParserCapture; +import org.eclipse.jetty.websocket.common.frames.BinaryFrame; +import org.eclipse.jetty.websocket.common.frames.ContinuationFrame; +import org.eclipse.jetty.websocket.common.frames.DataFrame; +import org.eclipse.jetty.websocket.common.frames.TextFrame; import org.eclipse.jetty.websocket.tests.SimpleServletServer; import org.eclipse.jetty.websocket.tests.UnitGenerator; import org.eclipse.jetty.websocket.tests.servlets.EchoServlet; -import org.hamcrest.Matchers; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Rule; @@ -59,8 +52,14 @@ import org.junit.rules.TestName; */ public abstract class AbstractLocalServerCase { + @SuppressWarnings("SpellCheckingInspection") + protected static final int KBYTE = 1024; + @SuppressWarnings("SpellCheckingInspection") + protected static final int MBYTE = KBYTE * KBYTE; + protected static SimpleServletServer server; protected final Logger LOG; + @Rule public TestName testname = new TestName(); public UnitGenerator generator = new UnitGenerator(WebSocketPolicy.newClientPolicy()); @@ -70,41 +69,6 @@ public abstract class AbstractLocalServerCase LOG = Log.getLogger(this.getClass().getName()); } - /** - * Make a copy of a byte buffer. - *

- * This is important in some tests, as the underlying byte buffer contained in a Frame can be modified through - * masking and make it difficult to compare the results in the fuzzer. - * - * @param payload the payload to copy - * @return a new byte array of the payload contents - */ - public static ByteBuffer clone(ByteBuffer payload) - { - ByteBuffer copy = ByteBuffer.allocate(payload.remaining()); - copy.put(payload.slice()); - copy.flip(); - return copy; - } - - /** - * Make a copy of a byte buffer. - *

- * This is important in some tests, as the underlying byte buffer contained in a Frame can be modified through - * masking and make it difficult to compare the results in the fuzzer. - * - * @param payload the payload to copy - * @return a new byte array of the payload contents - */ - public static ByteBuffer copyOf(ByteBuffer payload) - { - ByteBuffer copy = ByteBuffer.allocate(payload.remaining()); - BufferUtil.clearToFill(copy); - BufferUtil.put(payload, copy); - BufferUtil.flipToFlush(copy, 0); - return copy; - } - @BeforeClass public static void startServer() throws Exception { @@ -118,91 +82,57 @@ public abstract class AbstractLocalServerCase server.stop(); } - public void addInputInSegments(LocalConnector.LocalEndPoint endPoint, ByteBuffer outgoing, int segmentSize) + public DataFrame toDataFrame(byte op) { - while (outgoing.remaining() > 0) + switch (op) { - int len = Math.min(segmentSize, outgoing.remaining()); - ByteBuffer slice = outgoing.slice(); - slice.limit(len); - endPoint.addInput(slice); - outgoing.position(outgoing.position() + len); - } - } - - public void assertExpected(BlockingQueue framesQueue, List expect) throws InterruptedException - { - int expectedCount = expect.size(); - - String prefix; - for (int i = 0; i < expectedCount; i++) - { - prefix = "Frame[" + i + "]"; - - WebSocketFrame expected = expect.get(i); - WebSocketFrame actual = framesQueue.poll(1, TimeUnit.SECONDS); - assertThat(prefix + ".poll", actual, notNullValue()); - - if (LOG.isDebugEnabled()) - { - if (actual.getOpCode() == OpCode.CLOSE) - LOG.debug("{} CloseFrame: {}", prefix, new CloseInfo(actual)); - else - LOG.debug("{} {}", prefix, actual); - } - - assertThat(prefix + ".opcode", OpCode.name(actual.getOpCode()), Matchers.is(OpCode.name(expected.getOpCode()))); - prefix += "/" + actual.getOpCode(); - if (expected.getOpCode() == OpCode.CLOSE) - { - CloseInfo expectedClose = new CloseInfo(expected); - CloseInfo actualClose = new CloseInfo(actual); - assertThat(prefix + ".statusCode", actualClose.getStatusCode(), Matchers.is(expectedClose.getStatusCode())); - } - else if (expected.hasPayload()) - { - assertThat(prefix + ".payloadLength", actual.getPayloadLength(), Matchers.is(expected.getPayloadLength())); - ByteBufferAssert.assertEquals(prefix + ".payload", expected.getPayload(), actual.getPayload()); - } - else - { - assertThat(prefix + ".payloadLength", actual.getPayloadLength(), Matchers.is(0)); - } + case OpCode.BINARY: + return new BinaryFrame(); + case OpCode.TEXT: + return new TextFrame(); + case OpCode.CONTINUATION: + return new ContinuationFrame(); + default: + throw new IllegalArgumentException("Not a data frame: " + op); } } /** - * Make a copy of a byte buffer. - *

- * This is important in some tests, as the underlying byte buffer contained in a Frame can be modified through - * masking and make it difficult to compare the results in the fuzzer. + * Create a new multi-frame data message (TEXT or BINARY with CONTINUATIONS). * - * @param payload the payload to copy - * @return a new byte array of the payload contents + * @param send the list to add the individual frames making up the message + * @param opcode the opcode (message type: TEXT or BINARY) + * @param overallSize the overall size of the message + * @param frameSize the individual frame size to utilize + * @return the overall message payload (useful for expectation checks) */ - public ByteBuffer copyOf(byte[] payload) + public ByteBuffer newMultiFrameMessage(List send, byte opcode, int overallSize, int frameSize) { - return ByteBuffer.wrap(Arrays.copyOf(payload, payload.length)); - } - - public String generateUpgradeRequest(String requestPath, Map headers) - { - StringBuilder upgradeRequest = new StringBuilder(); - upgradeRequest.append("GET ").append(requestPath).append(" HTTP/1.1\r\n"); - headers.entrySet().stream().forEach(e -> - upgradeRequest.append(e.getKey()).append(": ").append(e.getValue()).append("\r\n")); - upgradeRequest.append("\r\n"); - return upgradeRequest.toString(); - } - - public String generateUpgradeRequest() - { - return generateUpgradeRequest("/", newDefaultUpgradeRequestHeaders()); - } - - public String generateUpgradeRequest(String requestPath) - { - return generateUpgradeRequest(requestPath, newDefaultUpgradeRequestHeaders()); + byte msg[] = new byte[overallSize]; + Arrays.fill(msg, (byte) 'M'); + + byte frag[]; + int remaining = msg.length; + int offset = 0; + boolean fin; + ByteBuffer buf; + byte op = opcode; + while (remaining > 0) + { + int len = Math.min(remaining, frameSize); + frag = new byte[len]; + System.arraycopy(msg, offset, frag, 0, len); + remaining -= len; + fin = (remaining <= 0); + buf = ByteBuffer.wrap(frag); + + send.add(toDataFrame(op).setPayload(buf).setFin(fin)); + + offset += len; + op = OpCode.CONTINUATION; + } + + return ByteBuffer.wrap(msg); } public Parser newClientParser(Parser.Handler parserHandler) @@ -210,31 +140,6 @@ public abstract class AbstractLocalServerCase return new Parser(WebSocketPolicy.newClientPolicy(), new MappedByteBufferPool(), parserHandler); } - public Map newDefaultUpgradeRequestHeaders() - { - Map headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); - headers.put("Host", "local"); - headers.put("Connection", "Upgrade"); - headers.put("Upgrade", "WebSocket"); - headers.put("Sec-WebSocket-Key", "dGhlIHNhbXBsZSBub25jZQ=="); - headers.put("Sec-WebSocket-Origin", "ws://local/"); - headers.put("Sec-WebSocket-Protocol", "echo"); - headers.put("Sec-WebSocket-Version", "13"); - return headers; - } - - public LocalConnector.LocalEndPoint newLocalConnection() - { - LocalConnector connector = server.getLocalConnector(); - LocalConnector.LocalEndPoint endPoint = connector.connect(); - return endPoint; - } - - public LocalFuzzer newLocalFuzzer() throws Exception - { - return new LocalFuzzer(this); - } - public HttpTester.Response performUpgrade(LocalConnector.LocalEndPoint endPoint, ByteBuffer buf) throws Exception { endPoint.addInput(buf); @@ -247,169 +152,4 @@ public abstract class AbstractLocalServerCase assertThat("Is WebSocket Upgrade", parsedResponse.get("Upgrade"), is("WebSocket")); return parsedResponse; } - - public static class LocalFuzzer implements AutoCloseable - { - private final AbstractLocalServerCase testcase; - private final LocalConnector.LocalEndPoint endPoint; - - public LocalFuzzer(AbstractLocalServerCase testcase) throws Exception - { - this.testcase = testcase; - String upgradeRequest = testcase.generateUpgradeRequest("/"); - ByteBuffer upgradeRequestBytes = BufferUtil.toBuffer(upgradeRequest.toString(), StandardCharsets.UTF_8); - this.endPoint = testcase.newLocalConnection(); - testcase.performUpgrade(endPoint, upgradeRequestBytes); - } - - public ByteBuffer asNetworkBuffer(List frames) - { - int bufferLength = 0; - for (WebSocketFrame f : frames) - { - bufferLength += f.getPayloadLength() + Generator.MAX_HEADER_LENGTH; - } - - ByteBuffer buffer = ByteBuffer.allocate(bufferLength); - - for (WebSocketFrame f : frames) - { - testcase.generator.generate(buffer, f); - } - BufferUtil.flipToFlush(buffer, 0); - return buffer; - } - - public void close() throws Exception - { - endPoint.close(); - } - - /** - * Send the EOF signal - */ - public void eof() - { - endPoint.addInputEOF(); - } - - public void expect(List expected) throws InterruptedException - { - // Get incoming frames - // Wait for server to close - endPoint.waitUntilClosed(); - - // Get the server send echo bytes - ByteBuffer incoming = endPoint.getOutput(); - - // Parse those bytes into frames - ParserCapture capture = new ParserCapture(); - Parser parser = testcase.newClientParser(capture); - parser.parse(incoming); - - testcase.assertExpected(capture.framesQueue, expected); - } - - /** - * Send raw bytes - */ - public void send(ByteBuffer buffer) - { - endPoint.addInput(buffer); - } - - /** - * Send some of the raw bytes - * - * @param buffer the buffer - * @param length the number of bytes to send from buffer - */ - public void send(ByteBuffer buffer, int length) - { - int limit = Math.min(length, buffer.remaining()); - ByteBuffer sliced = buffer.slice(); - sliced.limit(limit); - endPoint.addInput(sliced); - buffer.position(buffer.position() + limit); - } - - /** - * Generate a single ByteBuffer representing the entire - * list of generated frames, and submit it to {@link org.eclipse.jetty.server.LocalConnector.LocalEndPoint#addInput(ByteBuffer)} - * - * @param frames the list of frames to send - */ - public void sendBulk(List frames) - { - int bufferLength = 0; - for (WebSocketFrame f : frames) - { - bufferLength += f.getPayloadLength() + Generator.MAX_HEADER_LENGTH; - } - - ByteBuffer outgoing = ByteBuffer.allocate(bufferLength); - - boolean eof = false; - for (WebSocketFrame f : frames) - { - testcase.generator.generate(outgoing, f); - if (f.getOpCode() == OpCode.CLOSE) - eof = true; - } - BufferUtil.flipToFlush(outgoing, 0); - endPoint.addInput(outgoing); - if (eof) - 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(List frames) - { - boolean eof = false; - for (WebSocketFrame f : frames) - { - ByteBuffer buffer = testcase.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)} - * - * @param frames the list of frames to send - */ - public void sendSegmented(List frames, int segmentSize) - { - int bufferLength = 0; - for (WebSocketFrame f : frames) - { - bufferLength += f.getPayloadLength() + Generator.MAX_HEADER_LENGTH; - } - - ByteBuffer outgoing = ByteBuffer.allocate(bufferLength); - - boolean eof = false; - for (WebSocketFrame f : frames) - { - testcase.generator.generate(outgoing, f); - if (f.getOpCode() == OpCode.CLOSE) - eof = true; - } - BufferUtil.flipToFlush(outgoing, 0); - testcase.addInputInSegments(endPoint, outgoing, segmentSize); - if (eof) - endPoint.addInputEOF(); - } - } } diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/BadOpCodesTest.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/BadOpCodesTest.java index a5e6acbd4a8..df04b94e34a 100644 --- a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/BadOpCodesTest.java +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/BadOpCodesTest.java @@ -31,6 +31,7 @@ import org.eclipse.jetty.websocket.common.WebSocketFrame; import org.eclipse.jetty.websocket.common.frames.PingFrame; import org.eclipse.jetty.websocket.common.frames.TextFrame; import org.eclipse.jetty.websocket.tests.BadFrame; +import org.eclipse.jetty.websocket.tests.LocalFuzzer; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -70,9 +71,9 @@ public class BadOpCodesTest extends AbstractLocalServerCase List expect = new ArrayList<>(); expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame()); - + try (StacklessLogging ignored = new StacklessLogging(Parser.class); - LocalFuzzer session = newLocalFuzzer()) + LocalFuzzer session = server.newLocalFuzzer()) { session.sendBulk(send); session.expect(expect); @@ -92,9 +93,9 @@ public class BadOpCodesTest extends AbstractLocalServerCase List expect = new ArrayList<>(); expect.add(new TextFrame().setPayload("hello")); // echo expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame()); - + try (StacklessLogging ignored = new StacklessLogging(Parser.class); - LocalFuzzer session = newLocalFuzzer()) + LocalFuzzer session = server.newLocalFuzzer()) { session.sendBulk(send); session.expect(expect); diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/BinaryTest.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/BinaryTest.java new file mode 100644 index 00000000000..2e016bd56eb --- /dev/null +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/BinaryTest.java @@ -0,0 +1,437 @@ +// +// ======================================================================== +// 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.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +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.BinaryFrame; +import org.eclipse.jetty.websocket.tests.DataUtils; +import org.eclipse.jetty.websocket.tests.LocalFuzzer; +import org.junit.Test; + +/** + * Binary message / frame tests + */ +public class BinaryTest extends AbstractLocalServerCase +{ + /** + * Echo 16MB binary message (1 frame) + *

+ * From Autobahn WebSocket Server Testcase 9.2.6 + *

+ * @throws Exception on test failure + */ + @Test + public void testBinary_16mb_SingleFrame() throws Exception + { + byte data[] = new byte[16 * MBYTE]; + Arrays.fill(data,(byte)0x26); + ByteBuffer buf = ByteBuffer.wrap(data); + + List send = new ArrayList<>(); + send.add(new BinaryFrame().setPayload(buf)); + send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + List expect = new ArrayList<>(); + expect.add(new BinaryFrame().setPayload(DataUtils.copyOf(buf))); + expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + try(LocalFuzzer session = server.newLocalFuzzer()) + { + session.sendBulk(send); + session.expect(expect); + } + } + + /** + * Echo 1MB binary message (1 frame) + *

+ * From Autobahn WebSocket Server Testcase 9.2.3 + *

+ * @throws Exception on test failure + */ + @Test + public void testBinary_1mb_SingleFrame() throws Exception + { + byte data[] = new byte[1 * MBYTE]; + Arrays.fill(data,(byte)0x23); + ByteBuffer buf = ByteBuffer.wrap(data); + + List send = new ArrayList<>(); + send.add(new BinaryFrame().setPayload(buf)); + send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + List expect = new ArrayList<>(); + expect.add(new BinaryFrame().setPayload(DataUtils.copyOf(buf))); + expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + try(LocalFuzzer session = server.newLocalFuzzer()) + { + session.sendBulk(send); + session.expect(expect); + } + } + + /** + * Echo 256KB binary message (1 frame) + *

+ * From Autobahn WebSocket Server Testcase 9.2.2 + *

+ * @throws Exception on test failure + */ + @Test + public void testBinary_256kb_SingleFrame() throws Exception + { + byte data[] = new byte[256 * KBYTE]; + Arrays.fill(data,(byte)0x22); + ByteBuffer buf = ByteBuffer.wrap(data); + + List send = new ArrayList<>(); + send.add(new BinaryFrame().setPayload(buf)); + send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + List expect = new ArrayList<>(); + expect.add(new BinaryFrame().setPayload(DataUtils.copyOf(buf))); + expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + try(LocalFuzzer session = server.newLocalFuzzer()) + { + session.sendBulk(send); + session.expect(expect); + } + } + + /** + * Send 4MB binary message in multiple frames. + *

+ * From Autobahn WebSocket Server Testcase 9.4.5 + *

+ * @throws Exception on test failure + */ + @Test + public void testBinary_4mb_Frames_16kb() throws Exception + { + List send = new ArrayList<>(); + ByteBuffer payload = newMultiFrameMessage(send, OpCode.BINARY, 4 * MBYTE, 16 * KBYTE); + send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + List expect = new ArrayList<>(); + expect.add(new BinaryFrame().setPayload(payload)); + expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + try(LocalFuzzer session = server.newLocalFuzzer()) + { + session.sendBulk(send); + session.expect(expect); + } + } + + /** + * Send 4MB binary message in multiple frames. + *

+ * From Autobahn WebSocket Server Testcase 9.4.3 + *

+ * @throws Exception on test failure + */ + @Test + public void testBinary_4mb_Frames_1kb() throws Exception + { + List send = new ArrayList<>(); + ByteBuffer payload = newMultiFrameMessage(send, OpCode.BINARY, 4 * MBYTE, 1 * KBYTE); + send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + List expect = new ArrayList<>(); + expect.add(new BinaryFrame().setPayload(payload)); + expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + try(LocalFuzzer session = server.newLocalFuzzer()) + { + session.sendBulk(send); + session.expect(expect); + } + } + + /** + * Send 4MB binary message in multiple frames. + *

+ * From Autobahn WebSocket Server Testcase 9.4.8 + *

+ * @throws Exception on test failure + */ + @Test + public void testBinary_4mb_Frames_1mb() throws Exception + { + List send = new ArrayList<>(); + ByteBuffer payload = newMultiFrameMessage(send, OpCode.BINARY, 4 * MBYTE, 1 * MBYTE); + send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + List expect = new ArrayList<>(); + expect.add(new BinaryFrame().setPayload(payload)); + expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + try(LocalFuzzer session = server.newLocalFuzzer()) + { + session.sendBulk(send); + session.expect(expect); + } + } + + /** + * Send 4MB binary message in multiple frames. + *

+ * From Autobahn WebSocket Server Testcase 9.4.2 + *

+ * @throws Exception on test failure + */ + @Test + public void testBinary_4mb_Frames_256b() throws Exception + { + List send = new ArrayList<>(); + ByteBuffer payload = newMultiFrameMessage(send, OpCode.BINARY, 4 * MBYTE, 256); + send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + List expect = new ArrayList<>(); + expect.add(new BinaryFrame().setPayload(payload)); + expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + try(LocalFuzzer session = server.newLocalFuzzer()) + { + session.sendBulk(send); + session.expect(expect); + } + } + + /** + * Send 4MB binary message in multiple frames. + *

+ * From Autobahn WebSocket Server Testcase 9.4.7 + *

+ * @throws Exception on test failure + */ + @Test + public void testBinary_4mb_Frames_256kb() throws Exception + { + List send = new ArrayList<>(); + ByteBuffer payload = newMultiFrameMessage(send, OpCode.BINARY, 4 * MBYTE, 256 * KBYTE); + send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + List expect = new ArrayList<>(); + expect.add(new BinaryFrame().setPayload(payload)); + expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + try(LocalFuzzer session = server.newLocalFuzzer()) + { + session.sendBulk(send); + session.expect(expect); + } + } + + /** + * Send 4MB binary message in multiple frames. + *

+ * From Autobahn WebSocket Server Testcase 9.4.4 + *

+ * @throws Exception on test failure + */ + @Test + public void testBinary_4mb_Frames_4kb() throws Exception + { + List send = new ArrayList<>(); + ByteBuffer payload = newMultiFrameMessage(send, OpCode.BINARY, 4 * MBYTE, 4 * KBYTE); + send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + List expect = new ArrayList<>(); + expect.add(new BinaryFrame().setPayload(payload)); + expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + try(LocalFuzzer session = server.newLocalFuzzer()) + { + session.sendBulk(send); + session.expect(expect); + } + } + + /** + * Send 4MB binary message in multiple frames. + *

+ * From Autobahn WebSocket Server Testcase 9.4.9 + *

+ * @throws Exception on test failure + */ + @Test + public void testBinary_4mb_Frames_4mb() throws Exception + { + List send = new ArrayList<>(); + ByteBuffer payload = newMultiFrameMessage(send, OpCode.BINARY, 4 * MBYTE, 4 * MBYTE); + send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + List expect = new ArrayList<>(); + expect.add(new BinaryFrame().setPayload(payload)); + expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + try(LocalFuzzer session = server.newLocalFuzzer()) + { + session.sendBulk(send); + session.expect(expect); + } + } + + /** + * Send 4MB binary message in multiple frames. + *

+ * From Autobahn WebSocket Server Testcase 9.4.1 + *

+ * @throws Exception on test failure + */ + @Test + public void testBinary_4mb_Frames_64b() throws Exception + { + List send = new ArrayList<>(); + ByteBuffer payload = newMultiFrameMessage(send, OpCode.BINARY, 4 * MBYTE, 64); + send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + List expect = new ArrayList<>(); + expect.add(new BinaryFrame().setPayload(payload)); + expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + try(LocalFuzzer session = server.newLocalFuzzer()) + { + session.sendBulk(send); + session.expect(expect); + } + } + + /** + * Send 4MB binary message in multiple frames. + *

+ * From Autobahn WebSocket Server Testcase 9.4.6 + *

+ * @throws Exception on test failure + */ + @Test + public void testBinary_4mb_Frames_64kb() throws Exception + { + List send = new ArrayList<>(); + ByteBuffer payload = newMultiFrameMessage(send, OpCode.BINARY, 4 * MBYTE, 64 * KBYTE); + send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + List expect = new ArrayList<>(); + expect.add(new BinaryFrame().setPayload(payload)); + expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + try(LocalFuzzer session = server.newLocalFuzzer()) + { + session.sendBulk(send); + session.expect(expect); + } + } + + /** + * Echo 4MB binary message (1 frame) + *

+ * From Autobahn WebSocket Server Testcase 9.2.4 + *

+ * @throws Exception on test failure + */ + @Test + public void testBinary_4mb_SingleFrame() throws Exception + { + byte data[] = new byte[4 * MBYTE]; + Arrays.fill(data,(byte)0x24); + ByteBuffer buf = ByteBuffer.wrap(data); + + List send = new ArrayList<>(); + send.add(new BinaryFrame().setPayload(buf)); + send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + List expect = new ArrayList<>(); + expect.add(new BinaryFrame().setPayload(DataUtils.copyOf(buf))); + expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + try(LocalFuzzer session = server.newLocalFuzzer()) + { + session.sendBulk(send); + session.expect(expect); + } + } + + /** + * Echo 64KB binary message (1 frame) + *

+ * From Autobahn WebSocket Server Testcase 9.2.1 + *

+ * @throws Exception on test failure + */ + @Test + public void testBinary_64kb_SingleFrame() throws Exception + { + byte data[] = new byte[64 * KBYTE]; + Arrays.fill(data,(byte)0x21); + + List send = new ArrayList<>(); + send.add(new BinaryFrame().setPayload(data)); + send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + List expect = new ArrayList<>(); + expect.add(new BinaryFrame().setPayload(DataUtils.copyOf(data))); + expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + try(LocalFuzzer session = server.newLocalFuzzer()) + { + session.sendBulk(send); + session.expect(expect); + } + } + + /** + * Echo 8MB binary message (1 frame) + *

+ * From Autobahn WebSocket Server Testcase 9.2.5 + *

+ * @throws Exception on test failure + */ + @Test + public void testBinary_8mb_SingleFrame() throws Exception + { + byte data[] = new byte[8 * MBYTE]; + Arrays.fill(data,(byte)0x25); + ByteBuffer buf = ByteBuffer.wrap(data); + + List send = new ArrayList<>(); + send.add(new BinaryFrame().setPayload(buf)); + send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + List expect = new ArrayList<>(); + expect.add(new BinaryFrame().setPayload(DataUtils.copyOf(buf))); + expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + try(LocalFuzzer session = server.newLocalFuzzer()) + { + session.sendBulk(send); + session.expect(expect); + } + } +} diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/CloseHandlingTest.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/CloseHandlingTest.java index e8a408e2552..2bc7db594b9 100644 --- a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/CloseHandlingTest.java +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/CloseHandlingTest.java @@ -38,6 +38,8 @@ import org.eclipse.jetty.websocket.common.frames.PingFrame; import org.eclipse.jetty.websocket.common.frames.TextFrame; import org.eclipse.jetty.websocket.common.io.AbstractWebSocketConnection; import org.eclipse.jetty.websocket.tests.BadFrame; +import org.eclipse.jetty.websocket.tests.DataUtils; +import org.eclipse.jetty.websocket.tests.LocalFuzzer; import org.junit.Test; /** @@ -63,9 +65,9 @@ public class CloseHandlingTest extends AbstractLocalServerCase List expect = new ArrayList<>(); expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame()); - + try (StacklessLogging ignored = new StacklessLogging(Parser.class); - LocalFuzzer session = newLocalFuzzer()) + LocalFuzzer session = server.newLocalFuzzer()) { session.sendBulk(send); session.expect(expect); @@ -95,9 +97,9 @@ public class CloseHandlingTest extends AbstractLocalServerCase List expect = new ArrayList<>(); expect.add(new CloseInfo(StatusCode.BAD_PAYLOAD).asFrame()); - + try (StacklessLogging ignored = new StacklessLogging(Parser.class,CloseInfo.class); - LocalFuzzer session = newLocalFuzzer()) + LocalFuzzer session = server.newLocalFuzzer()) { session.sendBulk(send); session.expect(expect); @@ -120,7 +122,7 @@ public class CloseHandlingTest extends AbstractLocalServerCase List expect = new ArrayList<>(); expect.add(new CloseFrame()); - try (LocalFuzzer session = newLocalFuzzer()) + try (LocalFuzzer session = server.newLocalFuzzer()) { session.sendBulk(send); session.expect(expect); @@ -146,9 +148,9 @@ public class CloseHandlingTest extends AbstractLocalServerCase List expect = new ArrayList<>(); expect.add(new CloseInfo(StatusCode.NORMAL,reason).asFrame()); - + try (StacklessLogging ignored = new StacklessLogging(AbstractWebSocketConnection.class); - LocalFuzzer session = newLocalFuzzer()) + LocalFuzzer session = server.newLocalFuzzer()) { session.sendBulk(send); session.expect(expect); @@ -173,7 +175,7 @@ public class CloseHandlingTest extends AbstractLocalServerCase expect.add(new TextFrame().setPayload("Hello World")); expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - try (LocalFuzzer session = newLocalFuzzer()) + try (LocalFuzzer session = server.newLocalFuzzer()) { session.sendBulk(send); session.expect(expect); @@ -197,7 +199,7 @@ public class CloseHandlingTest extends AbstractLocalServerCase List expect = new ArrayList<>(); expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - try (LocalFuzzer session = newLocalFuzzer()) + try (LocalFuzzer session = server.newLocalFuzzer()) { session.sendBulk(send); session.expect(expect); @@ -220,7 +222,7 @@ public class CloseHandlingTest extends AbstractLocalServerCase List expect = new ArrayList<>(); expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - try (LocalFuzzer session = newLocalFuzzer()) + try (LocalFuzzer session = server.newLocalFuzzer()) { session.sendBulk(send); session.expect(expect); @@ -243,7 +245,7 @@ public class CloseHandlingTest extends AbstractLocalServerCase List expect = new ArrayList<>(); expect.add(new CloseInfo(StatusCode.NORMAL,"Hic").asFrame()); - try (LocalFuzzer session = newLocalFuzzer()) + try (LocalFuzzer session = server.newLocalFuzzer()) { session.sendBulk(send); session.expect(expect); @@ -267,7 +269,7 @@ public class CloseHandlingTest extends AbstractLocalServerCase List expect = new ArrayList<>(); expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - try (LocalFuzzer session = newLocalFuzzer()) + try (LocalFuzzer session = server.newLocalFuzzer()) { session.sendBulk(send); session.expect(expect); @@ -291,7 +293,7 @@ public class CloseHandlingTest extends AbstractLocalServerCase List expect = new ArrayList<>(); expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - try (LocalFuzzer session = newLocalFuzzer()) + try (LocalFuzzer session = server.newLocalFuzzer()) { session.sendBulk(send); session.expect(expect); @@ -316,7 +318,7 @@ public class CloseHandlingTest extends AbstractLocalServerCase List expect = new ArrayList<>(); expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - try (LocalFuzzer session = newLocalFuzzer()) + try (LocalFuzzer session = server.newLocalFuzzer()) { session.sendBulk(send); session.expect(expect); @@ -343,10 +345,10 @@ public class CloseHandlingTest extends AbstractLocalServerCase send.add(new PingFrame().setPayload("out of band")); List expect = new ArrayList<>(); - expect.add(new TextFrame().setPayload(clone(buf))); + expect.add(new TextFrame().setPayload(DataUtils.copyOf(buf))); expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - try (LocalFuzzer session = newLocalFuzzer()) + try (LocalFuzzer session = server.newLocalFuzzer()) { session.sendBulk(send); session.expect(expect); diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/TestABCase7_BadStatusCodes.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/CloseHandling_BadStatusCodesTest.java similarity index 86% rename from jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/TestABCase7_BadStatusCodes.java rename to jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/CloseHandling_BadStatusCodesTest.java index 703ef77ba9a..49ff72f9621 100644 --- a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/TestABCase7_BadStatusCodes.java +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/CloseHandling_BadStatusCodesTest.java @@ -25,13 +25,11 @@ import java.util.List; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.StringUtil; -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.common.CloseInfo; import org.eclipse.jetty.websocket.common.WebSocketFrame; import org.eclipse.jetty.websocket.common.frames.CloseFrame; -import org.eclipse.jetty.websocket.tests.Fuzzer; +import org.eclipse.jetty.websocket.tests.LocalFuzzer; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -41,11 +39,9 @@ import org.junit.runners.Parameterized.Parameters; * Test Bad Close Status Codes */ @RunWith(value = Parameterized.class) -public class TestABCase7_BadStatusCodes extends AbstractABCase +public class CloseHandling_BadStatusCodesTest extends AbstractLocalServerCase { - private static final Logger LOG = Log.getLogger(TestABCase7_GoodStatusCodes.class); - - @Parameters + @Parameters(name = "{0} {1}") public static Collection data() { // The various Good UTF8 sequences as a String (hex form) @@ -75,7 +71,7 @@ public class TestABCase7_BadStatusCodes extends AbstractABCase private final int statusCode; - public TestABCase7_BadStatusCodes(String testId, int statusCode) + public CloseHandling_BadStatusCodesTest(String testId, int statusCode) { LOG.debug("Test ID: {}", testId); this.statusCode = statusCode; @@ -99,11 +95,10 @@ public class TestABCase7_BadStatusCodes extends AbstractABCase List expect = new ArrayList<>(); expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame()); - - try (Fuzzer.Session session = fuzzer.connect(this)) + + try (LocalFuzzer session = server.newLocalFuzzer()) { - session.bulkMode(); - session.send(send); + session.sendBulk(send); session.expect(expect); } } @@ -127,11 +122,10 @@ public class TestABCase7_BadStatusCodes extends AbstractABCase List expect = new ArrayList<>(); expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame()); - - try (Fuzzer.Session session = fuzzer.connect(this)) + + try (LocalFuzzer session = server.newLocalFuzzer()) { - session.bulkMode(); - session.send(send); + session.sendBulk(send); session.expect(expect); } } diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/TestABCase7_GoodStatusCodes.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/CloseHandling_GoodStatusCodesTest.java similarity index 83% rename from jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/TestABCase7_GoodStatusCodes.java rename to jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/CloseHandling_GoodStatusCodesTest.java index 056b9959432..dab60436495 100644 --- a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/TestABCase7_GoodStatusCodes.java +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/CloseHandling_GoodStatusCodesTest.java @@ -29,7 +29,8 @@ import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.websocket.common.WebSocketFrame; import org.eclipse.jetty.websocket.common.frames.CloseFrame; -import org.eclipse.jetty.websocket.tests.Fuzzer; +import org.eclipse.jetty.websocket.tests.DataUtils; +import org.eclipse.jetty.websocket.tests.LocalFuzzer; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -39,11 +40,11 @@ import org.junit.runners.Parameterized.Parameters; * Test Good Close Status Codes */ @RunWith(value = Parameterized.class) -public class TestABCase7_GoodStatusCodes extends AbstractABCase +public class CloseHandling_GoodStatusCodesTest extends AbstractLocalServerCase { - private static final Logger LOG = Log.getLogger(TestABCase7_GoodStatusCodes.class); + private static final Logger LOG = Log.getLogger(CloseHandling_GoodStatusCodesTest.class); - @Parameters + @Parameters(name = "{0} {1}") public static Collection data() { // The various Good UTF8 sequences as a String (hex form) @@ -70,7 +71,7 @@ public class TestABCase7_GoodStatusCodes extends AbstractABCase private final int statusCode; - public TestABCase7_GoodStatusCodes(String testId, int statusCode) + public CloseHandling_GoodStatusCodesTest(String testId, int statusCode) { LOG.debug("Test ID: {}", testId); this.statusCode = statusCode; @@ -93,12 +94,11 @@ public class TestABCase7_GoodStatusCodes extends AbstractABCase send.add(new CloseFrame().setPayload(payload.slice())); List expect = new ArrayList<>(); - expect.add(new CloseFrame().setPayload(clone(payload))); - - try (Fuzzer.Session session = fuzzer.connect(this)) + expect.add(new CloseFrame().setPayload(DataUtils.copyOf(payload))); + + try (LocalFuzzer session = server.newLocalFuzzer()) { - session.bulkMode(); - session.send(send); + session.sendBulk(send); session.expect(expect); } } @@ -120,12 +120,11 @@ public class TestABCase7_GoodStatusCodes extends AbstractABCase send.add(new CloseFrame().setPayload(payload.slice())); List expect = new ArrayList<>(); - expect.add(new CloseFrame().setPayload(clone(payload))); - - try (Fuzzer.Session session = fuzzer.connect(this)) + expect.add(new CloseFrame().setPayload(DataUtils.copyOf(payload))); + + try (LocalFuzzer session = server.newLocalFuzzer()) { - session.bulkMode(); - session.send(send); + session.sendBulk(send); session.expect(expect); } } diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/ConnectionUpgradeToBufferTest.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/ConnectionUpgradeToBufferTest.java index c3f29c12858..8f436b18f67 100644 --- a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/ConnectionUpgradeToBufferTest.java +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/ConnectionUpgradeToBufferTest.java @@ -36,6 +36,7 @@ import org.eclipse.jetty.websocket.common.Parser; import org.eclipse.jetty.websocket.common.WebSocketFrame; import org.eclipse.jetty.websocket.common.frames.TextFrame; import org.eclipse.jetty.websocket.tests.ParserCapture; +import org.eclipse.jetty.websocket.tests.UpgradeUtils; import org.junit.Test; /** @@ -57,7 +58,7 @@ public class ConnectionUpgradeToBufferTest extends AbstractLocalServerCase ByteBuffer buf = ByteBuffer.allocate(4096); // Create Upgrade Request Header - String upgradeRequest = generateUpgradeRequest("/"); + String upgradeRequest = UpgradeUtils.generateUpgradeRequest("/"); ByteBuffer upgradeRequestBytes = BufferUtil.toBuffer(upgradeRequest.toString(), StandardCharsets.UTF_8); BufferUtil.put(upgradeRequestBytes, buf); @@ -70,7 +71,7 @@ public class ConnectionUpgradeToBufferTest extends AbstractLocalServerCase generator.generate(buf, frames); // Send this buffer to the server - LocalConnector.LocalEndPoint endPoint = newLocalConnection(); + LocalConnector.LocalEndPoint endPoint = server.newLocalConnection(); BufferUtil.flipToFlush(buf,0); performUpgrade(endPoint, buf); diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/ContinuationTest.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/ContinuationTest.java index 5c6481abf83..c9d0c7e7966 100644 --- a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/ContinuationTest.java +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/ContinuationTest.java @@ -31,6 +31,7 @@ import org.eclipse.jetty.websocket.common.frames.ContinuationFrame; import org.eclipse.jetty.websocket.common.frames.PingFrame; import org.eclipse.jetty.websocket.common.frames.PongFrame; import org.eclipse.jetty.websocket.common.frames.TextFrame; +import org.eclipse.jetty.websocket.tests.LocalFuzzer; import org.junit.Test; /** @@ -55,9 +56,9 @@ public class ContinuationTest extends AbstractLocalServerCase List expect = new ArrayList<>(); expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame()); - + try (StacklessLogging ignored = new StacklessLogging(Parser.class); - LocalFuzzer session = newLocalFuzzer()) + LocalFuzzer session = server.newLocalFuzzer()) { session.sendBulk(send); session.expect(expect); @@ -81,9 +82,9 @@ public class ContinuationTest extends AbstractLocalServerCase List expect = new ArrayList<>(); expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame()); - + try (StacklessLogging ignored = new StacklessLogging(Parser.class); - LocalFuzzer session = newLocalFuzzer()) + LocalFuzzer session = server.newLocalFuzzer()) { session.sendFrames(send); session.expect(expect); @@ -107,9 +108,9 @@ public class ContinuationTest extends AbstractLocalServerCase List expect = new ArrayList<>(); expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame()); - + try (StacklessLogging ignored = new StacklessLogging(Parser.class); - LocalFuzzer session = newLocalFuzzer()) + LocalFuzzer session = server.newLocalFuzzer()) { session.sendSegmented(send,1 ); session.expect(expect); @@ -135,7 +136,7 @@ public class ContinuationTest extends AbstractLocalServerCase expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame()); try (StacklessLogging ignored = new StacklessLogging(Parser.class); - LocalFuzzer session = newLocalFuzzer()) + LocalFuzzer session = server.newLocalFuzzer()) { session.sendBulk(send); session.expect(expect); @@ -162,9 +163,9 @@ public class ContinuationTest extends AbstractLocalServerCase List expect = new ArrayList<>(); expect.add(new TextFrame().setPayload("fragment1fragment2")); expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame()); - + try (StacklessLogging ignored = new StacklessLogging(Parser.class); - LocalFuzzer session = newLocalFuzzer()) + LocalFuzzer session = server.newLocalFuzzer()) { session.sendBulk(send); session.expect(expect); @@ -188,9 +189,9 @@ public class ContinuationTest extends AbstractLocalServerCase List expect = new ArrayList<>(); expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame()); - + try (StacklessLogging ignored = new StacklessLogging(Parser.class); - LocalFuzzer session = newLocalFuzzer()) + LocalFuzzer session = server.newLocalFuzzer()) { session.sendFrames(send); session.expect(expect); @@ -218,9 +219,9 @@ public class ContinuationTest extends AbstractLocalServerCase List expect = new ArrayList<>(); expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame()); - + try (StacklessLogging ignored = new StacklessLogging(Parser.class); - LocalFuzzer session = newLocalFuzzer()) + LocalFuzzer session = server.newLocalFuzzer()) { session.sendBulk(send); session.expect(expect); @@ -244,9 +245,9 @@ public class ContinuationTest extends AbstractLocalServerCase List expect = new ArrayList<>(); expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame()); - + try (StacklessLogging ignored = new StacklessLogging(Parser.class); - LocalFuzzer session = newLocalFuzzer()) + LocalFuzzer session = server.newLocalFuzzer()) { session.sendSegmented(send,1); session.expect(expect); @@ -274,9 +275,9 @@ public class ContinuationTest extends AbstractLocalServerCase List expect = new ArrayList<>(); expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame()); - + try (StacklessLogging ignored = new StacklessLogging(Parser.class); - LocalFuzzer session = newLocalFuzzer()) + LocalFuzzer session = server.newLocalFuzzer()) { session.sendBulk(send); session.expect(expect); @@ -300,9 +301,9 @@ public class ContinuationTest extends AbstractLocalServerCase List expect = new ArrayList<>(); expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame()); - + try (StacklessLogging ignored = new StacklessLogging(Parser.class); - LocalFuzzer session = newLocalFuzzer()) + LocalFuzzer session = server.newLocalFuzzer()) { session.sendBulk(send); session.expect(expect); @@ -326,9 +327,9 @@ public class ContinuationTest extends AbstractLocalServerCase List expect = new ArrayList<>(); expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame()); - + try (StacklessLogging ignored = new StacklessLogging(Parser.class); - LocalFuzzer session = newLocalFuzzer()) + LocalFuzzer session = server.newLocalFuzzer()) { session.sendBulk(send); session.expect(expect); @@ -352,9 +353,9 @@ public class ContinuationTest extends AbstractLocalServerCase List expect = new ArrayList<>(); expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame()); - + try (StacklessLogging ignored = new StacklessLogging(Parser.class); - LocalFuzzer session = newLocalFuzzer()) + LocalFuzzer session = server.newLocalFuzzer()) { session.sendBulk(send); session.expect(expect); @@ -381,7 +382,7 @@ public class ContinuationTest extends AbstractLocalServerCase expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); try (StacklessLogging ignored = new StacklessLogging(Parser.class); - LocalFuzzer session = newLocalFuzzer()) + LocalFuzzer session = server.newLocalFuzzer()) { session.sendBulk(send); session.expect(expect); @@ -406,9 +407,9 @@ public class ContinuationTest extends AbstractLocalServerCase List expect = new ArrayList<>(); expect.add(new TextFrame().setPayload("hello, world")); expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - + try (StacklessLogging ignored = new StacklessLogging(Parser.class); - LocalFuzzer session = newLocalFuzzer()) + LocalFuzzer session = server.newLocalFuzzer()) { session.sendFrames(send); session.expect(expect); @@ -441,9 +442,9 @@ public class ContinuationTest extends AbstractLocalServerCase expect.add(new PongFrame().setPayload("pong-2")); expect.add(new TextFrame().setPayload("f1,f2,f3,f4,f5")); expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - + try (StacklessLogging ignored = new StacklessLogging(Parser.class); - LocalFuzzer session = newLocalFuzzer()) + LocalFuzzer session = server.newLocalFuzzer()) { session.sendBulk(send); session.expect(expect); @@ -468,9 +469,9 @@ public class ContinuationTest extends AbstractLocalServerCase List expect = new ArrayList<>(); expect.add(new TextFrame().setPayload("hello, world")); expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - + try (StacklessLogging ignored = new StacklessLogging(Parser.class); - LocalFuzzer session = newLocalFuzzer()) + LocalFuzzer session = server.newLocalFuzzer()) { session.sendSegmented(send,1); session.expect(expect); @@ -499,7 +500,7 @@ public class ContinuationTest extends AbstractLocalServerCase expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); try (StacklessLogging ignored = new StacklessLogging(Parser.class); - LocalFuzzer session = newLocalFuzzer()) + LocalFuzzer session = server.newLocalFuzzer()) { session.sendBulk(send); session.expect(expect); @@ -526,9 +527,9 @@ public class ContinuationTest extends AbstractLocalServerCase expect.add(new PongFrame().setPayload("ping")); expect.add(new TextFrame().setPayload("hello, world")); expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - + try (StacklessLogging ignored = new StacklessLogging(Parser.class); - LocalFuzzer session = newLocalFuzzer()) + LocalFuzzer session = server.newLocalFuzzer()) { session.sendFrames(send); session.expect(expect); @@ -555,9 +556,9 @@ public class ContinuationTest extends AbstractLocalServerCase expect.add(new PongFrame().setPayload("ping")); expect.add(new TextFrame().setPayload("hello, world")); expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - + try (StacklessLogging ignored = new StacklessLogging(Parser.class); - LocalFuzzer session = newLocalFuzzer()) + LocalFuzzer session = server.newLocalFuzzer()) { session.sendSegmented(send,1); session.expect(expect); diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/PayloadLengthTest.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/PayloadLengthTest.java index 269cd345c0c..eed8358502a 100644 --- a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/PayloadLengthTest.java +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/PayloadLengthTest.java @@ -28,6 +28,8 @@ import org.eclipse.jetty.websocket.common.CloseInfo; import org.eclipse.jetty.websocket.common.WebSocketFrame; import org.eclipse.jetty.websocket.common.frames.BinaryFrame; import org.eclipse.jetty.websocket.common.frames.TextFrame; +import org.eclipse.jetty.websocket.tests.DataUtils; +import org.eclipse.jetty.websocket.tests.LocalFuzzer; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -69,10 +71,10 @@ public class PayloadLengthTest extends AbstractLocalServerCase send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); List expect = new ArrayList<>(); - expect.add(new TextFrame().setPayload(clone(buf))); + expect.add(new TextFrame().setPayload(DataUtils.copyOf(buf))); expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - - try (LocalFuzzer session = newLocalFuzzer()) + + try (LocalFuzzer session = server.newLocalFuzzer()) { session.sendBulk(send); session.expect(expect); @@ -91,10 +93,10 @@ public class PayloadLengthTest extends AbstractLocalServerCase send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); List expect = new ArrayList<>(); - expect.add(new TextFrame().setPayload(clone(buf))); + expect.add(new TextFrame().setPayload(DataUtils.copyOf(buf))); expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - - try (LocalFuzzer session = newLocalFuzzer()) + + try (LocalFuzzer session = server.newLocalFuzzer()) { session.sendSegmented(send, 10); session.expect(expect); @@ -113,10 +115,10 @@ public class PayloadLengthTest extends AbstractLocalServerCase send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); List expect = new ArrayList<>(); - expect.add(new BinaryFrame().setPayload(clone(buf))); + expect.add(new BinaryFrame().setPayload(DataUtils.copyOf(buf))); expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - - try (LocalFuzzer session = newLocalFuzzer()) + + try (LocalFuzzer session = server.newLocalFuzzer()) { session.sendBulk(send); session.expect(expect); @@ -135,10 +137,10 @@ public class PayloadLengthTest extends AbstractLocalServerCase send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); List expect = new ArrayList<>(); - expect.add(new BinaryFrame().setPayload(clone(buf))); + expect.add(new BinaryFrame().setPayload(DataUtils.copyOf(buf))); expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - - try (LocalFuzzer session = newLocalFuzzer()) + + try (LocalFuzzer session = server.newLocalFuzzer()) { session.sendSegmented(send, 10); session.expect(expect); diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/PingPongTest.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/PingPongTest.java index 36252f2fe8c..51c9f2dcb2f 100644 --- a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/PingPongTest.java +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/PingPongTest.java @@ -33,6 +33,8 @@ import org.eclipse.jetty.websocket.common.WebSocketFrame; import org.eclipse.jetty.websocket.common.frames.PingFrame; import org.eclipse.jetty.websocket.common.frames.PongFrame; import org.eclipse.jetty.websocket.tests.BadFrame; +import org.eclipse.jetty.websocket.tests.DataUtils; +import org.eclipse.jetty.websocket.tests.LocalFuzzer; import org.junit.Test; public class PingPongTest extends AbstractLocalServerCase @@ -66,8 +68,8 @@ public class PingPongTest extends AbstractLocalServerCase } send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - - try (LocalFuzzer session = newLocalFuzzer()) + + try (LocalFuzzer session = server.newLocalFuzzer()) { session.sendBulk(send); session.expect(expect); @@ -103,8 +105,8 @@ public class PingPongTest extends AbstractLocalServerCase } send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - - try (LocalFuzzer session = newLocalFuzzer()) + + try (LocalFuzzer session = server.newLocalFuzzer()) { session.sendSegmented(send, 5); session.expect(expect); @@ -130,10 +132,10 @@ public class PingPongTest extends AbstractLocalServerCase send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); List expect = new ArrayList<>(); - expect.add(new PongFrame().setPayload(copyOf(payload))); + expect.add(new PongFrame().setPayload(DataUtils.copyOf(payload))); expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - - try (LocalFuzzer session = newLocalFuzzer()) + + try (LocalFuzzer session = server.newLocalFuzzer()) { session.sendBulk(send); session.expect(expect); @@ -159,10 +161,10 @@ public class PingPongTest extends AbstractLocalServerCase send.add(new CloseInfo(StatusCode.NORMAL, "Test 2.6").asFrame()); List expect = new ArrayList<>(); - expect.add(new PongFrame().setPayload(copyOf(payload))); + expect.add(new PongFrame().setPayload(DataUtils.copyOf(payload))); expect.add(new CloseInfo(StatusCode.NORMAL, "Test 2.6").asFrame()); - - try (LocalFuzzer session = newLocalFuzzer()) + + try (LocalFuzzer session = server.newLocalFuzzer()) { session.sendSegmented(send, 1); session.expect(expect); @@ -187,8 +189,8 @@ public class PingPongTest extends AbstractLocalServerCase List expect = new ArrayList<>(); expect.add(new PongFrame()); expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - - try (LocalFuzzer session = newLocalFuzzer()) + + try (LocalFuzzer session = server.newLocalFuzzer()) { session.sendBulk(send); session.expect(expect); @@ -219,8 +221,8 @@ public class PingPongTest extends AbstractLocalServerCase List expect = new ArrayList<>(); expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame()); - - try (LocalFuzzer session = newLocalFuzzer()) + + try (LocalFuzzer session = server.newLocalFuzzer()) { session.sendBulk(send); session.expect(expect); @@ -246,10 +248,10 @@ public class PingPongTest extends AbstractLocalServerCase send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); List expect = new ArrayList<>(); - expect.add(new PongFrame().setPayload(copyOf(payload))); + expect.add(new PongFrame().setPayload(DataUtils.copyOf(payload))); expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - - try (LocalFuzzer session = newLocalFuzzer()) + + try (LocalFuzzer session = server.newLocalFuzzer()) { session.sendBulk(send); session.expect(expect); @@ -274,10 +276,10 @@ public class PingPongTest extends AbstractLocalServerCase send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); List expect = new ArrayList<>(); - expect.add(new PongFrame().setPayload(copyOf(payload))); + expect.add(new PongFrame().setPayload(DataUtils.copyOf(payload))); expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - - try (LocalFuzzer session = newLocalFuzzer()) + + try (LocalFuzzer session = server.newLocalFuzzer()) { session.sendBulk(send); session.expect(expect); @@ -301,8 +303,8 @@ public class PingPongTest extends AbstractLocalServerCase List expect = new ArrayList<>(); expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - - try (LocalFuzzer session = newLocalFuzzer()) + + try (LocalFuzzer session = server.newLocalFuzzer()) { session.sendBulk(send); session.expect(expect); @@ -326,8 +328,8 @@ public class PingPongTest extends AbstractLocalServerCase List expect = new ArrayList<>(); expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - - try (LocalFuzzer session = newLocalFuzzer()) + + try (LocalFuzzer session = server.newLocalFuzzer()) { session.sendBulk(send); session.expect(expect); @@ -353,8 +355,8 @@ public class PingPongTest extends AbstractLocalServerCase List expect = new ArrayList<>(); expect.add(new PongFrame().setPayload("our ping")); // our pong expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - - try (LocalFuzzer session = newLocalFuzzer()) + + try (LocalFuzzer session = server.newLocalFuzzer()) { session.sendBulk(send); session.expect(expect); diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/ReservedBitTest.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/ReservedBitTest.java index 15e13a9b3b6..75e7c38591e 100644 --- a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/ReservedBitTest.java +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/ReservedBitTest.java @@ -30,6 +30,7 @@ import org.eclipse.jetty.websocket.common.WebSocketFrame; import org.eclipse.jetty.websocket.common.frames.BinaryFrame; import org.eclipse.jetty.websocket.common.frames.PingFrame; import org.eclipse.jetty.websocket.common.frames.TextFrame; +import org.eclipse.jetty.websocket.tests.LocalFuzzer; import org.junit.Test; /** @@ -54,7 +55,7 @@ public class ReservedBitTest extends AbstractLocalServerCase expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame()); try (StacklessLogging ignored = new StacklessLogging(Parser.class); - LocalFuzzer session = newLocalFuzzer()) + LocalFuzzer session = server.newLocalFuzzer()) { session.sendBulk(send); session.expect(expect); @@ -81,7 +82,7 @@ public class ReservedBitTest extends AbstractLocalServerCase expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame()); try (StacklessLogging ignored = new StacklessLogging(Parser.class); - LocalFuzzer session = newLocalFuzzer()) + LocalFuzzer session = server.newLocalFuzzer()) { session.sendBulk(send); session.expect(expect); @@ -106,9 +107,9 @@ public class ReservedBitTest extends AbstractLocalServerCase List expect = new ArrayList<>(); expect.add(new TextFrame().setPayload("small")); // echo on good frame expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame()); - + try (StacklessLogging ignored = new StacklessLogging(Parser.class); - LocalFuzzer session = newLocalFuzzer()) + LocalFuzzer session = server.newLocalFuzzer()) { session.sendFrames(send); session.expect(expect); @@ -133,9 +134,9 @@ public class ReservedBitTest extends AbstractLocalServerCase List expect = new ArrayList<>(); expect.add(new TextFrame().setPayload("small")); // echo on good frame expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame()); - + try (StacklessLogging ignored = new StacklessLogging(Parser.class); - LocalFuzzer session = newLocalFuzzer()) + LocalFuzzer session = server.newLocalFuzzer()) { session.sendSegmented(send, 1); session.expect(expect); @@ -162,7 +163,7 @@ public class ReservedBitTest extends AbstractLocalServerCase expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame()); try (StacklessLogging ignored = new StacklessLogging(Parser.class); - LocalFuzzer session = newLocalFuzzer()) + LocalFuzzer session = server.newLocalFuzzer()) { session.sendBulk(send); session.expect(expect); @@ -187,9 +188,9 @@ public class ReservedBitTest extends AbstractLocalServerCase List expect = new ArrayList<>(); expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame()); - + try (StacklessLogging ignored = new StacklessLogging(Parser.class); - LocalFuzzer session = newLocalFuzzer()) + LocalFuzzer session = server.newLocalFuzzer()) { session.sendBulk(send); session.expect(expect); @@ -217,7 +218,7 @@ public class ReservedBitTest extends AbstractLocalServerCase expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame()); try (StacklessLogging ignored = new StacklessLogging(Parser.class); - LocalFuzzer session = newLocalFuzzer()) + LocalFuzzer session = server.newLocalFuzzer()) { session.sendBulk(send); session.expect(expect); diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/TestABCase9.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/TestABCase9.java deleted file mode 100644 index 3d9dbf1c0ba..00000000000 --- a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/TestABCase9.java +++ /dev/null @@ -1,787 +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 java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.TimeUnit; - -import org.eclipse.jetty.toolchain.test.AdvancedRunner; -import org.eclipse.jetty.toolchain.test.annotation.Stress; -import org.eclipse.jetty.util.StringUtil; -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.BinaryFrame; -import org.eclipse.jetty.websocket.common.frames.ContinuationFrame; -import org.eclipse.jetty.websocket.common.frames.DataFrame; -import org.eclipse.jetty.websocket.common.frames.TextFrame; -import org.eclipse.jetty.websocket.tests.Fuzzer; -import org.junit.Test; -import org.junit.runner.RunWith; - -/** - * Big frame/message tests - */ -@RunWith(AdvancedRunner.class) -public class TestABCase9 extends AbstractABCase -{ - private static final int KBYTE = 1024; - private static final int MBYTE = KBYTE * KBYTE; - - private DataFrame toDataFrame(byte op) - { - switch (op) - { - case OpCode.BINARY: - return new BinaryFrame(); - case OpCode.TEXT: - return new TextFrame(); - case OpCode.CONTINUATION: - return new ContinuationFrame(); - default: - throw new IllegalArgumentException("Not a data frame: " + op); - } - } - - private void assertMultiFrameEcho(byte opcode, int overallMsgSize, int fragmentSize) throws Exception - { - byte msg[] = new byte[overallMsgSize]; - Arrays.fill(msg,(byte)'M'); - - List send = new ArrayList<>(); - byte frag[]; - int remaining = msg.length; - int offset = 0; - boolean fin; - ByteBuffer buf; - ; - byte op = opcode; - while (remaining > 0) - { - int len = Math.min(remaining,fragmentSize); - frag = new byte[len]; - System.arraycopy(msg,offset,frag,0,len); - remaining -= len; - fin = (remaining <= 0); - buf = ByteBuffer.wrap(frag); - - send.add(toDataFrame(op).setPayload(buf).setFin(fin)); - - offset += len; - op = OpCode.CONTINUATION; - } - send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - - List expect = new ArrayList<>(); - expect.add(toDataFrame(opcode).setPayload(copyOf(msg))); - expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - - try(Fuzzer.Session session = fuzzer.connect(this)) - { - session.bulkMode(); - session.send(send); - session.expect(expect, 32, TimeUnit.SECONDS); - } - } - - private void assertSlowFrameEcho(byte opcode, int overallMsgSize, int segmentSize) throws Exception - { - byte msg[] = new byte[overallMsgSize]; - Arrays.fill(msg,(byte)'M'); - ByteBuffer buf = ByteBuffer.wrap(msg); - - List send = new ArrayList<>(); - send.add(toDataFrame(opcode).setPayload(buf)); - send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - - List expect = new ArrayList<>(); - expect.add(toDataFrame(opcode).setPayload(clone(buf))); - expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - - try(Fuzzer.Session session = fuzzer.connect(this)) - { - session.slowMode(segmentSize); - session.send(send); - session.expect(expect, 32, TimeUnit.SECONDS); - } - } - - /** - * Echo 64KB text message (1 frame) - * @throws Exception on test failure - */ - @Test - public void testCase9_1_1() throws Exception - { - byte utf[] = new byte[64 * KBYTE]; - Arrays.fill(utf,(byte)'y'); - String msg = StringUtil.toUTF8String(utf,0,utf.length); - - List send = new ArrayList<>(); - send.add(new TextFrame().setPayload(msg)); - send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - - List expect = new ArrayList<>(); - expect.add(new TextFrame().setPayload(msg)); - expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - - try(Fuzzer.Session session = fuzzer.connect(this)) - { - session.bulkMode(); - session.send(send); - session.expect(expect); - } - } - - /** - * Echo 256KB text message (1 frame) - * @throws Exception on test failure - */ - @Test - public void testCase9_1_2() throws Exception - { - byte utf[] = new byte[256 * KBYTE]; - Arrays.fill(utf,(byte)'y'); - ByteBuffer buf = ByteBuffer.wrap(utf); - - List send = new ArrayList<>(); - send.add(new TextFrame().setPayload(buf)); - send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - - List expect = new ArrayList<>(); - expect.add(new TextFrame().setPayload(clone(buf))); - expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - - try(Fuzzer.Session session = fuzzer.connect(this)) - { - session.bulkMode(); - session.send(send); - session.expect(expect); - } - } - - /** - * Echo 1MB text message (1 frame) - * @throws Exception on test failure - */ - @Test - public void testCase9_1_3() throws Exception - { - byte utf[] = new byte[1 * MBYTE]; - Arrays.fill(utf,(byte)'y'); - ByteBuffer buf = ByteBuffer.wrap(utf); - - List send = new ArrayList<>(); - send.add(new TextFrame().setPayload(buf)); - send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - - List expect = new ArrayList<>(); - expect.add(new TextFrame().setPayload(clone(buf))); - expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - - try(Fuzzer.Session session = fuzzer.connect(this)) - { - session.bulkMode(); - session.send(send); - session.expect(expect); - } - } - - /** - * Echo 4MB text message (1 frame) - * @throws Exception on test failure - */ - @Test - public void testCase9_1_4() throws Exception - { - byte utf[] = new byte[4 * MBYTE]; - Arrays.fill(utf,(byte)'y'); - ByteBuffer buf = ByteBuffer.wrap(utf); - - List send = new ArrayList<>(); - send.add(new TextFrame().setPayload(buf)); - send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - - List expect = new ArrayList<>(); - expect.add(new TextFrame().setPayload(clone(buf))); - expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - - try(Fuzzer.Session session = fuzzer.connect(this)) - { - session.bulkMode(); - session.send(send); - session.expect(expect); - } - } - - /** - * Echo 8MB text message (1 frame) - * @throws Exception on test failure - */ - @Test - @Stress("High I/O use") - public void testCase9_1_5() throws Exception - { - byte utf[] = new byte[8 * MBYTE]; - Arrays.fill(utf,(byte)'y'); - ByteBuffer buf = ByteBuffer.wrap(utf); - - List send = new ArrayList<>(); - send.add(new TextFrame().setPayload(buf)); - send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - - List expect = new ArrayList<>(); - expect.add(new TextFrame().setPayload(clone(buf))); - expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - - try(Fuzzer.Session session = fuzzer.connect(this)) - { - session.bulkMode(); - session.send(send); - session.expect(expect, 16, TimeUnit.SECONDS); - } - } - - /** - * Echo 16MB text message (1 frame) - * @throws Exception on test failure - */ - @Test - @Stress("High I/O use") - public void testCase9_1_6() throws Exception - { - byte utf[] = new byte[16 * MBYTE]; - Arrays.fill(utf,(byte)'y'); - ByteBuffer buf = ByteBuffer.wrap(utf); - - List send = new ArrayList<>(); - send.add(new TextFrame().setPayload(buf)); - send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - - List expect = new ArrayList<>(); - expect.add(new TextFrame().setPayload(clone(buf))); - expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - - try(Fuzzer.Session session = fuzzer.connect(this)) - { - session.bulkMode(); - session.send(send); - session.expect(expect, 32, TimeUnit.SECONDS); - } - } - - /** - * Echo 64KB binary message (1 frame) - * @throws Exception on test failure - */ - @Test - public void testCase9_2_1() throws Exception - { - byte data[] = new byte[64 * KBYTE]; - Arrays.fill(data,(byte)0x21); - - List send = new ArrayList<>(); - send.add(new BinaryFrame().setPayload(data)); - send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - - List expect = new ArrayList<>(); - expect.add(new BinaryFrame().setPayload(copyOf(data))); - expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - - try(Fuzzer.Session session = fuzzer.connect(this)) - { - session.bulkMode(); - session.send(send); - session.expect(expect); - } - } - - /** - * Echo 256KB binary message (1 frame) - * @throws Exception on test failure - */ - @Test - public void testCase9_2_2() throws Exception - { - byte data[] = new byte[256 * KBYTE]; - Arrays.fill(data,(byte)0x22); - ByteBuffer buf = ByteBuffer.wrap(data); - - List send = new ArrayList<>(); - send.add(new BinaryFrame().setPayload(buf)); - send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - - List expect = new ArrayList<>(); - expect.add(new BinaryFrame().setPayload(clone(buf))); - expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - - try(Fuzzer.Session session = fuzzer.connect(this)) - { - session.bulkMode(); - session.send(send); - session.expect(expect); - } - } - - /** - * Echo 1MB binary message (1 frame) - * @throws Exception on test failure - */ - @Test - @Stress("High I/O use") - public void testCase9_2_3() throws Exception - { - byte data[] = new byte[1 * MBYTE]; - Arrays.fill(data,(byte)0x23); - ByteBuffer buf = ByteBuffer.wrap(data); - - List send = new ArrayList<>(); - send.add(new BinaryFrame().setPayload(buf)); - send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - - List expect = new ArrayList<>(); - expect.add(new BinaryFrame().setPayload(clone(buf))); - expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - - try(Fuzzer.Session session = fuzzer.connect(this)) - { - session.bulkMode(); - session.send(send); - session.expect(expect); - } - } - - /** - * Echo 4MB binary message (1 frame) - * @throws Exception on test failure - */ - @Test - @Stress("High I/O use") - public void testCase9_2_4() throws Exception - { - byte data[] = new byte[4 * MBYTE]; - Arrays.fill(data,(byte)0x24); - ByteBuffer buf = ByteBuffer.wrap(data); - - List send = new ArrayList<>(); - send.add(new BinaryFrame().setPayload(buf)); - send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - - List expect = new ArrayList<>(); - expect.add(new BinaryFrame().setPayload(clone(buf))); - expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - - try(Fuzzer.Session session = fuzzer.connect(this)) - { - session.bulkMode(); - session.send(send); - session.expect(expect); - } - } - - /** - * Echo 8MB binary message (1 frame) - * @throws Exception on test failure - */ - @Test - @Stress("High I/O use") - public void testCase9_2_5() throws Exception - { - byte data[] = new byte[8 * MBYTE]; - Arrays.fill(data,(byte)0x25); - ByteBuffer buf = ByteBuffer.wrap(data); - - List send = new ArrayList<>(); - send.add(new BinaryFrame().setPayload(buf)); - send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - - List expect = new ArrayList<>(); - expect.add(new BinaryFrame().setPayload(clone(buf))); - expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - - try(Fuzzer.Session session = fuzzer.connect(this)) - { - session.bulkMode(); - session.send(send); - session.expect(expect,16,TimeUnit.SECONDS); - } - } - - /** - * Echo 16MB binary message (1 frame) - * @throws Exception on test failure - */ - @Test - @Stress("High I/O use") - public void testCase9_2_6() throws Exception - { - byte data[] = new byte[16 * MBYTE]; - Arrays.fill(data,(byte)0x26); - ByteBuffer buf = ByteBuffer.wrap(data); - - List send = new ArrayList<>(); - send.add(new BinaryFrame().setPayload(buf)); - send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - - List expect = new ArrayList<>(); - expect.add(new BinaryFrame().setPayload(clone(buf))); - expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - - try(Fuzzer.Session session = fuzzer.connect(this)) - { - session.bulkMode(); - session.send(send); - session.expect(expect,32,TimeUnit.SECONDS); - } - } - - /** - * Send 4MB text message in multiple frames. - * @throws Exception on test failure - */ - @Test - @Stress("High I/O use") - public void testCase9_3_1() throws Exception - { - assertMultiFrameEcho(OpCode.TEXT,4 * MBYTE,64); - } - - /** - * Send 4MB text message in multiple frames. - * @throws Exception on test failure - */ - @Test - @Stress("High I/O use") - public void testCase9_3_2() throws Exception - { - assertMultiFrameEcho(OpCode.TEXT,4 * MBYTE,256); - } - - /** - * Send 4MB text message in multiple frames. - * @throws Exception on test failure - */ - @Test - @Stress("High I/O use") - public void testCase9_3_3() throws Exception - { - assertMultiFrameEcho(OpCode.TEXT,4 * MBYTE,1 * KBYTE); - } - - /** - * Send 4MB text message in multiple frames. - * @throws Exception on test failure - */ - @Test - @Stress("High I/O use") - public void testCase9_3_4() throws Exception - { - assertMultiFrameEcho(OpCode.TEXT,4 * MBYTE,4 * KBYTE); - } - - /** - * Send 4MB text message in multiple frames. - * @throws Exception on test failure - */ - @Test - @Stress("High I/O use") - public void testCase9_3_5() throws Exception - { - assertMultiFrameEcho(OpCode.TEXT,4 * MBYTE,16 * KBYTE); - } - - /** - * Send 4MB text message in multiple frames. - * @throws Exception on test failure - */ - @Test - @Stress("High I/O use") - public void testCase9_3_6() throws Exception - { - assertMultiFrameEcho(OpCode.TEXT,4 * MBYTE,64 * KBYTE); - } - - /** - * Send 4MB text message in multiple frames. - * @throws Exception on test failure - */ - @Test - @Stress("High I/O use") - public void testCase9_3_7() throws Exception - { - assertMultiFrameEcho(OpCode.TEXT,4 * MBYTE,256 * KBYTE); - } - - /** - * Send 4MB text message in multiple frames. - * @throws Exception on test failure - */ - @Test - @Stress("High I/O use") - public void testCase9_3_8() throws Exception - { - assertMultiFrameEcho(OpCode.TEXT,4 * MBYTE,1 * MBYTE); - } - - /** - * Send 4MB text message in multiple frames. - * @throws Exception on test failure - */ - @Test - @Stress("High I/O use") - public void testCase9_3_9() throws Exception - { - assertMultiFrameEcho(OpCode.TEXT,4 * MBYTE,4 * MBYTE); - } - - /** - * Send 4MB binary message in multiple frames. - * @throws Exception on test failure - */ - @Test - @Stress("High I/O use") - public void testCase9_4_1() throws Exception - { - assertMultiFrameEcho(OpCode.BINARY,4 * MBYTE,64); - } - - /** - * Send 4MB binary message in multiple frames. - * @throws Exception on test failure - */ - @Test - @Stress("High I/O use") - public void testCase9_4_2() throws Exception - { - assertMultiFrameEcho(OpCode.BINARY,4 * MBYTE,256); - } - - /** - * Send 4MB binary message in multiple frames. - * @throws Exception on test failure - */ - @Test - @Stress("High I/O use") - public void testCase9_4_3() throws Exception - { - assertMultiFrameEcho(OpCode.BINARY,4 * MBYTE,1 * KBYTE); - } - - /** - * Send 4MB binary message in multiple frames. - * @throws Exception on test failure - */ - @Test - @Stress("High I/O use") - public void testCase9_4_4() throws Exception - { - assertMultiFrameEcho(OpCode.BINARY,4 * MBYTE,4 * KBYTE); - } - - /** - * Send 4MB binary message in multiple frames. - * @throws Exception on test failure - */ - @Test - @Stress("High I/O use") - public void testCase9_4_5() throws Exception - { - assertMultiFrameEcho(OpCode.BINARY,4 * MBYTE,16 * KBYTE); - } - - /** - * Send 4MB binary message in multiple frames. - * @throws Exception on test failure - */ - @Test - @Stress("High I/O use") - public void testCase9_4_6() throws Exception - { - assertMultiFrameEcho(OpCode.BINARY,4 * MBYTE,64 * KBYTE); - } - - /** - * Send 4MB binary message in multiple frames. - * @throws Exception on test failure - */ - @Test - @Stress("High I/O use") - public void testCase9_4_7() throws Exception - { - assertMultiFrameEcho(OpCode.BINARY,4 * MBYTE,256 * KBYTE); - } - - /** - * Send 4MB binary message in multiple frames. - * @throws Exception on test failure - */ - @Test - @Stress("High I/O use") - public void testCase9_4_8() throws Exception - { - assertMultiFrameEcho(OpCode.BINARY,4 * MBYTE,1 * MBYTE); - } - - /** - * Send 4MB binary message in multiple frames. - * @throws Exception on test failure - */ - @Test - @Stress("High I/O use") - public void testCase9_4_9() throws Exception - { - assertMultiFrameEcho(OpCode.BINARY,4 * MBYTE,4 * MBYTE); - } - - /** - * Send 1MB text message in 1 frame, but slowly - * @throws Exception on test failure - */ - @Test - @Stress("High I/O use") - public void testCase9_5_1() throws Exception - { - assertSlowFrameEcho(OpCode.TEXT,1 * MBYTE,64); - } - - /** - * Send 1MB text message in 1 frame, but slowly - * @throws Exception on test failure - */ - @Test - @Stress("High I/O use") - public void testCase9_5_2() throws Exception - { - assertSlowFrameEcho(OpCode.TEXT,1 * MBYTE,128); - } - - /** - * Send 1MB text message in 1 frame, but slowly - * @throws Exception on test failure - */ - @Test - @Stress("High I/O use") - public void testCase9_5_3() throws Exception - { - assertSlowFrameEcho(OpCode.TEXT,1 * MBYTE,256); - } - - /** - * Send 1MB text message in 1 frame, but slowly - * @throws Exception on test failure - */ - @Test - @Stress("High I/O use") - public void testCase9_5_4() throws Exception - { - assertSlowFrameEcho(OpCode.TEXT,1 * MBYTE,512); - } - - /** - * Send 1MB text message in 1 frame, but slowly - * @throws Exception on test failure - */ - @Test - @Stress("High I/O use") - public void testCase9_5_5() throws Exception - { - assertSlowFrameEcho(OpCode.TEXT,1 * MBYTE,1024); - } - - /** - * Send 1MB text message in 1 frame, but slowly - * @throws Exception on test failure - */ - @Test - @Stress("High I/O use") - public void testCase9_5_6() throws Exception - { - assertSlowFrameEcho(OpCode.TEXT,1 * MBYTE,2048); - } - - /** - * Send 1MB binary message in 1 frame, but slowly - * @throws Exception on test failure - */ - @Test - @Stress("High I/O use") - public void testCase9_6_1() throws Exception - { - assertSlowFrameEcho(OpCode.BINARY,1 * MBYTE,64); - } - - /** - * Send 1MB binary message in 1 frame, but slowly - * @throws Exception on test failure - */ - @Test - @Stress("High I/O use") - public void testCase9_6_2() throws Exception - { - assertSlowFrameEcho(OpCode.BINARY,1 * MBYTE,128); - } - - /** - * Send 1MB binary message in 1 frame, but slowly - * @throws Exception on test failure - */ - @Test - @Stress("High I/O use") - public void testCase9_6_3() throws Exception - { - assertSlowFrameEcho(OpCode.BINARY,1 * MBYTE,256); - } - - /** - * Send 1MB binary message in 1 frame, but slowly - * @throws Exception on test failure - */ - @Test - @Stress("High I/O use") - public void testCase9_6_4() throws Exception - { - assertSlowFrameEcho(OpCode.BINARY,1 * MBYTE,512); - } - - /** - * Send 1MB binary message in 1 frame, but slowly - * @throws Exception on test failure - */ - @Test - @Stress("High I/O use") - public void testCase9_6_5() throws Exception - { - assertSlowFrameEcho(OpCode.BINARY,1 * MBYTE,1024); - } - - /** - * Send 1MB binary message in 1 frame, but slowly - * @throws Exception on test failure - */ - @Test - @Stress("High I/O use") - public void testCase9_6_6() throws Exception - { - assertSlowFrameEcho(OpCode.BINARY,1 * MBYTE,2048); - } -} diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/TextUTF8Test.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/TextTest.java similarity index 50% rename from jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/TextUTF8Test.java rename to jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/TextTest.java index 1c2e61882c0..b7c8b98fa1c 100644 --- a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/TextUTF8Test.java +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/TextTest.java @@ -20,6 +20,7 @@ package org.eclipse.jetty.websocket.tests.server; import java.nio.ByteBuffer; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.concurrent.TimeUnit; @@ -30,69 +31,44 @@ import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.log.StacklessLogging; 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.Parser; import org.eclipse.jetty.websocket.common.WebSocketFrame; import org.eclipse.jetty.websocket.common.frames.ContinuationFrame; import org.eclipse.jetty.websocket.common.frames.DataFrame; import org.eclipse.jetty.websocket.common.frames.TextFrame; +import org.eclipse.jetty.websocket.tests.DataUtils; +import org.eclipse.jetty.websocket.tests.LocalFuzzer; import org.junit.Test; /** * UTF-8 Tests */ -public class TextUTF8Test extends AbstractLocalServerCase +public class TextTest extends AbstractLocalServerCase { /** - * Split a message byte array into a series of fragments (frames + continuations) of 1 byte message contents each. - * - * @param frames the frames - * @param msg the message - */ - private void fragmentText(List frames, byte msg[]) - { - int len = msg.length; - boolean continuation = false; - byte mini[]; - for (int i = 0; i < len; i++) - { - DataFrame frame; - if (continuation) - { - frame = new ContinuationFrame(); - } - else - { - frame = new TextFrame(); - } - mini = new byte[1]; - mini[0] = msg[i]; - frame.setPayload(ByteBuffer.wrap(mini)); - boolean isLast = (i >= (len - 1)); - frame.setFin(isLast); - frames.add(frame); - continuation = true; - } - } - - /** - * text message, 1 frame, 0 length + * Echo 16MB text message (1 frame) *

- * From Autobahn WebSocket Server Testcase 6.1.1 + * From Autobahn WebSocket Server Testcase 9.1.6 *

* @throws Exception on test failure */ @Test - public void testText_Empty() throws Exception + public void testText_16mb_SingleFrame() throws Exception { + byte utf[] = new byte[16 * MBYTE]; + Arrays.fill(utf,(byte)'y'); + ByteBuffer buf = ByteBuffer.wrap(utf); + List send = new ArrayList<>(); - send.add(new TextFrame()); + send.add(new TextFrame().setPayload(buf)); send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); List expect = new ArrayList<>(); - expect.add(new TextFrame()); + expect.add(new TextFrame().setPayload(DataUtils.copyOf(buf))); expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - - try (LocalFuzzer session = newLocalFuzzer()) + + try(LocalFuzzer session = server.newLocalFuzzer()) { session.sendBulk(send); session.expect(expect); @@ -100,26 +76,29 @@ public class TextUTF8Test extends AbstractLocalServerCase } /** - * text message, 0 length, 3 fragments + * Echo 1MB text message (1 frame) *

- * From Autobahn WebSocket Server Testcase 6.1.2 + * From Autobahn WebSocket Server Testcase 9.1.3 *

* @throws Exception on test failure */ @Test - public void testText_Continuation_Continuation_AllEmpty() throws Exception + public void testText_1mb_SingleFrame() throws Exception { + //noinspection PointlessArithmeticExpression + byte utf[] = new byte[1 * MBYTE]; + Arrays.fill(utf,(byte)'y'); + ByteBuffer buf = ByteBuffer.wrap(utf); + List send = new ArrayList<>(); - send.add(new TextFrame().setFin(false)); - send.add(new ContinuationFrame().setFin(false)); - send.add(new ContinuationFrame().setFin(true)); + send.add(new TextFrame().setPayload(buf)); send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); List expect = new ArrayList<>(); - expect.add(new TextFrame()); + expect.add(new TextFrame().setPayload(DataUtils.copyOf(buf))); expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - - try (LocalFuzzer session = newLocalFuzzer()) + + try(LocalFuzzer session = server.newLocalFuzzer()) { session.sendBulk(send); session.expect(expect); @@ -127,26 +106,28 @@ public class TextUTF8Test extends AbstractLocalServerCase } /** - * text message, small length, 3 fragments (only middle frame has payload) + * Echo 256KB text message (1 frame) *

- * From Autobahn WebSocket Server Testcase 6.1.3 + * From Autobahn WebSocket Server Testcase 9.1.2 *

* @throws Exception on test failure */ @Test - public void testText_ContinuationWithPayload_Continuation() throws Exception + public void testText_256k_SingleFrame() throws Exception { + byte utf[] = new byte[256 * KBYTE]; + Arrays.fill(utf,(byte)'y'); + ByteBuffer buf = ByteBuffer.wrap(utf); + List send = new ArrayList<>(); - send.add(new TextFrame().setFin(false)); - send.add(new ContinuationFrame().setPayload("middle").setFin(false)); - send.add(new ContinuationFrame().setFin(true)); + send.add(new TextFrame().setPayload(buf)); send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); List expect = new ArrayList<>(); - expect.add(new TextFrame().setPayload("middle")); + expect.add(new TextFrame().setPayload(DataUtils.copyOf(buf))); expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - - try (LocalFuzzer session = newLocalFuzzer()) + + try(LocalFuzzer session = server.newLocalFuzzer()) { session.sendBulk(send); session.expect(expect); @@ -154,35 +135,24 @@ public class TextUTF8Test extends AbstractLocalServerCase } /** - * valid utf8 text message, 2 fragments (on UTF8 code point boundary) + * Send 4MB text message in multiple frames. *

- * From Autobahn WebSocket Server Testcase 6.2.2 + * From Autobahn WebSocket Server Testcase 9.3.5 *

* @throws Exception on test failure */ @Test - public void testText_SplitOnCodePointBoundary() throws Exception + public void testText_4mb_Frames_16kb() throws Exception { - String utf1 = "Hello-\uC2B5@\uC39F\uC3A4"; - String utf2 = "\uC3BC\uC3A0\uC3A1-UTF-8!!"; - - ByteBuffer b1 = ByteBuffer.wrap(StringUtil.getUtf8Bytes(utf1)); - ByteBuffer b2 = ByteBuffer.wrap(StringUtil.getUtf8Bytes(utf2)); - List send = new ArrayList<>(); - send.add(new TextFrame().setPayload(b1).setFin(false)); - send.add(new ContinuationFrame().setPayload(b2).setFin(true)); + ByteBuffer payload = newMultiFrameMessage(send, OpCode.TEXT, 4 * MBYTE, 16 * KBYTE); send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - + List expect = new ArrayList<>(); - ByteBuffer e1 = ByteBuffer.allocate(100); - e1.put(StringUtil.getUtf8Bytes(utf1)); - e1.put(StringUtil.getUtf8Bytes(utf2)); - e1.flip(); - expect.add(new TextFrame().setPayload(e1)); + expect.add(new TextFrame().setPayload(payload)); expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - - try (LocalFuzzer session = newLocalFuzzer()) + + try(LocalFuzzer session = server.newLocalFuzzer()) { session.sendBulk(send); session.expect(expect); @@ -190,27 +160,24 @@ public class TextUTF8Test extends AbstractLocalServerCase } /** - * valid utf8 text message, many fragments (1 byte each) + * Send 4MB text message in multiple frames. *

- * From Autobahn WebSocket Server Testcase 6.2.3 + * From Autobahn WebSocket Server Testcase 9.3.3 *

* @throws Exception on test failure */ @Test - public void testText_ManyContinuationsNotOnCodePoints_Hello() throws Exception + public void testText_4mb_Frames_1kb() throws Exception { - String utf8 = "Hello-\uC2B5@\uC39F\uC3A4\uC3BC\uC3A0\uC3A1-UTF-8!!"; - byte msg[] = StringUtil.getUtf8Bytes(utf8); - List send = new ArrayList<>(); - fragmentText(send, msg); + ByteBuffer payload = newMultiFrameMessage(send, OpCode.TEXT, 4 * MBYTE, 1 * KBYTE); send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - + List expect = new ArrayList<>(); - expect.add(new TextFrame().setPayload(ByteBuffer.wrap(msg))); + expect.add(new TextFrame().setPayload(payload)); expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - - try (LocalFuzzer session = newLocalFuzzer()) + + try(LocalFuzzer session = server.newLocalFuzzer()) { session.sendBulk(send); session.expect(expect); @@ -218,26 +185,261 @@ public class TextUTF8Test extends AbstractLocalServerCase } /** - * valid utf8 text message, many fragments (1 byte each) + * Send 4MB text message in multiple frames. *

- * From Autobahn WebSocket Server Testcase 6.2.4 + * From Autobahn WebSocket Server Testcase 9.3.8 *

* @throws Exception on test failure */ @Test - public void testText_ManyContinuationsNotOnCodePoints() throws Exception + public void testText_4mb_Frames_1mb() throws Exception { - byte msg[] = Hex.asByteArray("CEBAE1BDB9CF83CEBCCEB5"); + List send = new ArrayList<>(); + ByteBuffer payload = newMultiFrameMessage(send, OpCode.TEXT, 4 * MBYTE, 1 * MBYTE); + send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + List expect = new ArrayList<>(); + expect.add(new TextFrame().setPayload(payload)); + expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + try(LocalFuzzer session = server.newLocalFuzzer()) + { + session.sendBulk(send); + session.expect(expect); + } + } + + /** + * Send 4MB text message in multiple frames. + *

+ * From Autobahn WebSocket Server Testcase 9.3.2 + *

+ * @throws Exception on test failure + */ + @Test + public void testText_4mb_Frames_256b() throws Exception + { + List send = new ArrayList<>(); + ByteBuffer payload = newMultiFrameMessage(send, OpCode.TEXT, 4 * MBYTE, 256); + send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + List expect = new ArrayList<>(); + expect.add(new TextFrame().setPayload(payload)); + expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + try(LocalFuzzer session = server.newLocalFuzzer()) + { + session.sendBulk(send); + session.expect(expect); + } + } + + /** + * Send 4MB text message in multiple frames. + *

+ * From Autobahn WebSocket Server Testcase 9.3.7 + *

+ * @throws Exception on test failure + */ + @Test + public void testText_4mb_Frames_256kb() throws Exception + { + List send = new ArrayList<>(); + ByteBuffer payload = newMultiFrameMessage(send, OpCode.TEXT, 4 * MBYTE, 256 * KBYTE); + send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + List expect = new ArrayList<>(); + expect.add(new TextFrame().setPayload(payload)); + expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + try(LocalFuzzer session = server.newLocalFuzzer()) + { + session.sendBulk(send); + session.expect(expect); + } + } + + /** + * Send 4MB text message in multiple frames. + *

+ * From Autobahn WebSocket Server Testcase 9.3.4 + *

+ * @throws Exception on test failure + */ + @Test + public void testText_4mb_Frames_4kb() throws Exception + { + List send = new ArrayList<>(); + ByteBuffer payload = newMultiFrameMessage(send, OpCode.TEXT, 4 * MBYTE, 4 * KBYTE); + send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + List expect = new ArrayList<>(); + expect.add(new TextFrame().setPayload(payload)); + expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + try(LocalFuzzer session = server.newLocalFuzzer()) + { + session.sendBulk(send); + session.expect(expect); + } + } + + /** + * Send 4MB text message in multiple frames. + *

+ * From Autobahn WebSocket Server Testcase 9.3.9 + *

+ * @throws Exception on test failure + */ + @Test + public void testText_4mb_Frames_4mb() throws Exception + { + List send = new ArrayList<>(); + ByteBuffer payload = newMultiFrameMessage(send, OpCode.TEXT, 4 * MBYTE, 4 * MBYTE); + send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + List expect = new ArrayList<>(); + expect.add(new TextFrame().setPayload(payload)); + expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + try(LocalFuzzer session = server.newLocalFuzzer()) + { + session.sendBulk(send); + session.expect(expect); + } + } + + /** + * Send 4MB text message in multiple frames. + *

+ * From Autobahn WebSocket Server Testcase 9.3.1 + *

+ * @throws Exception on test failure + */ + @Test + public void testText_4mb_Frames_64b() throws Exception + { + List send = new ArrayList<>(); + ByteBuffer payload = newMultiFrameMessage(send, OpCode.TEXT, 4*MBYTE, 64); + send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + List expect = new ArrayList<>(); + expect.add(new TextFrame().setPayload(payload)); + expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + try(LocalFuzzer session = server.newLocalFuzzer()) + { + session.sendBulk(send); + session.expect(expect); + } + } + + /** + * Send 4MB text message in multiple frames. + *

+ * From Autobahn WebSocket Server Testcase 9.3.6 + *

+ * @throws Exception on test failure + */ + @Test + public void testText_4mb_Frames_64kb() throws Exception + { + List send = new ArrayList<>(); + ByteBuffer payload = newMultiFrameMessage(send, OpCode.TEXT, 4 * MBYTE, 64 * KBYTE); + send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + List expect = new ArrayList<>(); + expect.add(new TextFrame().setPayload(payload)); + expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + try(LocalFuzzer session = server.newLocalFuzzer()) + { + session.sendBulk(send); + session.expect(expect); + } + } + + /** + * Echo 4MB text message (1 frame) + *

+ * From Autobahn WebSocket Server Testcase 9.1.4 + *

+ * @throws Exception on test failure + */ + @Test + public void testText_4mb_SingleFrame() throws Exception + { + byte utf[] = new byte[4 * MBYTE]; + Arrays.fill(utf,(byte)'y'); + ByteBuffer buf = ByteBuffer.wrap(utf); List send = new ArrayList<>(); - fragmentText(send, msg); + send.add(new TextFrame().setPayload(buf)); send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); List expect = new ArrayList<>(); - expect.add(new TextFrame().setPayload(ByteBuffer.wrap(msg))); + expect.add(new TextFrame().setPayload(DataUtils.copyOf(buf))); expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + try(LocalFuzzer session = server.newLocalFuzzer()) + { + session.sendBulk(send); + session.expect(expect); + } + } + + /** + * Echo 64KB text message (1 frame) + *

+ * From Autobahn WebSocket Server Testcase 9.1.1 + *

+ * @throws Exception on test failure + */ + @Test + public void testText_64k_SingleFrame() throws Exception + { + byte utf[] = new byte[64 * KBYTE]; + Arrays.fill(utf,(byte)'y'); + String msg = StringUtil.toUTF8String(utf,0,utf.length); - try (LocalFuzzer session = newLocalFuzzer()) + List send = new ArrayList<>(); + send.add(new TextFrame().setPayload(msg)); + send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + List expect = new ArrayList<>(); + expect.add(new TextFrame().setPayload(msg)); + expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + try(LocalFuzzer session = server.newLocalFuzzer()) + { + session.sendBulk(send); + session.expect(expect); + } + } + + /** + * Echo 8MB text message (1 frame) + *

+ * From Autobahn WebSocket Server Testcase 9.1.5 + *

+ * @throws Exception on test failure + */ + @Test + public void testText_8mb_SingleFrame() throws Exception + { + byte utf[] = new byte[8 * MBYTE]; + Arrays.fill(utf,(byte)'y'); + ByteBuffer buf = ByteBuffer.wrap(utf); + + List send = new ArrayList<>(); + send.add(new TextFrame().setPayload(buf)); + send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + List expect = new ArrayList<>(); + expect.add(new TextFrame().setPayload(DataUtils.copyOf(buf))); + expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + try(LocalFuzzer session = server.newLocalFuzzer()) { session.sendBulk(send); session.expect(expect); @@ -262,14 +464,68 @@ public class TextUTF8Test extends AbstractLocalServerCase List expect = new ArrayList<>(); expect.add(new CloseInfo(StatusCode.BAD_PAYLOAD).asFrame()); - - try (LocalFuzzer session = newLocalFuzzer()) + + try (LocalFuzzer session = server.newLocalFuzzer()) { session.sendBulk(send); session.expect(expect); } } + /** + * invalid text message, 1 frame/fragment (slowly, and split within code points) + *

+ * From Autobahn WebSocket Server Testcase 6.4.3 + *

+ * @throws Exception on test failure + */ + @Test + public void testText_BadUtf8_ByteWise() throws Exception + { + // Disable Long Stacks from Parser (we know this test will throw an exception) + try (StacklessLogging ignored = new StacklessLogging(Parser.class)) + { + ByteBuffer payload = ByteBuffer.allocate(64); + BufferUtil.clearToFill(payload); + payload.put(TypeUtil.fromHexString("cebae1bdb9cf83cebcceb5")); // good + payload.put(TypeUtil.fromHexString("f4908080")); // INVALID + payload.put(TypeUtil.fromHexString("656469746564")); // good + BufferUtil.flipToFlush(payload, 0); + + List send = new ArrayList<>(); + send.add(new TextFrame().setPayload(payload)); + send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + List expect = new ArrayList<>(); + expect.add(new CloseInfo(StatusCode.BAD_PAYLOAD).asFrame()); + + try (LocalFuzzer session = server.newLocalFuzzer()) + { + ByteBuffer net = session.asNetworkBuffer(send); + + int splits[] = {17, 21, net.limit()}; + + ByteBuffer part1 = net.slice(); // Header + good UTF + part1.limit(splits[0]); + ByteBuffer part2 = net.slice(); // invalid UTF + part2.position(splits[0]); + part2.limit(splits[1]); + ByteBuffer part3 = net.slice(); // good UTF + part3.position(splits[1]); + part3.limit(splits[2]); + + session.send(part1); // the header + good utf + TimeUnit.MILLISECONDS.sleep(500); + session.send(part2); // the bad UTF + TimeUnit.MILLISECONDS.sleep(500); + session.send(part3); // the rest (shouldn't work) + session.eof(); + + session.expect(expect); + } + } + } + /** * invalid text message, 3 fragments. *

@@ -297,8 +553,8 @@ public class TextUTF8Test extends AbstractLocalServerCase List expect = new ArrayList<>(); expect.add(new CloseInfo(StatusCode.BAD_PAYLOAD).asFrame()); - - try (LocalFuzzer session = newLocalFuzzer()) + + try (LocalFuzzer session = server.newLocalFuzzer()) { session.sendFrames(send); session.expect(expect); @@ -335,68 +591,14 @@ public class TextUTF8Test extends AbstractLocalServerCase List expect = new ArrayList<>(); expect.add(new CloseInfo(StatusCode.BAD_PAYLOAD).asFrame()); - - try (LocalFuzzer session = newLocalFuzzer()) + + try (LocalFuzzer session = server.newLocalFuzzer()) { session.sendFrames(send); session.expect(expect); } } - /** - * invalid text message, 1 frame/fragment (slowly, and split within code points) - *

- * From Autobahn WebSocket Server Testcase 6.4.3 - *

- * @throws Exception on test failure - */ - @Test - public void testText_BadUtf8_ByteWise() throws Exception - { - // Disable Long Stacks from Parser (we know this test will throw an exception) - try (StacklessLogging ignored = new StacklessLogging(Parser.class)) - { - ByteBuffer payload = ByteBuffer.allocate(64); - BufferUtil.clearToFill(payload); - payload.put(TypeUtil.fromHexString("cebae1bdb9cf83cebcceb5")); // good - payload.put(TypeUtil.fromHexString("f4908080")); // INVALID - payload.put(TypeUtil.fromHexString("656469746564")); // good - BufferUtil.flipToFlush(payload, 0); - - List send = new ArrayList<>(); - send.add(new TextFrame().setPayload(payload)); - send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - - List expect = new ArrayList<>(); - expect.add(new CloseInfo(StatusCode.BAD_PAYLOAD).asFrame()); - - try (LocalFuzzer session = newLocalFuzzer()) - { - ByteBuffer net = session.asNetworkBuffer(send); - - int splits[] = {17, 21, net.limit()}; - - ByteBuffer part1 = net.slice(); // Header + good UTF - part1.limit(splits[0]); - ByteBuffer part2 = net.slice(); // invalid UTF - part2.position(splits[0]); - part2.limit(splits[1]); - ByteBuffer part3 = net.slice(); // good UTF - part3.position(splits[1]); - part3.limit(splits[2]); - - session.send(part1); // the header + good utf - TimeUnit.MILLISECONDS.sleep(500); - session.send(part2); // the bad UTF - TimeUnit.MILLISECONDS.sleep(500); - session.send(part3); // the rest (shouldn't work) - session.eof(); - - session.expect(expect); - } - } - } - /** * invalid text message, 1 frame/fragment (slowly, and split within code points) *

@@ -415,9 +617,9 @@ public class TextUTF8Test extends AbstractLocalServerCase List expect = new ArrayList<>(); expect.add(new CloseInfo(StatusCode.BAD_PAYLOAD).asFrame()); - + try (StacklessLogging ignored = new StacklessLogging(Parser.class); - LocalFuzzer session = newLocalFuzzer()) + LocalFuzzer session = server.newLocalFuzzer()) { ByteBuffer net = session.asNetworkBuffer(send); session.send(net, 6); @@ -428,4 +630,206 @@ public class TextUTF8Test extends AbstractLocalServerCase session.expect(expect); } } + + /** + * text message, small length, 3 fragments (only middle frame has payload) + *

+ * From Autobahn WebSocket Server Testcase 6.1.3 + *

+ * @throws Exception on test failure + */ + @Test + public void testText_ContinuationWithPayload_Continuation() throws Exception + { + List send = new ArrayList<>(); + send.add(new TextFrame().setFin(false)); + send.add(new ContinuationFrame().setPayload("middle").setFin(false)); + send.add(new ContinuationFrame().setFin(true)); + send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + List expect = new ArrayList<>(); + expect.add(new TextFrame().setPayload("middle")); + expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + try (LocalFuzzer session = server.newLocalFuzzer()) + { + session.sendBulk(send); + session.expect(expect); + } + } + + /** + * text message, 0 length, 3 fragments + *

+ * From Autobahn WebSocket Server Testcase 6.1.2 + *

+ * @throws Exception on test failure + */ + @Test + public void testText_Continuation_Continuation_AllEmpty() throws Exception + { + List send = new ArrayList<>(); + send.add(new TextFrame().setFin(false)); + send.add(new ContinuationFrame().setFin(false)); + send.add(new ContinuationFrame().setFin(true)); + send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + List expect = new ArrayList<>(); + expect.add(new TextFrame()); + expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + try (LocalFuzzer session = server.newLocalFuzzer()) + { + session.sendBulk(send); + session.expect(expect); + } + } + + /** + * text message, 1 frame, 0 length + *

+ * From Autobahn WebSocket Server Testcase 6.1.1 + *

+ * @throws Exception on test failure + */ + @Test + public void testText_Empty() throws Exception + { + List send = new ArrayList<>(); + send.add(new TextFrame()); + send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + List expect = new ArrayList<>(); + expect.add(new TextFrame()); + expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + try (LocalFuzzer session = server.newLocalFuzzer()) + { + session.sendBulk(send); + session.expect(expect); + } + } + + /** + * valid utf8 text message, many fragments (1 byte each) + *

+ * From Autobahn WebSocket Server Testcase 6.2.4 + *

+ * @throws Exception on test failure + */ + @Test + public void testText_Utf8ContinuationsNotOnCodePoints() throws Exception + { + byte msg[] = Hex.asByteArray("CEBAE1BDB9CF83CEBCCEB5"); + + List send = new ArrayList<>(); + fragmentText(send, msg); + send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + List expect = new ArrayList<>(); + expect.add(new TextFrame().setPayload(ByteBuffer.wrap(msg))); + expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + try (LocalFuzzer session = server.newLocalFuzzer()) + { + session.sendBulk(send); + session.expect(expect); + } + } + + /** + * valid utf8 text message, many fragments (1 byte each) + *

+ * From Autobahn WebSocket Server Testcase 6.2.3 + *

+ * @throws Exception on test failure + */ + @Test + public void testText_Utf8ContinuationsNotOnCodePoints_Hello() throws Exception + { + String utf8 = "Hello-\uC2B5@\uC39F\uC3A4\uC3BC\uC3A0\uC3A1-UTF-8!!"; + byte msg[] = StringUtil.getUtf8Bytes(utf8); + + List send = new ArrayList<>(); + fragmentText(send, msg); + send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + List expect = new ArrayList<>(); + expect.add(new TextFrame().setPayload(ByteBuffer.wrap(msg))); + expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + try (LocalFuzzer session = server.newLocalFuzzer()) + { + session.sendBulk(send); + session.expect(expect); + } + } + + /** + * valid utf8 text message, 2 fragments (on UTF8 code point boundary) + *

+ * From Autobahn WebSocket Server Testcase 6.2.2 + *

+ * @throws Exception on test failure + */ + @Test + public void testText_Utf8SplitOnCodePointBoundary() throws Exception + { + String utf1 = "Hello-\uC2B5@\uC39F\uC3A4"; + String utf2 = "\uC3BC\uC3A0\uC3A1-UTF-8!!"; + + ByteBuffer b1 = ByteBuffer.wrap(StringUtil.getUtf8Bytes(utf1)); + ByteBuffer b2 = ByteBuffer.wrap(StringUtil.getUtf8Bytes(utf2)); + + List send = new ArrayList<>(); + send.add(new TextFrame().setPayload(b1).setFin(false)); + send.add(new ContinuationFrame().setPayload(b2).setFin(true)); + send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + List expect = new ArrayList<>(); + ByteBuffer e1 = ByteBuffer.allocate(100); + e1.put(StringUtil.getUtf8Bytes(utf1)); + e1.put(StringUtil.getUtf8Bytes(utf2)); + e1.flip(); + expect.add(new TextFrame().setPayload(e1)); + expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + try (LocalFuzzer session = server.newLocalFuzzer()) + { + session.sendBulk(send); + session.expect(expect); + } + } + + /** + * Split a message byte array into a series of fragments (frames + continuations) of 1 byte message contents each. + * + * @param frames the frames + * @param msg the message + */ + private void fragmentText(List frames, byte msg[]) + { + int len = msg.length; + boolean continuation = false; + byte mini[]; + for (int i = 0; i < len; i++) + { + DataFrame frame; + if (continuation) + { + frame = new ContinuationFrame(); + } + else + { + frame = new TextFrame(); + } + mini = new byte[1]; + mini[0] = msg[i]; + frame.setPayload(ByteBuffer.wrap(mini)); + boolean isLast = (i >= (len - 1)); + frame.setFin(isLast); + frames.add(frame); + continuation = true; + } + } } diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/TextUTF8_GoodValuesTest.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/Text_GoodUtf8Test.java similarity index 94% rename from jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/TextUTF8_GoodValuesTest.java rename to jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/Text_GoodUtf8Test.java index 1de2614264d..f574687e9e4 100644 --- a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/TextUTF8_GoodValuesTest.java +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/Text_GoodUtf8Test.java @@ -28,6 +28,8 @@ 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.DataUtils; +import org.eclipse.jetty.websocket.tests.LocalFuzzer; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -39,7 +41,7 @@ import org.junit.runners.Parameterized.Parameters; * Should be preserved / echoed back, with normal close code. */ @RunWith(Parameterized.class) -public class TextUTF8_GoodValuesTest extends AbstractLocalServerCase +public class Text_GoodUtf8Test extends AbstractLocalServerCase { @Parameters(name = "{0} - {1}") public static Collection data() @@ -117,7 +119,7 @@ public class TextUTF8_GoodValuesTest extends AbstractLocalServerCase private final ByteBuffer msg; - public TextUTF8_GoodValuesTest(String testId, String hexMsg) + public Text_GoodUtf8Test(String testId, String hexMsg) { LOG.debug("Test ID: {}", testId); this.msg = Hex.asByteBuffer(hexMsg); @@ -131,10 +133,10 @@ public class TextUTF8_GoodValuesTest extends AbstractLocalServerCase send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); List expect = new ArrayList<>(); - expect.add(new TextFrame().setPayload(clone(msg))); + expect.add(new TextFrame().setPayload(DataUtils.copyOf(msg))); expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); - - try (LocalFuzzer session = newLocalFuzzer()) + + try (LocalFuzzer session = server.newLocalFuzzer()) { session.sendBulk(send); session.expect(expect); diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/TextUTF8_InvalidValuesTest.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/Text_InvalidUtf8Test.java similarity index 96% rename from jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/TextUTF8_InvalidValuesTest.java rename to jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/Text_InvalidUtf8Test.java index 07f51648a19..acc9a339598 100644 --- a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/TextUTF8_InvalidValuesTest.java +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/Text_InvalidUtf8Test.java @@ -30,6 +30,7 @@ import org.eclipse.jetty.websocket.common.CloseInfo; import org.eclipse.jetty.websocket.common.Parser; import org.eclipse.jetty.websocket.common.WebSocketFrame; import org.eclipse.jetty.websocket.common.frames.TextFrame; +import org.eclipse.jetty.websocket.tests.LocalFuzzer; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -39,7 +40,7 @@ import org.junit.runners.Parameterized.Parameters; * Tests of Known Bad UTF8 sequences that should trigger a {@link StatusCode#BAD_PAYLOAD} close and early connection termination */ @RunWith(Parameterized.class) -public class TextUTF8_InvalidValuesTest extends AbstractLocalServerCase +public class Text_InvalidUtf8Test extends AbstractLocalServerCase { @Parameters(name = "{0} - {1}") public static Collection data() @@ -142,7 +143,7 @@ public class TextUTF8_InvalidValuesTest extends AbstractLocalServerCase private final byte[] invalid; - public TextUTF8_InvalidValuesTest(String testId, String hexMsg) + public Text_InvalidUtf8Test(String testId, String hexMsg) { LOG.debug("Test ID: {}",testId); this.invalid = Hex.asByteArray(hexMsg); @@ -157,9 +158,9 @@ public class TextUTF8_InvalidValuesTest extends AbstractLocalServerCase List expect = new ArrayList<>(); expect.add(new CloseInfo(StatusCode.BAD_PAYLOAD).asFrame()); - + try (StacklessLogging ignored = new StacklessLogging(Parser.class); - LocalFuzzer session = newLocalFuzzer()) + LocalFuzzer session = server.newLocalFuzzer()) { session.sendBulk(send); session.expect(expect); diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/AltFilterTest.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/AltFilterTest.java similarity index 64% rename from jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/AltFilterTest.java rename to jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/AltFilterTest.java index 090422c4af2..ccfe97e0836 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/AltFilterTest.java +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/AltFilterTest.java @@ -16,24 +16,25 @@ // ======================================================================== // -package org.eclipse.jetty.websocket.jsr356.server; +package org.eclipse.jetty.websocket.tests.server.jsr356; import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.CoreMatchers.nullValue; -import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; -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.servlet.FilterHolder; import org.eclipse.jetty.toolchain.test.TestingDir; import org.eclipse.jetty.webapp.WebAppContext; -import org.eclipse.jetty.websocket.api.Session; -import org.eclipse.jetty.websocket.client.WebSocketClient; -import org.eclipse.jetty.websocket.common.test.LeakTrackingBufferPoolRule; -import org.eclipse.jetty.websocket.jsr356.server.samples.echo.BasicEchoSocket; +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.WSServer; +import org.eclipse.jetty.websocket.tests.server.jsr356.sockets.BasicEchoSocket; import org.junit.Rule; import org.junit.Test; @@ -60,7 +61,6 @@ public class AltFilterTest try { wsb.start(); - URI uri = wsb.getServerBaseURI(); WebAppContext webapp = wsb.createWebAppContext(); wsb.deployWebapp(webapp); @@ -71,24 +71,18 @@ public class AltFilterTest FilterHolder filterSCI = webapp.getServletHandler().getFilter("Jetty_WebSocketUpgradeFilter"); assertThat("Filter[Jetty_WebSocketUpgradeFilter]", filterSCI, nullValue()); - WebSocketClient client = new WebSocketClient(bufferPool); - try + List send = new ArrayList<>(); + send.add(new TextFrame().setPayload("Hello Echo")); + send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + List expect = new ArrayList<>(); + expect.add(new TextFrame().setPayload("Hello Echo")); + expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + try(LocalFuzzer session = wsb.newLocalFuzzer("/app/echo;jsession=xyz")) { - client.start(); - JettyEchoSocket clientSocket = new JettyEchoSocket(); - Future clientConnectFuture = client.connect(clientSocket,uri.resolve("echo")); - // wait for connect - Session clientSession = clientConnectFuture.get(5,TimeUnit.SECONDS); - clientSocket.sendMessage("Hello Echo"); - - String incomingMessage = clientSocket.messageQueue.poll(1, TimeUnit.SECONDS); - assertEquals("Expected message","Hello Echo",incomingMessage); - clientSession.close(); - clientSocket.awaitCloseEvent("Client"); - } - finally - { - client.stop(); + session.sendFrames(send); + session.expect(expect); } } finally diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/AnnotatedServerEndpointTest.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/AnnotatedServerEndpointTest.java similarity index 53% rename from jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/AnnotatedServerEndpointTest.java rename to jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/AnnotatedServerEndpointTest.java index e96a561f669..320fa199476 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/AnnotatedServerEndpointTest.java +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/AnnotatedServerEndpointTest.java @@ -16,27 +16,29 @@ // ======================================================================== // -package org.eclipse.jetty.websocket.jsr356.server; +package org.eclipse.jetty.websocket.tests.server.jsr356; -import static org.hamcrest.Matchers.containsString; - -import java.net.URI; import java.nio.file.Path; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; 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.client.ClientUpgradeRequest; -import org.eclipse.jetty.websocket.client.WebSocketClient; -import org.eclipse.jetty.websocket.common.test.LeakTrackingBufferPoolRule; -import org.eclipse.jetty.websocket.jsr356.server.samples.beans.DateDecoder; -import org.eclipse.jetty.websocket.jsr356.server.samples.beans.TimeEncoder; -import org.eclipse.jetty.websocket.jsr356.server.samples.echo.ConfiguredEchoSocket; -import org.eclipse.jetty.websocket.jsr356.server.samples.echo.EchoSocketConfigurator; +import org.eclipse.jetty.websocket.api.StatusCode; +import org.eclipse.jetty.websocket.api.WebSocketConstants; +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.LeakTrackingBufferPoolRule; +import org.eclipse.jetty.websocket.tests.LocalFuzzer; +import org.eclipse.jetty.websocket.tests.UpgradeUtils; +import org.eclipse.jetty.websocket.tests.WSServer; +import org.eclipse.jetty.websocket.tests.server.jsr356.coders.DateDecoder; +import org.eclipse.jetty.websocket.tests.server.jsr356.coders.TimeEncoder; +import org.eclipse.jetty.websocket.tests.server.jsr356.configs.EchoSocketConfigurator; +import org.eclipse.jetty.websocket.tests.server.jsr356.sockets.ConfiguredEchoSocket; import org.junit.AfterClass; -import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; @@ -48,94 +50,85 @@ public class AnnotatedServerEndpointTest { @Rule public LeakTrackingBufferPoolRule bufferPool = new LeakTrackingBufferPoolRule("Test"); - + private static WSServer server; - + @BeforeClass public static void startServer() throws Exception { Path testdir = MavenTestingUtils.getTargetTestingPath(AnnotatedServerEndpointTest.class.getName()); - server = new WSServer(testdir,"app"); + server = new WSServer(testdir, "app"); server.createWebInf(); server.copyEndpoint(ConfiguredEchoSocket.class); server.copyClass(EchoSocketConfigurator.class); server.copyClass(DateDecoder.class); server.copyClass(TimeEncoder.class); - + server.start(); - + WebAppContext webapp = server.createWebAppContext(); server.deployWebapp(webapp); } - + @AfterClass public static void stopServer() { server.stop(); } - + private void assertResponse(String message, String expectedText) throws Exception { - WebSocketClient client = new WebSocketClient(bufferPool); - try + Map upgradeRequest = UpgradeUtils.newDefaultUpgradeRequestHeaders(); + upgradeRequest.put(WebSocketConstants.SEC_WEBSOCKET_PROTOCOL, "echo"); + + List send = new ArrayList<>(); + send.add(new TextFrame().setPayload(message)); + send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + List expect = new ArrayList<>(); + expect.add(new TextFrame().setPayload(expectedText)); + expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + try (LocalFuzzer session = server.newLocalFuzzer("/app/echo", upgradeRequest)) { - client.start(); - JettyEchoSocket clientSocket = new JettyEchoSocket(); - - URI uri = server.getServerBaseURI().resolve("echo"); - ClientUpgradeRequest req = new ClientUpgradeRequest(); - req.setSubProtocols("echo"); - Future clientConnectFuture = client.connect(clientSocket,uri,req); - // wait for connect - Session clientSession = clientConnectFuture.get(5,TimeUnit.SECONDS); - - clientSocket.sendMessage(message); - - String incomingMessage = clientSocket.messageQueue.poll(1, TimeUnit.SECONDS); - Assert.assertThat("Expected message",incomingMessage,containsString(expectedText)); - - clientSession.close(); - clientSocket.awaitCloseEvent("Client"); - } - finally - { - client.stop(); + session.sendFrames(send); + session.expect(expect); } } - + @Test public void testConfigurator() throws Exception { - assertResponse("configurator",EchoSocketConfigurator.class.getName()); + assertResponse("configurator", EchoSocketConfigurator.class.getName()); } @Test public void testTextMax() throws Exception { - assertResponse("text-max","111,222"); + assertResponse("text-max", "111,222"); } @Test public void testBinaryMax() throws Exception { - assertResponse("binary-max","333,444"); + assertResponse("binary-max", "333,444"); } - + @Test public void testDecoders() throws Exception { - assertResponse("decoders",DateDecoder.class.getName()); + assertResponse("decoders", DateDecoder.class.getName()); } - + @Test public void testEncoders() throws Exception { - assertResponse("encoders",TimeEncoder.class.getName()); + assertResponse("encoders", TimeEncoder.class.getName()); } - + @Test public void testSubProtocols() throws Exception { - assertResponse("subprotocols","chat, echo, test"); + assertResponse("subprotocols", "chat, echo, test"); } } diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/BinaryStreamTest.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/BinaryStreamTest.java new file mode 100644 index 00000000000..89f94030de4 --- /dev/null +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/BinaryStreamTest.java @@ -0,0 +1,164 @@ +// +// ======================================================================== +// 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.io.InputStream; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.BlockingQueue; + +import javax.websocket.OnMessage; +import javax.websocket.Session; +import javax.websocket.server.ServerEndpoint; +import javax.websocket.server.ServerEndpointConfig; + +import org.eclipse.jetty.servlet.ServletContextHandler; +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.common.CloseInfo; +import org.eclipse.jetty.websocket.common.OpCode; +import org.eclipse.jetty.websocket.common.WebSocketFrame; +import org.eclipse.jetty.websocket.common.frames.BinaryFrame; +import org.eclipse.jetty.websocket.jsr356.server.ServerContainer; +import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer; +import org.eclipse.jetty.websocket.tests.DataUtils; +import org.eclipse.jetty.websocket.tests.LocalFuzzer; +import org.eclipse.jetty.websocket.tests.LocalServer; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +public class BinaryStreamTest +{ + private static final String PATH = "/echo"; + + private static LocalServer server; + private static ServerContainer container; + + @BeforeClass + public static void startServer() throws Exception + { + server = new LocalServer() + { + @Override + protected void configureServletContextHandler(ServletContextHandler context) throws Exception + { + container = WebSocketServerContainerInitializer.configureContext(context); + ServerEndpointConfig config = ServerEndpointConfig.Builder.create(ServerBinaryStreamer.class, PATH).build(); + container.addEndpoint(config); + } + }; + server.start(); + } + + @AfterClass + public static void stopServer() throws Exception + { + server.stop(); + } + + @Test + public void testEchoWithMediumMessage() throws Exception + { + testEcho(1024); + } + + @Test + public void testLargestMessage() throws Exception + { + testEcho(container.getDefaultMaxBinaryMessageBufferSize()); + } + + private byte[] newData(int size) + { + byte[] pattern = "01234567890abcdefghijlklmopqrstuvwxyz".getBytes(StandardCharsets.UTF_8); + byte[] data = new byte[size]; + for (int i = 0; i < size; i++) + { + data[i] = pattern[i % pattern.length]; + } + return data; + } + + private void testEcho(int size) throws Exception + { + byte[] data = newData(size); + + List send = new ArrayList<>(); + send.add(new BinaryFrame().setPayload(data)); + send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + ByteBuffer expectedMessage = DataUtils.copyOf(data); + + try (LocalFuzzer session = server.newLocalFuzzer("/echo")) + { + session.sendBulk(send); + BlockingQueue receivedFrames = session.getOutputFrames(); + session.expectMessage(receivedFrames, OpCode.BINARY, expectedMessage); + } + } + + @Test + public void testMoreThanLargestMessageOneByteAtATime() throws Exception + { + int size = container.getDefaultMaxBinaryMessageBufferSize() + 16; + byte[] data = newData(size); + + List send = new ArrayList<>(); + send.add(new BinaryFrame().setPayload(data)); + send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + ByteBuffer expectedMessage = DataUtils.copyOf(data); + + try (LocalFuzzer session = server.newLocalFuzzer("/echo")) + { + session.sendSegmented(send, 1); + BlockingQueue receivedFrames = session.getOutputFrames(); + session.expectMessage(receivedFrames, OpCode.BINARY, expectedMessage); + } + } + + @ServerEndpoint(PATH) + public static class ServerBinaryStreamer + { + private static final Logger LOG = Log.getLogger(ServerBinaryStreamer.class); + + @OnMessage + public void echo(Session session, InputStream input) throws IOException + { + byte[] buffer = new byte[128]; + try (OutputStream output = session.getBasicRemote().getSendStream()) + { + int readCount = 0; + int read; + while ((read = input.read(buffer)) >= 0) + { + output.write(buffer, 0, read); + readCount += read; + } + LOG.debug("Read {} bytes", readCount); + } + } + } +} diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/ConfiguratorTest.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/ConfiguratorTest.java index fa90016d5ed..373682b0fff 100644 --- a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/ConfiguratorTest.java +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/ConfiguratorTest.java @@ -83,6 +83,7 @@ public class ConfiguratorTest { } + @SuppressWarnings("unused") @ServerEndpoint(value = "/empty", configurator = EmptyConfigurator.class) public static class EmptySocket { @@ -102,6 +103,7 @@ public class ConfiguratorTest } } + @SuppressWarnings("unused") @ServerEndpoint(value = "/no-extensions", configurator = NoExtensionsConfigurator.class) public static class NoExtensionsSocket { @@ -132,6 +134,7 @@ public class ConfiguratorTest } } + @SuppressWarnings("unused") @ServerEndpoint(value = "/capture-request-headers", configurator = CaptureHeadersConfigurator.class) public static class CaptureHeadersSocket { @@ -183,6 +186,7 @@ public class ConfiguratorTest } } + @SuppressWarnings("unused") @ServerEndpoint(value = "/protocols", configurator = ProtocolsConfigurator.class) public static class ProtocolsSocket { @@ -225,6 +229,7 @@ public class ConfiguratorTest } } + @SuppressWarnings("unused") @ServerEndpoint(value = "/unique-user-props", configurator = UniqueUserPropsConfigurator.class) public static class UniqueUserPropsSocket { @@ -261,6 +266,7 @@ public class ConfiguratorTest } } + @SuppressWarnings("unused") @ServerEndpoint(value = "/addr", configurator = AddrConfigurator.class) public static class AddressSocket { @@ -341,6 +347,7 @@ public class ConfiguratorTest } } + @SuppressWarnings("unused") @ServerEndpoint(value = "/timedecoder", subprotocols = {"time", "gmt"}, configurator = SelectedProtocolConfigurator.class, diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/InputStreamEchoTest.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/InputStreamEchoTest.java new file mode 100644 index 00000000000..7d119591cbd --- /dev/null +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/InputStreamEchoTest.java @@ -0,0 +1,153 @@ +// +// ======================================================================== +// 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.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +import javax.websocket.OnError; +import javax.websocket.OnMessage; +import javax.websocket.server.PathParam; +import javax.websocket.server.ServerEndpoint; + +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.util.IO; +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.common.CloseInfo; +import org.eclipse.jetty.websocket.common.WebSocketFrame; +import org.eclipse.jetty.websocket.common.frames.BinaryFrame; +import org.eclipse.jetty.websocket.common.frames.TextFrame; +import org.eclipse.jetty.websocket.jsr356.server.ServerContainer; +import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer; +import org.eclipse.jetty.websocket.tests.LocalFuzzer; +import org.eclipse.jetty.websocket.tests.LocalServer; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +/** + * Test various {@link javax.websocket.Decoder.BinaryStream Decoder.BinaryStream} echo behavior of Java InputStreams + */ +public class InputStreamEchoTest +{ + private static final Logger LOG = Log.getLogger(InputStreamEchoTest.class); + + public static class BaseSocket + { + @OnError + public void onError(Throwable cause) throws IOException + { + LOG.warn("Error", cause); + } + } + + @SuppressWarnings("unused") + @ServerEndpoint("/echo/stream") + public static class InputStreamSocket extends BaseSocket + { + @OnMessage + public String onStream(InputStream stream) throws IOException + { + return IO.toString(stream); + } + } + + @SuppressWarnings("unused") + @ServerEndpoint("/echo/stream-param/{param}") + public static class InputStreamParamSocket extends BaseSocket + { + @OnMessage + public String onStream(InputStream stream, @PathParam("param") String param) throws IOException + { + StringBuilder msg = new StringBuilder(); + msg.append(IO.toString(stream)); + msg.append('|'); + msg.append(param); + return msg.toString(); + } + } + + private static LocalServer server; + + @BeforeClass + public static void startServer() throws Exception + { + server = new LocalServer() + { + @Override + protected void configureServletContextHandler(ServletContextHandler context) throws Exception + { + ServerContainer container = WebSocketServerContainerInitializer.configureContext(context); + container.addEndpoint(InputStreamSocket.class); + container.addEndpoint(InputStreamParamSocket.class); + } + }; + server.start(); + } + + @AfterClass + public static void stopServer() throws Exception + { + server.stop(); + } + + @Test + public void testInputStreamSocket() throws Exception + { + String requestPath = "/echo/stream"; + + List send = new ArrayList<>(); + send.add(new BinaryFrame().setPayload("Hello World")); + send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + List expect = new ArrayList<>(); + expect.add(new TextFrame().setPayload("Hello World")); + expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + try (LocalFuzzer session = server.newLocalFuzzer(requestPath)) + { + session.sendBulk(send); + session.expect(expect); + } + } + + @Test + public void testInputStreamParamSocket() throws Exception + { + String requestPath = "/echo/stream-param/Every%20Person"; + + List send = new ArrayList<>(); + send.add(new BinaryFrame().setPayload("Hello World")); + send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + List expect = new ArrayList<>(); + expect.add(new TextFrame().setPayload("Hello World|Every Person")); + expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + try (LocalFuzzer session = server.newLocalFuzzer(requestPath)) + { + session.sendBulk(send); + session.expect(expect); + } + } +} diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/JsrEchoTest.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/JsrEchoTest.java new file mode 100644 index 00000000000..110fdc63d93 --- /dev/null +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/JsrEchoTest.java @@ -0,0 +1,226 @@ +// +// ======================================================================== +// 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.Arrays; +import java.util.List; + +import javax.websocket.CloseReason; +import javax.websocket.OnMessage; +import javax.websocket.OnOpen; +import javax.websocket.Session; +import javax.websocket.server.ServerEndpoint; + +import org.eclipse.jetty.servlet.ServletContextHandler; +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.jsr356.server.ServerContainer; +import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer; +import org.eclipse.jetty.websocket.tests.LocalFuzzer; +import org.eclipse.jetty.websocket.tests.LocalServer; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +/** + * Tests various ways to echo with JSR356 + */ +@RunWith(Parameterized.class) +public class JsrEchoTest +{ + @SuppressWarnings("unused") + @ServerEndpoint("/echo/basic") + public static class EchoBasicTextSocket + { + private Session session; + + @OnOpen + public void onOpen(Session session) + { + this.session = session; + } + + @OnMessage + public void onText(String msg) + { + try + { + session.getBasicRemote().sendText(msg); + } + catch (IOException esend) + { + esend.printStackTrace(System.err); + try + { + session.close(new CloseReason(CloseReason.CloseCodes.getCloseCode(4001), "Unable to echo msg")); + } + catch (IOException eclose) + { + eclose.printStackTrace(); + } + } + } + } + + @SuppressWarnings("unused") + @ServerEndpoint("/echo/basic-stateless") + public static class EchoBasicStatelessTextSocket + { + @OnMessage + public void onText(Session session, String msg) + { + try + { + session.getBasicRemote().sendText(msg); + } + catch (IOException esend) + { + esend.printStackTrace(System.err); + try + { + session.close(new CloseReason(CloseReason.CloseCodes.getCloseCode(4001), "Unable to echo msg")); + } + catch (IOException eclose) + { + eclose.printStackTrace(); + } + } + } + } + + @SuppressWarnings("unused") + @ServerEndpoint("/echo/async") + public static class EchoAsyncTextSocket + { + private Session session; + + @OnOpen + public void onOpen(Session session) + { + this.session = session; + } + + @OnMessage + public void onText(String msg) + { + session.getAsyncRemote().sendText(msg); + } + } + + @SuppressWarnings("unused") + @ServerEndpoint("/echo/async-stateless") + public static class EchoAsyncStatelessSocket + { + @OnMessage + public void onText(Session session, String msg) + { + session.getAsyncRemote().sendText(msg); + } + } + + @SuppressWarnings("unused") + @ServerEndpoint("/echo/text/return") + public static class EchoReturnTextSocket + { + @OnMessage + public String onText(String msg) + { + return msg; + } + } + + private static final List> TESTCLASSES = Arrays.asList( + EchoBasicTextSocket.class, + EchoBasicStatelessTextSocket.class, + EchoAsyncTextSocket.class, + EchoAsyncStatelessSocket.class, + EchoReturnTextSocket.class); + + @Parameterized.Parameters(name = "{0}") + public static List data() + { + List data = new ArrayList<>(); + + for (Class clazz : TESTCLASSES) + { + data.add(new Object[]{clazz.getSimpleName(), clazz}); + } + + return data; + } + + private static LocalServer server; + + @BeforeClass + public static void startServer() throws Exception + { + server = new LocalServer() + { + @Override + protected void configureServletContextHandler(ServletContextHandler context) throws Exception + { + ServerContainer container = WebSocketServerContainerInitializer.configureContext(context); + + for (Class clazz : TESTCLASSES) + { + container.addEndpoint(clazz); + } + } + }; + server.start(); + } + + @AfterClass + public static void stopServer() throws Exception + { + server.stop(); + } + + @Parameterized.Parameter + public String endpointClassname; + + @Parameterized.Parameter(1) + public Class endpointClass; + + @Test + public void testTextEcho() throws Exception + { + String requestPath = endpointClass.getAnnotation(ServerEndpoint.class).value(); + + List send = new ArrayList<>(); + send.add(new TextFrame().setPayload("Hello Echo")); + send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + List expect = new ArrayList<>(); + expect.add(new TextFrame().setPayload("Hello Echo")); + expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + try (LocalFuzzer session = server.newLocalFuzzer(requestPath)) + { + session.sendBulk(send); + session.expect(expect); + } + } +} diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/PartialEchoTest.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/PartialEchoTest.java new file mode 100644 index 00000000000..cbde8771a8d --- /dev/null +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/PartialEchoTest.java @@ -0,0 +1,176 @@ +// +// ======================================================================== +// 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.List; + +import javax.websocket.OnError; +import javax.websocket.OnMessage; +import javax.websocket.OnOpen; +import javax.websocket.Session; +import javax.websocket.server.ServerEndpoint; + +import org.eclipse.jetty.servlet.ServletContextHandler; +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.common.CloseInfo; +import org.eclipse.jetty.websocket.common.WebSocketFrame; +import org.eclipse.jetty.websocket.common.frames.ContinuationFrame; +import org.eclipse.jetty.websocket.common.frames.TextFrame; +import org.eclipse.jetty.websocket.jsr356.server.ServerContainer; +import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer; +import org.eclipse.jetty.websocket.tests.LocalFuzzer; +import org.eclipse.jetty.websocket.tests.LocalServer; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +/** + * Sends raw TEXT or BINARY messages to server. + *

+ * JSR356 Decoder resolves it to an object, and uses the JSR356 Encoder to produce an echo response. + *

+ */ +public class PartialEchoTest +{ + private static final Logger LOG = Log.getLogger(PartialEchoTest.class); + + public static class BaseSocket + { + @OnError + public void onError(Throwable cause) throws IOException + { + LOG.warn("Error", cause); + } + } + + @SuppressWarnings("unused") + @ServerEndpoint("/echo/partial/text") + public static class PartialTextSocket extends BaseSocket + { + private Session session; + private StringBuilder buf = new StringBuilder(); + + @OnOpen + public void onOpen(Session session) + { + this.session = session; + } + + @OnMessage + public void onPartial(String msg, boolean fin) throws IOException + { + buf.append("('").append(msg).append("',").append(fin).append(')'); + if (fin) + { + session.getBasicRemote().sendText(buf.toString()); + buf.setLength(0); + } + } + } + + @SuppressWarnings("unused") + @ServerEndpoint("/echo/partial/text-session") + public static class PartialTextSessionSocket extends BaseSocket + { + private StringBuilder buf = new StringBuilder(); + + @OnMessage + public void onPartial(String msg, boolean fin, Session session) throws IOException + { + buf.append("('").append(msg).append("',").append(fin).append(')'); + if (fin) + { + session.getBasicRemote().sendText(buf.toString()); + buf.setLength(0); + } + } + } + + private static LocalServer server; + + @BeforeClass + public static void startServer() throws Exception + { + server = new LocalServer() + { + @Override + protected void configureServletContextHandler(ServletContextHandler context) throws Exception + { + ServerContainer container = WebSocketServerContainerInitializer.configureContext(context); + container.addEndpoint(PartialTextSocket.class); + container.addEndpoint(PartialTextSessionSocket.class); + } + }; + server.start(); + } + + @AfterClass + public static void stopServer() throws Exception + { + server.stop(); + } + + @Test + public void testPartialText() throws Exception + { + String requestPath = "/echo/partial/text"; + + List send = new ArrayList<>(); + send.add(new TextFrame().setPayload("Hello").setFin(false)); + send.add(new ContinuationFrame().setPayload(", ").setFin(false)); + send.add(new ContinuationFrame().setPayload("World").setFin(true)); + send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + List expect = new ArrayList<>(); + expect.add(new TextFrame().setPayload("('Hello',false)(', ',false)('World',true)")); + expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + try (LocalFuzzer session = server.newLocalFuzzer(requestPath)) + { + session.sendBulk(send); + session.expect(expect); + } + } + + @Test + public void testPartialTextSession() throws Exception + { + String requestPath = "/echo/partial/text-session"; + + List send = new ArrayList<>(); + send.add(new TextFrame().setPayload("Hello").setFin(false)); + send.add(new ContinuationFrame().setPayload(", ").setFin(false)); + send.add(new ContinuationFrame().setPayload("World").setFin(true)); + send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + List expect = new ArrayList<>(); + expect.add(new TextFrame().setPayload("('Hello',false)(', ',false)('World',true)")); + expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + try (LocalFuzzer session = server.newLocalFuzzer(requestPath)) + { + session.sendBulk(send); + session.expect(expect); + } + } +} diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/PrimitivesBinaryEchoTest.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/PrimitivesBinaryEchoTest.java new file mode 100644 index 00000000000..b04e8a12b37 --- /dev/null +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/PrimitivesBinaryEchoTest.java @@ -0,0 +1,169 @@ +// +// ======================================================================== +// 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.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; + +import javax.websocket.OnError; +import javax.websocket.OnMessage; +import javax.websocket.server.ServerEndpoint; + +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.toolchain.test.Hex; +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.common.CloseInfo; +import org.eclipse.jetty.websocket.common.WebSocketFrame; +import org.eclipse.jetty.websocket.common.frames.BinaryFrame; +import org.eclipse.jetty.websocket.jsr356.server.ServerContainer; +import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer; +import org.eclipse.jetty.websocket.tests.LocalFuzzer; +import org.eclipse.jetty.websocket.tests.LocalServer; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +/** + * Test various {@link javax.websocket.Decoder.Binary Decoder.Binary} / {@link javax.websocket.Encoder.Binary Encoder.Binary} echo behavior of Java Primitives + */ +@RunWith(Parameterized.class) +public class PrimitivesBinaryEchoTest +{ + private static final Logger LOG = Log.getLogger(PrimitivesBinaryEchoTest.class); + + public static class BaseSocket + { + @OnError + public void onError(Throwable cause) throws IOException + { + LOG.warn("Error", cause); + } + } + + @ServerEndpoint("/echo/bytebuffer") + public static class ByteBufferEchoSocket extends BaseSocket + { + @OnMessage + public ByteBuffer onMessage(ByteBuffer buf) throws IOException + { + ByteBuffer ret = ByteBuffer.allocate(buf.remaining() + 1); + ret.put((byte) 0xFF); // proof that this endpoint got it + ret.put(buf); + ret.flip(); + return ret; + } + } + + @ServerEndpoint("/echo/bytearray") + public static class ByteArrayEchoSocket extends BaseSocket + { + @OnMessage + public byte[] onMessage(byte[] buf) throws IOException + { + byte ret[] = new byte[buf.length + 1]; + ret[0] = (byte) 0xFE; // proof that this endpoint got it + System.arraycopy(buf, 0, ret, 1, buf.length); + return ret; + } + } + + private static void addCase(List data, Class endpointClass, String sendHex, String expectHex) + { + data.add(new Object[]{endpointClass.getSimpleName(), endpointClass, sendHex, expectHex}); + } + + @Parameterized.Parameters(name = "{0}: {2}") + public static List data() + { + List data = new ArrayList<>(); + + addCase(data, ByteBufferEchoSocket.class, "00", "FF00"); + addCase(data, ByteBufferEchoSocket.class, "001133445566778899AA", "FF001133445566778899AA"); + addCase(data, ByteBufferEchoSocket.class, "11112222333344445555", "FF11112222333344445555"); + + addCase(data, ByteArrayEchoSocket.class, "00", "FE00"); + addCase(data, ByteArrayEchoSocket.class, "001133445566778899AA", "FE001133445566778899AA"); + addCase(data, ByteArrayEchoSocket.class, "11112222333344445555", "FE11112222333344445555"); + + return data; + } + + private static LocalServer server; + + @BeforeClass + public static void startServer() throws Exception + { + server = new LocalServer() + { + @Override + protected void configureServletContextHandler(ServletContextHandler context) throws Exception + { + ServerContainer container = WebSocketServerContainerInitializer.configureContext(context); + + container.addEndpoint(ByteBufferEchoSocket.class); + container.addEndpoint(ByteArrayEchoSocket.class); + } + }; + server.start(); + } + + @AfterClass + public static void stopServer() throws Exception + { + server.stop(); + } + + @Parameterized.Parameter + public String endpointClassname; + + @Parameterized.Parameter(1) + public Class endpointClass; + + @Parameterized.Parameter(2) + public String sendHex; + + @Parameterized.Parameter(3) + public String expectHex; + + @Test + public void testPrimitiveEcho() throws Exception + { + String requestPath = endpointClass.getAnnotation(ServerEndpoint.class).value(); + + List send = new ArrayList<>(); + send.add(new BinaryFrame().setPayload(Hex.asByteBuffer(sendHex))); + send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + List expect = new ArrayList<>(); + expect.add(new BinaryFrame().setPayload(Hex.asByteBuffer(expectHex))); + expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + try (LocalFuzzer session = server.newLocalFuzzer(requestPath)) + { + session.sendBulk(send); + session.expect(expect); + } + } +} diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/PrimitivesTextEchoTest.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/PrimitivesTextEchoTest.java new file mode 100644 index 00000000000..348f016dfd0 --- /dev/null +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/PrimitivesTextEchoTest.java @@ -0,0 +1,418 @@ +// +// ======================================================================== +// 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.List; + +import javax.websocket.OnError; +import javax.websocket.OnMessage; +import javax.websocket.server.ServerEndpoint; + +import org.eclipse.jetty.servlet.ServletContextHandler; +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.common.CloseInfo; +import org.eclipse.jetty.websocket.common.WebSocketFrame; +import org.eclipse.jetty.websocket.common.frames.TextFrame; +import org.eclipse.jetty.websocket.jsr356.server.ServerContainer; +import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer; +import org.eclipse.jetty.websocket.tests.LocalFuzzer; +import org.eclipse.jetty.websocket.tests.LocalServer; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +/** + * Test various {@link javax.websocket.Decoder.Text Decoder.Text} / {@link javax.websocket.Encoder.Text Encoder.Text} echo behavior of Java Primitives + */ +@RunWith(Parameterized.class) +public class PrimitivesTextEchoTest +{ + private static final Logger LOG = Log.getLogger(PrimitivesTextEchoTest.class); + + public static class BaseSocket + { + @OnError + public void onError(Throwable cause) throws IOException + { + LOG.warn("Error", cause); + } + } + + @ServerEndpoint("/echo/boolean") + public static class BooleanEchoSocket extends BaseSocket + { + @OnMessage + public boolean onMessage(boolean b) throws IOException + { + return b; + } + } + + @ServerEndpoint("/echo/boolean-obj") + public static class BooleanObjEchoSocket extends BaseSocket + { + @OnMessage + public Boolean onMessage(Boolean b) throws IOException + { + return b; + } + } + + @ServerEndpoint("/echo/byte") + public static class ByteEchoSocket extends BaseSocket + { + @OnMessage + public byte onMessage(byte b) throws IOException + { + return b; + } + } + + @ServerEndpoint("/echo/byte-obj") + public static class ByteObjEchoSocket extends BaseSocket + { + @OnMessage + public byte onMessage(byte b) throws IOException + { + return b; + } + } + + @ServerEndpoint("/echo/char") + public static class CharacterEchoSocket extends BaseSocket + { + @OnMessage + public char onMessage(char c) throws IOException + { + return c; + } + } + + @ServerEndpoint("/echo/char-obj") + public static class CharacterObjEchoSocket extends BaseSocket + { + @OnMessage + public Character onMessage(Character c) throws IOException + { + return c; + } + } + + @ServerEndpoint("/echo/double") + public static class DoubleEchoSocket extends BaseSocket + { + @OnMessage + public double onMessage(double d) throws IOException + { + return d; + } + } + + @ServerEndpoint("/echo/double-obj") + public static class DoubleObjEchoSocket extends BaseSocket + { + @OnMessage + public Double onMessage(Double d) throws IOException + { + return d; + } + } + + @ServerEndpoint("/echo/float") + public static class FloatEchoSocket extends BaseSocket + { + @OnMessage + public float onMessage(float f) throws IOException + { + return f; + } + } + + @ServerEndpoint("/echo/float-obj") + public static class FloatObjEchoSocket extends BaseSocket + { + @OnMessage + public Float onMessage(Float f) throws IOException + { + return f; + } + } + + @ServerEndpoint("/echo/short") + public static class ShortEchoSocket extends BaseSocket + { + @OnMessage + public short onMessage(short s) throws IOException + { + return s; + } + } + + @ServerEndpoint("/echo/short-obj") + public static class ShortObjEchoSocket extends BaseSocket + { + @OnMessage + public Short onMessage(Short s) throws IOException + { + return s; + } + } + + @ServerEndpoint("/echo/integer") + public static class IntegerEchoSocket extends BaseSocket + { + @OnMessage + public int onMessage(int i) throws IOException + { + return i; + } + } + + @ServerEndpoint("/echo/integer-obj") + public static class IntegerObjEchoSocket extends BaseSocket + { + @OnMessage + public Integer onMessage(Integer i) throws IOException + { + return i; + } + } + + @ServerEndpoint("/echo/long") + public static class LongEchoSocket extends BaseSocket + { + @OnMessage + public long onMessage(long l) throws IOException + { + return l; + } + } + + @ServerEndpoint("/echo/long-obj") + public static class LongObjEchoSocket extends BaseSocket + { + @OnMessage + public Long onMessage(Long l) throws IOException + { + return l; + } + } + + @ServerEndpoint("/echo/string") + public static class StringEchoSocket extends BaseSocket + { + @OnMessage + public String onMessage(String s) throws IOException + { + return s; + } + } + + private static void addCase(List data, Class endpointClass, String sendText, String expectText) + { + data.add(new Object[]{endpointClass.getSimpleName(), endpointClass, sendText, expectText}); + } + + @Parameterized.Parameters(name = "{0}: {2}") + public static List data() + { + List data = new ArrayList<>(); + + addCase(data, BooleanEchoSocket.class, "true", "true"); + addCase(data, BooleanEchoSocket.class, "TRUE", "true"); + addCase(data, BooleanEchoSocket.class, "false", "false"); + addCase(data, BooleanEchoSocket.class, "FALSE", "false"); + addCase(data, BooleanEchoSocket.class, "TRue", "true"); + addCase(data, BooleanEchoSocket.class, Boolean.toString(Boolean.TRUE), "true"); + addCase(data, BooleanEchoSocket.class, Boolean.toString(Boolean.FALSE), "false"); + addCase(data, BooleanEchoSocket.class, "Apple", "false"); + + addCase(data, BooleanObjEchoSocket.class, "true", "true"); + addCase(data, BooleanObjEchoSocket.class, "TRUE", "true"); + addCase(data, BooleanObjEchoSocket.class, "false", "false"); + addCase(data, BooleanObjEchoSocket.class, "FALSE", "false"); + addCase(data, BooleanObjEchoSocket.class, "TRue", "true"); + addCase(data, BooleanObjEchoSocket.class, Boolean.toString(Boolean.TRUE), "true"); + addCase(data, BooleanObjEchoSocket.class, Boolean.toString(Boolean.FALSE), "false"); + addCase(data, BooleanObjEchoSocket.class, "Apple", "false"); + + addCase(data, ByteEchoSocket.class, Byte.toString((byte)0x00), "0"); + addCase(data, ByteEchoSocket.class, Byte.toString((byte)0x58), "88"); + addCase(data, ByteEchoSocket.class, Byte.toString((byte)0x65), "101"); + addCase(data, ByteEchoSocket.class, Byte.toString(Byte.MAX_VALUE), "127"); + addCase(data, ByteEchoSocket.class, Byte.toString(Byte.MIN_VALUE), "-128"); + + addCase(data, ByteObjEchoSocket.class, Byte.toString((byte)0x00), "0"); + addCase(data, ByteObjEchoSocket.class, Byte.toString((byte)0x58), "88"); + addCase(data, ByteObjEchoSocket.class, Byte.toString((byte)0x65), "101"); + addCase(data, ByteObjEchoSocket.class, Byte.toString(Byte.MAX_VALUE), "127"); + addCase(data, ByteObjEchoSocket.class, Byte.toString(Byte.MIN_VALUE), "-128"); + + addCase(data, CharacterEchoSocket.class, Character.toString((char) 40), "("); + addCase(data, CharacterEchoSocket.class, Character.toString((char) 106), "j"); + addCase(data, CharacterEchoSocket.class, Character.toString((char) 64), "@"); + addCase(data, CharacterEchoSocket.class, Character.toString((char) 0x262f), "\u262f"); + + addCase(data, CharacterObjEchoSocket.class, Character.toString((char) 40), "("); + addCase(data, CharacterObjEchoSocket.class, Character.toString((char) 106), "j"); + addCase(data, CharacterObjEchoSocket.class, Character.toString((char) 64), "@"); + addCase(data, CharacterObjEchoSocket.class, Character.toString((char) 0x262f), "\u262f"); + + addCase(data, DoubleEchoSocket.class, Double.toString(3.1459), "3.1459"); + addCase(data, DoubleEchoSocket.class, Double.toString(123.456), "123.456"); + addCase(data, DoubleEchoSocket.class, Double.toString(55), "55.0"); + addCase(data, DoubleEchoSocket.class, Double.toString(.123), "0.123"); + addCase(data, DoubleEchoSocket.class, Double.toString(Double.MAX_VALUE), Double.toString(Double.MAX_VALUE)); + addCase(data, DoubleEchoSocket.class, Double.toString(Double.MIN_VALUE), Double.toString(Double.MIN_VALUE)); + + addCase(data, DoubleObjEchoSocket.class, Double.toString(3.1459), "3.1459"); + addCase(data, DoubleObjEchoSocket.class, Double.toString(123.456), "123.456"); + addCase(data, DoubleObjEchoSocket.class, Double.toString(55), "55.0"); + addCase(data, DoubleObjEchoSocket.class, Double.toString(.123), "0.123"); + addCase(data, DoubleObjEchoSocket.class, Double.toString(Double.MAX_VALUE), Double.toString(Double.MAX_VALUE)); + addCase(data, DoubleObjEchoSocket.class, Double.toString(Double.MIN_VALUE), Double.toString(Double.MIN_VALUE)); + + addCase(data, FloatEchoSocket.class, Float.toString(3.1459f), "3.1459"); + addCase(data, FloatEchoSocket.class, Float.toString(0.0f), "0.0"); + addCase(data, FloatEchoSocket.class, Float.toString(Float.MAX_VALUE), Float.toString(Float.MAX_VALUE)); + addCase(data, FloatEchoSocket.class, Float.toString(Float.MIN_VALUE), Float.toString(Float.MIN_VALUE)); + + addCase(data, FloatObjEchoSocket.class, Float.toString(3.1459f), "3.1459"); + addCase(data, FloatObjEchoSocket.class, Float.toString(0.0f), "0.0"); + addCase(data, FloatObjEchoSocket.class, Float.toString(Float.MAX_VALUE), Float.toString(Float.MAX_VALUE)); + addCase(data, FloatObjEchoSocket.class, Float.toString(Float.MIN_VALUE), Float.toString(Float.MIN_VALUE)); + + addCase(data, ShortEchoSocket.class, Short.toString((short) 0), "0"); + addCase(data, ShortEchoSocket.class, Short.toString((short) 30000), "30000"); + addCase(data, ShortEchoSocket.class, Short.toString(Short.MAX_VALUE), Short.toString(Short.MAX_VALUE)); + addCase(data, ShortEchoSocket.class, Short.toString(Short.MIN_VALUE), Short.toString(Short.MIN_VALUE)); + + addCase(data, ShortObjEchoSocket.class, Short.toString((short) 0), "0"); + addCase(data, ShortObjEchoSocket.class, Short.toString((short) 30000), "30000"); + addCase(data, ShortObjEchoSocket.class, Short.toString(Short.MAX_VALUE), Short.toString(Short.MAX_VALUE)); + addCase(data, ShortObjEchoSocket.class, Short.toString(Short.MIN_VALUE), Short.toString(Short.MIN_VALUE)); + + addCase(data, IntegerEchoSocket.class, Integer.toString(0), "0"); + addCase(data, IntegerEchoSocket.class, Integer.toString(100_000), "100000"); + addCase(data, IntegerEchoSocket.class, Integer.toString(-2_000_000), "-2000000"); + addCase(data, IntegerEchoSocket.class, Integer.toString(Integer.MAX_VALUE), Integer.toString(Integer.MAX_VALUE)); + addCase(data, IntegerEchoSocket.class, Integer.toString(Integer.MIN_VALUE), Integer.toString(Integer.MIN_VALUE)); + + addCase(data, IntegerObjEchoSocket.class, Integer.toString(0), "0"); + addCase(data, IntegerObjEchoSocket.class, Integer.toString(100_000), "100000"); + addCase(data, IntegerObjEchoSocket.class, Integer.toString(-2_000_000), "-2000000"); + addCase(data, IntegerObjEchoSocket.class, Integer.toString(Integer.MAX_VALUE), Integer.toString(Integer.MAX_VALUE)); + addCase(data, IntegerObjEchoSocket.class, Integer.toString(Integer.MIN_VALUE), Integer.toString(Integer.MIN_VALUE)); + + addCase(data, LongEchoSocket.class, Long.toString(0), "0"); + addCase(data, LongEchoSocket.class, Long.toString(100_000), "100000"); + addCase(data, LongEchoSocket.class, Long.toString(-2_000_000), "-2000000"); + addCase(data, LongEchoSocket.class, Long.toString(300_000_000_000l), "300000000000"); + addCase(data, LongEchoSocket.class, Long.toString(Long.MAX_VALUE), Long.toString(Long.MAX_VALUE)); + addCase(data, LongEchoSocket.class, Long.toString(Long.MIN_VALUE), Long.toString(Long.MIN_VALUE)); + + addCase(data, LongObjEchoSocket.class, Long.toString(0), "0"); + addCase(data, LongObjEchoSocket.class, Long.toString(100_000), "100000"); + addCase(data, LongObjEchoSocket.class, Long.toString(-2_000_000), "-2000000"); + addCase(data, LongObjEchoSocket.class, Long.toString(300_000_000_000l), "300000000000"); + addCase(data, LongObjEchoSocket.class, Long.toString(Long.MAX_VALUE), Long.toString(Long.MAX_VALUE)); + addCase(data, LongObjEchoSocket.class, Long.toString(Long.MIN_VALUE), Long.toString(Long.MIN_VALUE)); + + addCase(data, StringEchoSocket.class, "Hello World", "Hello World"); + return data; + } + + private static LocalServer server; + + @BeforeClass + public static void startServer() throws Exception + { + server = new LocalServer() + { + @Override + protected void configureServletContextHandler(ServletContextHandler context) throws Exception + { + ServerContainer container = WebSocketServerContainerInitializer.configureContext(context); + + container.addEndpoint(BooleanEchoSocket.class); + container.addEndpoint(BooleanObjEchoSocket.class); + container.addEndpoint(ByteEchoSocket.class); + container.addEndpoint(ByteObjEchoSocket.class); + container.addEndpoint(CharacterEchoSocket.class); + container.addEndpoint(CharacterObjEchoSocket.class); + container.addEndpoint(DoubleEchoSocket.class); + container.addEndpoint(DoubleObjEchoSocket.class); + container.addEndpoint(FloatEchoSocket.class); + container.addEndpoint(FloatObjEchoSocket.class); + container.addEndpoint(ShortEchoSocket.class); + container.addEndpoint(ShortObjEchoSocket.class); + container.addEndpoint(IntegerEchoSocket.class); + container.addEndpoint(IntegerObjEchoSocket.class); + container.addEndpoint(LongEchoSocket.class); + container.addEndpoint(LongObjEchoSocket.class); + container.addEndpoint(StringEchoSocket.class); + } + }; + server.start(); + } + + @AfterClass + public static void stopServer() throws Exception + { + server.stop(); + } + + @Parameterized.Parameter + public String endpointClassname; + + @Parameterized.Parameter(1) + public Class endpointClass; + + @Parameterized.Parameter(2) + public String sendText; + + @Parameterized.Parameter(3) + public String expectText; + + @Test + public void testPrimitiveEcho() throws Exception + { + String requestPath = endpointClass.getAnnotation(ServerEndpoint.class).value(); + + List send = new ArrayList<>(); + send.add(new TextFrame().setPayload(sendText)); + send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + List expect = new ArrayList<>(); + expect.add(new TextFrame().setPayload(expectText)); + expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + try (LocalFuzzer session = server.newLocalFuzzer(requestPath)) + { + session.sendBulk(send); + session.expect(expect); + } + } +} diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/ReaderEchoTest.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/ReaderEchoTest.java new file mode 100644 index 00000000000..9432118567f --- /dev/null +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/ReaderEchoTest.java @@ -0,0 +1,207 @@ +// +// ======================================================================== +// 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.io.Reader; +import java.io.Writer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import javax.websocket.OnError; +import javax.websocket.OnMessage; +import javax.websocket.Session; +import javax.websocket.server.PathParam; +import javax.websocket.server.ServerEndpoint; + +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.util.IO; +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.common.CloseInfo; +import org.eclipse.jetty.websocket.common.WebSocketFrame; +import org.eclipse.jetty.websocket.common.frames.TextFrame; +import org.eclipse.jetty.websocket.jsr356.server.ServerContainer; +import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer; +import org.eclipse.jetty.websocket.tests.DataUtils; +import org.eclipse.jetty.websocket.tests.LocalFuzzer; +import org.eclipse.jetty.websocket.tests.LocalServer; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; + +/** + * Test various {@link javax.websocket.Decoder.TextStream Decoder.TextStream} and {@link javax.websocket.Encoder.TextStream Encoder.TextStream} echo behavior of Java Readers + */ +public class ReaderEchoTest +{ + private static final Logger LOG = Log.getLogger(ReaderEchoTest.class); + + public static class BaseSocket + { + @OnError + public void onError(Throwable cause) throws IOException + { + LOG.warn("Error", cause); + } + } + + @SuppressWarnings("unused") + @ServerEndpoint("/echo/reader") + public static class ReaderSocket extends BaseSocket + { + @OnMessage + public String onReader(Reader reader) throws IOException + { + return IO.toString(reader); + } + } + + @SuppressWarnings("unused") + @ServerEndpoint("/echo/reader-self") + public static class ReaderSelfSocket extends BaseSocket + { + @OnMessage + public Writer onReader(Session session, Reader reader) throws IOException + { + final Writer writer = session.getBasicRemote().getSendWriter(); + + new Thread(() -> + { + try + { + IO.copy(reader, writer); + } + catch (IOException e) + { + LOG.warn(e); + } + }).start(); + + return writer; + } + } + + @SuppressWarnings("unused") + @ServerEndpoint("/echo/reader-param/{param}") + public static class ReaderParamSocket extends BaseSocket + { + @OnMessage + public String onReader(Reader reader, @PathParam("param") String param) throws IOException + { + StringBuilder msg = new StringBuilder(); + msg.append(IO.toString(reader)); + msg.append('|'); + msg.append(param); + return msg.toString(); + } + } + + private static LocalServer server; + + @BeforeClass + public static void startServer() throws Exception + { + server = new LocalServer() + { + @Override + protected void configureServletContextHandler(ServletContextHandler context) throws Exception + { + ServerContainer container = WebSocketServerContainerInitializer.configureContext(context); + container.addEndpoint(ReaderSocket.class); + // TODO: container.addEndpoint(ReaderSelfSocket.class); + container.addEndpoint(ReaderParamSocket.class); + } + }; + server.start(); + } + + @AfterClass + public static void stopServer() throws Exception + { + server.stop(); + } + + @Test + public void testReaderSocket() throws Exception + { + String requestPath = "/echo/reader"; + + List send = new ArrayList<>(); + send.add(new TextFrame().setPayload("Hello World")); + send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + List expect = new ArrayList<>(); + expect.add(new TextFrame().setPayload("Hello World")); + expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + try (LocalFuzzer session = server.newLocalFuzzer(requestPath)) + { + session.sendBulk(send); + session.expect(expect); + } + } + + @Test + @Ignore("TODO: Need Encoder for Writer?") + public void testReaderSelfSocket() throws Exception + { + String requestPath = "/echo/reader-self"; + + byte data[] = new byte[1024 * 1024]; + Arrays.fill(data, (byte) 'x'); + + List send = new ArrayList<>(); + send.add(new TextFrame().setPayload(DataUtils.copyOf(data))); + send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + List expect = new ArrayList<>(); + expect.add(new TextFrame().setPayload(DataUtils.copyOf(data))); + expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + try (LocalFuzzer session = server.newLocalFuzzer(requestPath)) + { + session.sendBulk(send); + session.expect(expect); + } + } + + @Test + public void testReaderParamSocket() throws Exception + { + String requestPath = "/echo/reader-param/Every%20Person"; + + List send = new ArrayList<>(); + send.add(new TextFrame().setPayload("Hello World")); + send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + List expect = new ArrayList<>(); + expect.add(new TextFrame().setPayload("Hello World|Every Person")); + expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + try (LocalFuzzer session = server.newLocalFuzzer(requestPath)) + { + session.sendBulk(send); + session.expect(expect); + } + } +} diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/SessionTest.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/SessionTest.java new file mode 100644 index 00000000000..5b58d141fe0 --- /dev/null +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/SessionTest.java @@ -0,0 +1,368 @@ +// +// ======================================================================== +// 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.net.URI; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import javax.websocket.Endpoint; +import javax.websocket.EndpointConfig; +import javax.websocket.MessageHandler; +import javax.websocket.OnMessage; +import javax.websocket.server.ServerEndpoint; +import javax.websocket.server.ServerEndpointConfig; + +import org.eclipse.jetty.servlet.DefaultServlet; +import org.eclipse.jetty.servlet.ServletContextHandler; +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.jsr356.server.ServerContainer; +import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer; +import org.eclipse.jetty.websocket.tests.LocalFuzzer; +import org.eclipse.jetty.websocket.tests.LocalServer; +import org.junit.After; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class SessionTest +{ + @ServerEndpoint(value = "/info/") + public static class SessionInfoSocket + { + @OnMessage + public String onMessage(javax.websocket.Session session, String message) + { + if ("pathParams".equalsIgnoreCase(message)) + { + StringBuilder ret = new StringBuilder(); + ret.append("pathParams"); + Map pathParams = session.getPathParameters(); + if (pathParams == null) + { + ret.append("="); + } + else + { + ret.append('[').append(pathParams.size()).append(']'); + List keys = new ArrayList<>(); + for (String key : pathParams.keySet()) + { + keys.add(key); + } + Collections.sort(keys); + for (String key : keys) + { + String value = pathParams.get(key); + ret.append(": '").append(key).append("'=").append(value); + } + } + return ret.toString(); + } + + if ("requestUri".equalsIgnoreCase(message)) + { + StringBuilder ret = new StringBuilder(); + ret.append("requestUri="); + URI uri = session.getRequestURI(); + if (uri == null) + { + ret.append("="); + } + else + { + ret.append(uri.toASCIIString()); + } + return ret.toString(); + } + + // simple echo + return "echo:'" + message + "'"; + } + } + + public static class SessionInfoEndpoint extends Endpoint implements MessageHandler.Whole + { + private javax.websocket.Session session; + + @Override + public void onOpen(javax.websocket.Session session, EndpointConfig config) + { + this.session = session; + this.session.addMessageHandler(this); + } + + @Override + public void onMessage(String message) + { + try + { + if ("pathParams".equalsIgnoreCase(message)) + { + StringBuilder ret = new StringBuilder(); + ret.append("pathParams"); + Map pathParams = session.getPathParameters(); + if (pathParams == null) + { + ret.append("="); + } + else + { + ret.append('[').append(pathParams.size()).append(']'); + List keys = new ArrayList<>(); + for (String key : pathParams.keySet()) + { + keys.add(key); + } + Collections.sort(keys); + for (String key : keys) + { + String value = pathParams.get(key); + ret.append(": '").append(key).append("'=").append(value); + } + } + session.getBasicRemote().sendText(ret.toString()); + return; + } + + if ("requestUri".equalsIgnoreCase(message)) + { + StringBuilder ret = new StringBuilder(); + ret.append("requestUri="); + URI uri = session.getRequestURI(); + if (uri == null) + { + ret.append("="); + } + else + { + ret.append(uri.toASCIIString()); + } + session.getBasicRemote().sendText(ret.toString()); + return; + } + + // simple echo + session.getBasicRemote().sendText("echo:'" + message + "'"); + } + catch (IOException e) + { + e.printStackTrace(System.err); + } + } + } + + private interface Case + { + void customize(ServletContextHandler context); + } + + @Parameters + public static Collection data() + { + List cases = new ArrayList<>(); + cases.add(new Case[] + {context -> + { + // no customization + }}); + cases.add(new Case[] + {context -> + { + // Test with DefaultServlet only + context.addServlet(DefaultServlet.class,"/"); + }}); + cases.add(new Case[] + {context -> + { + // Test with Servlet mapped to "/*" + context.addServlet(DefaultServlet.class,"/*"); + }}); + cases.add(new Case[] + {context -> + { + // Test with Servlet mapped to "/info/*" + context.addServlet(DefaultServlet.class,"/info/*"); + }}); + return cases; + } + + private LocalServer server; + + @After + public void stopServer() throws Exception + { + server.stop(); + } + + public SessionTest(final Case testcase) throws Exception + { + server = new LocalServer() + { + @Override + protected void configureServletContextHandler(ServletContextHandler context) throws Exception + { + testcase.customize(context); + + ServerContainer container = WebSocketServerContainerInitializer.configureContext(context); + + container.addEndpoint(SessionInfoSocket.class); // default behavior + Class endpointClass = SessionInfoSocket.class; + container.addEndpoint(ServerEndpointConfig.Builder.create(endpointClass,"/info/{a}/").build()); + container.addEndpoint(ServerEndpointConfig.Builder.create(endpointClass,"/info/{a}/{b}/").build()); + container.addEndpoint(ServerEndpointConfig.Builder.create(endpointClass,"/info/{a}/{b}/{c}/").build()); + container.addEndpoint(ServerEndpointConfig.Builder.create(endpointClass,"/info/{a}/{b}/{c}/{d}/").build()); + endpointClass = SessionInfoEndpoint.class; + container.addEndpoint(ServerEndpointConfig.Builder.create(endpointClass,"/einfo/").build()); + container.addEndpoint(ServerEndpointConfig.Builder.create(endpointClass,"/einfo/{a}/").build()); + container.addEndpoint(ServerEndpointConfig.Builder.create(endpointClass,"/einfo/{a}/{b}/").build()); + container.addEndpoint(ServerEndpointConfig.Builder.create(endpointClass,"/einfo/{a}/{b}/{c}/").build()); + container.addEndpoint(ServerEndpointConfig.Builder.create(endpointClass,"/einfo/{a}/{b}/{c}/{d}/").build()); + } + }; + server.start(); + } + + private void assertResponse(String requestPath, String requestMessage, + String expectedResponse) throws Exception + { + List send = new ArrayList<>(); + send.add(new TextFrame().setPayload(requestMessage)); + send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + List expect = new ArrayList<>(); + expect.add(new TextFrame().setPayload(expectedResponse)); + expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + try (LocalFuzzer session = server.newLocalFuzzer(requestPath)) + { + session.sendBulk(send); + session.expect(expect); + } + } + + @Test + public void testPathParams_Annotated_Empty() throws Exception + { + assertResponse("/info/","pathParams", + "pathParams[0]"); + } + + @Test + public void testPathParams_Annotated_Single() throws Exception + { + assertResponse("/info/apple/","pathParams", + "pathParams[1]: 'a'=apple"); + } + + @Test + public void testPathParams_Annotated_Double() throws Exception + { + assertResponse("/info/apple/pear/","pathParams", + "pathParams[2]: 'a'=apple: 'b'=pear"); + } + + @Test + public void testPathParams_Annotated_Triple() throws Exception + { + assertResponse("/info/apple/pear/cherry/","pathParams", + "pathParams[3]: 'a'=apple: 'b'=pear: 'c'=cherry"); + } + + @Test + public void testPathParams_Endpoint_Empty() throws Exception + { + assertResponse("/einfo/","pathParams", + "pathParams[0]"); + } + + @Test + public void testPathParams_Endpoint_Single() throws Exception + { + assertResponse("/einfo/apple/","pathParams", + "pathParams[1]: 'a'=apple"); + } + + @Test + public void testPathParams_Endpoint_Double() throws Exception + { + assertResponse("/einfo/apple/pear/","pathParams", + "pathParams[2]: 'a'=apple: 'b'=pear"); + } + + @Test + public void testPathParams_Endpoint_Triple() throws Exception + { + assertResponse("/einfo/apple/pear/cherry/","pathParams", + "pathParams[3]: 'a'=apple: 'b'=pear: 'c'=cherry"); + } + + @Test + public void testRequestUri_Annotated_Basic() throws Exception + { + assertResponse("/info/","requestUri", + "requestUri=ws://local/info/"); + } + + @Test + public void testRequestUri_Annotated_WithPathParam() throws Exception + { + assertResponse("/info/apple/banana/","requestUri", + "requestUri=ws://local/info/apple/banana/"); + } + + @Test + public void testRequestUri_Annotated_WithPathParam_WithQuery() throws Exception + { + assertResponse("/info/apple/banana/?fruit=fresh&store=grandmasfarm", + "requestUri", + "requestUri=ws://local/info/apple/banana/?fruit=fresh&store=grandmasfarm"); + } + + @Test + public void testRequestUri_Endpoint_Basic() throws Exception + { + assertResponse("/einfo/","requestUri", + "requestUri=ws://local/einfo/"); + } + + @Test + public void testRequestUri_Endpoint_WithPathParam() throws Exception + { + assertResponse("/einfo/apple/banana/","requestUri", + "requestUri=ws://local/einfo/apple/banana/"); + } + + @Test + public void testRequestUri_Endpoint_WithPathParam_WithQuery() throws Exception + { + assertResponse("/einfo/apple/banana/?fruit=fresh&store=grandmasfarm", + "requestUri", + "requestUri=ws://local/einfo/apple/banana/?fruit=fresh&store=grandmasfarm"); + } +} diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/TextStreamTest.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/TextStreamTest.java new file mode 100644 index 00000000000..dd244c71d49 --- /dev/null +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/TextStreamTest.java @@ -0,0 +1,156 @@ +// +// ======================================================================== +// 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.io.Reader; +import java.io.Writer; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.BlockingQueue; + +import javax.websocket.OnMessage; +import javax.websocket.Session; +import javax.websocket.server.ServerEndpoint; +import javax.websocket.server.ServerEndpointConfig; + +import org.eclipse.jetty.servlet.ServletContextHandler; +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.jsr356.server.ServerContainer; +import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer; +import org.eclipse.jetty.websocket.tests.DataUtils; +import org.eclipse.jetty.websocket.tests.LocalFuzzer; +import org.eclipse.jetty.websocket.tests.LocalServer; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +public class TextStreamTest +{ + private static final String PATH = "/echo"; + private static final String CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + + private static LocalServer server; + private static ServerContainer container; + + @BeforeClass + public static void startServer() throws Exception + { + server = new LocalServer() + { + @Override + protected void configureServletContextHandler(ServletContextHandler context) throws Exception + { + container = WebSocketServerContainerInitializer.configureContext(context); + ServerEndpointConfig config = ServerEndpointConfig.Builder.create(ServerTextStreamer.class, PATH).build(); + container.addEndpoint(config); + } + }; + server.start(); + } + + @AfterClass + public static void stopServer() throws Exception + { + server.stop(); + } + + @Test + public void testEchoWithMediumMessage() throws Exception + { + testEcho(1024); + } + + @Test + public void testLargestMessage() throws Exception + { + testEcho(container.getDefaultMaxTextMessageBufferSize()); + } + + private byte[] newData(int size) + { + byte[] pattern = "01234567890abcdefghijlklmopqrstuvwxyz".getBytes(StandardCharsets.UTF_8); + byte[] data = new byte[size]; + for (int i = 0; i < size; i++) + { + data[i] = pattern[i % pattern.length]; + } + return data; + } + + private void testEcho(int size) throws Exception + { + byte[] data = newData(size); + + List send = new ArrayList<>(); + send.add(new TextFrame().setPayload(ByteBuffer.wrap(data))); + send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + ByteBuffer expectedMessage = DataUtils.copyOf(data); + + try (LocalFuzzer session = server.newLocalFuzzer("/echo")) + { + session.sendBulk(send); + BlockingQueue receivedFrames = session.getOutputFrames(); + session.expectMessage(receivedFrames, OpCode.TEXT, expectedMessage); + } + } + + @Test + public void testMoreThanLargestMessageOneByteAtATime() throws Exception + { + int size = container.getDefaultMaxTextMessageBufferSize() + 16; + byte[] data = newData(size); + + List send = new ArrayList<>(); + send.add(new TextFrame().setPayload(ByteBuffer.wrap(data))); + send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + ByteBuffer expectedMessage = DataUtils.copyOf(data); + + try (LocalFuzzer session = server.newLocalFuzzer("/echo")) + { + session.sendBulk(send); + BlockingQueue receivedFrames = session.getOutputFrames(); + session.expectMessage(receivedFrames, OpCode.TEXT, expectedMessage); + } + } + + @ServerEndpoint(PATH) + public static class ServerTextStreamer + { + @OnMessage + public void echo(Session session, Reader input) throws IOException + { + char[] buffer = new char[128]; + try (Writer output = session.getBasicRemote().getSendWriter()) + { + int read; + while ((read = input.read(buffer)) >= 0) + output.write(buffer, 0, read); + } + } + } +} diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/UriTemplateParameterTest.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/UriTemplateParameterTest.java new file mode 100644 index 00000000000..547e5ae7515 --- /dev/null +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/UriTemplateParameterTest.java @@ -0,0 +1,107 @@ +// +// ======================================================================== +// 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.List; + +import javax.websocket.OnError; +import javax.websocket.OnMessage; +import javax.websocket.server.PathParam; +import javax.websocket.server.ServerEndpoint; + +import org.eclipse.jetty.servlet.ServletContextHandler; +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.common.CloseInfo; +import org.eclipse.jetty.websocket.common.WebSocketFrame; +import org.eclipse.jetty.websocket.common.frames.TextFrame; +import org.eclipse.jetty.websocket.jsr356.server.ServerContainer; +import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer; +import org.eclipse.jetty.websocket.tests.LocalFuzzer; +import org.eclipse.jetty.websocket.tests.LocalServer; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +public class UriTemplateParameterTest +{ + private static final Logger LOG = Log.getLogger(UriTemplateParameterTest.class); + + @ServerEndpoint("/echo/params/{a}/{b}") + public static class IntParamTextSocket + { + @OnMessage + public String onMessage(int i, @PathParam("a") int paramA, @PathParam("b") int paramB) throws IOException + { + return String.format("%,d|%,d|%,d", i, paramA, paramB); + } + + @OnError + public void onError(Throwable cause) throws IOException + { + LOG.warn("Error", cause); + } + } + + private static LocalServer server; + + @BeforeClass + public static void startServer() throws Exception + { + server = new LocalServer() + { + @Override + protected void configureServletContextHandler(ServletContextHandler context) throws Exception + { + ServerContainer container = WebSocketServerContainerInitializer.configureContext(context); + container.addEndpoint(IntParamTextSocket.class); + } + }; + server.start(); + } + + @AfterClass + public static void stopServer() throws Exception + { + server.stop(); + } + + @Test + public void testIntParams() throws Exception + { + String requestPath = "/echo/params/1234/5678"; + + List send = new ArrayList<>(); + send.add(new TextFrame().setPayload("9999")); + send.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + List expect = new ArrayList<>(); + expect.add(new TextFrame().setPayload("9,999|1,234|5,678")); + expect.add(new CloseInfo(StatusCode.NORMAL).asFrame()); + + try (LocalFuzzer session = server.newLocalFuzzer(requestPath)) + { + session.sendBulk(send); + session.expect(expect); + } + } +} diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/beans/DateDecoder.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/coders/DateDecoder.java similarity index 96% rename from jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/beans/DateDecoder.java rename to jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/coders/DateDecoder.java index 5f47fd9ecb2..30a830c127a 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/beans/DateDecoder.java +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/coders/DateDecoder.java @@ -16,7 +16,7 @@ // ======================================================================== // -package org.eclipse.jetty.websocket.jsr356.server.samples.beans; +package org.eclipse.jetty.websocket.tests.server.jsr356.coders; import java.text.ParseException; import java.text.SimpleDateFormat; diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/beans/DateEncoder.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/coders/DateEncoder.java similarity index 95% rename from jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/beans/DateEncoder.java rename to jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/coders/DateEncoder.java index 3848cd5b457..ff381263160 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/beans/DateEncoder.java +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/coders/DateEncoder.java @@ -16,7 +16,7 @@ // ======================================================================== // -package org.eclipse.jetty.websocket.jsr356.server.samples.beans; +package org.eclipse.jetty.websocket.tests.server.jsr356.coders; import java.text.SimpleDateFormat; import java.util.Date; diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/beans/DateTimeDecoder.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/coders/DateTimeDecoder.java similarity index 96% rename from jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/beans/DateTimeDecoder.java rename to jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/coders/DateTimeDecoder.java index 8f6c8bc12a9..987832dc887 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/beans/DateTimeDecoder.java +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/coders/DateTimeDecoder.java @@ -16,7 +16,7 @@ // ======================================================================== // -package org.eclipse.jetty.websocket.jsr356.server.samples.beans; +package org.eclipse.jetty.websocket.tests.server.jsr356.coders; import java.text.ParseException; import java.text.SimpleDateFormat; diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/beans/DateTimeEncoder.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/coders/DateTimeEncoder.java similarity index 95% rename from jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/beans/DateTimeEncoder.java rename to jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/coders/DateTimeEncoder.java index 93e485cd181..7a3c3858522 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/beans/DateTimeEncoder.java +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/coders/DateTimeEncoder.java @@ -16,7 +16,7 @@ // ======================================================================== // -package org.eclipse.jetty.websocket.jsr356.server.samples.beans; +package org.eclipse.jetty.websocket.tests.server.jsr356.coders; import java.text.SimpleDateFormat; import java.util.Date; diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/beans/TimeDecoder.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/coders/TimeDecoder.java similarity index 96% rename from jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/beans/TimeDecoder.java rename to jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/coders/TimeDecoder.java index 95db93b16b3..2add684d49d 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/beans/TimeDecoder.java +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/coders/TimeDecoder.java @@ -16,7 +16,7 @@ // ======================================================================== // -package org.eclipse.jetty.websocket.jsr356.server.samples.beans; +package org.eclipse.jetty.websocket.tests.server.jsr356.coders; import java.text.ParseException; import java.text.SimpleDateFormat; diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/beans/TimeEncoder.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/coders/TimeEncoder.java similarity index 95% rename from jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/beans/TimeEncoder.java rename to jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/coders/TimeEncoder.java index 4c4271e1f6d..9e299315e26 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/beans/TimeEncoder.java +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/coders/TimeEncoder.java @@ -16,7 +16,7 @@ // ======================================================================== // -package org.eclipse.jetty.websocket.jsr356.server.samples.beans; +package org.eclipse.jetty.websocket.tests.server.jsr356.coders; import java.text.SimpleDateFormat; import java.util.Date; diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/echo/EchoSocketConfigurator.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/configs/EchoSocketConfigurator.java similarity index 95% rename from jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/echo/EchoSocketConfigurator.java rename to jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/configs/EchoSocketConfigurator.java index 635055a211e..eeb99915b4c 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/echo/EchoSocketConfigurator.java +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/configs/EchoSocketConfigurator.java @@ -16,7 +16,7 @@ // ======================================================================== // -package org.eclipse.jetty.websocket.jsr356.server.samples.echo; +package org.eclipse.jetty.websocket.tests.server.jsr356.configs; import java.util.Collections; diff --git a/jetty-websocket/websocket-tests/src/main/java/org/eclipse/jetty/websocket/tests/Fuzzed.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/sockets/BasicEchoSocket.java similarity index 65% rename from jetty-websocket/websocket-tests/src/main/java/org/eclipse/jetty/websocket/tests/Fuzzed.java rename to jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/sockets/BasicEchoSocket.java index 2214164ff60..c129250df98 100644 --- a/jetty-websocket/websocket-tests/src/main/java/org/eclipse/jetty/websocket/tests/Fuzzed.java +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/sockets/BasicEchoSocket.java @@ -16,17 +16,22 @@ // ======================================================================== // -package org.eclipse.jetty.websocket.tests; +package org.eclipse.jetty.websocket.tests.server.jsr356.sockets; -import java.net.URI; +import javax.websocket.OnMessage; +import javax.websocket.Session; +import javax.websocket.server.ServerEndpoint; -import org.eclipse.jetty.websocket.common.Generator; - -public interface Fuzzed +/** + * Annotated echo socket + */ +@ServerEndpoint("/echo") +public class BasicEchoSocket { - URI getServerURI(); - - Generator getLaxGenerator(); - - String getTestMethodName(); + @OnMessage + public void echo(Session session, String msg) + { + // reply with echo + session.getAsyncRemote().sendText(msg); + } } diff --git a/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/sockets/ByteBufferSocket.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/sockets/ByteBufferSocket.java new file mode 100644 index 00000000000..ef5aa1f1797 --- /dev/null +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/sockets/ByteBufferSocket.java @@ -0,0 +1,51 @@ +// +// ======================================================================== +// 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 java.io.IOException; +import java.nio.ByteBuffer; + +import javax.websocket.OnError; +import javax.websocket.OnMessage; +import javax.websocket.Session; +import javax.websocket.server.ServerEndpoint; + +import org.eclipse.jetty.toolchain.test.StackUtils; +import org.eclipse.jetty.util.BufferUtil; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; + +@ServerEndpoint("/echo/binary/bytebuffer") +public class ByteBufferSocket +{ + private static final Logger LOG = Log.getLogger(ByteBufferSocket.class); + + @OnMessage + public String onByteBuffer(ByteBuffer bbuf) + { + return BufferUtil.toUTF8String(bbuf); + } + + @OnError + public void onError(Session session, Throwable cause) throws IOException + { + LOG.warn("Error",cause); + session.getBasicRemote().sendText("Exception: " + StackUtils.toString(cause)); + } +} diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/echo/ConfiguredEchoSocket.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/sockets/ConfiguredEchoSocket.java similarity index 74% rename from jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/echo/ConfiguredEchoSocket.java rename to jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/sockets/ConfiguredEchoSocket.java index c65859a86df..59568102f66 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/echo/ConfiguredEchoSocket.java +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/sockets/ConfiguredEchoSocket.java @@ -16,15 +16,13 @@ // ======================================================================== // -package org.eclipse.jetty.websocket.jsr356.server.samples.echo; +package org.eclipse.jetty.websocket.tests.server.jsr356.sockets; + +import static java.util.Comparator.naturalOrder; +import static java.util.stream.Collectors.joining; import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; import java.util.Locale; -import java.util.Objects; import javax.websocket.EndpointConfig; import javax.websocket.OnMessage; @@ -33,8 +31,9 @@ import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; import javax.websocket.server.ServerEndpointConfig; -import org.eclipse.jetty.websocket.jsr356.server.samples.beans.DateDecoder; -import org.eclipse.jetty.websocket.jsr356.server.samples.beans.TimeEncoder; +import org.eclipse.jetty.websocket.tests.server.jsr356.coders.DateDecoder; +import org.eclipse.jetty.websocket.tests.server.jsr356.coders.TimeEncoder; +import org.eclipse.jetty.websocket.tests.server.jsr356.configs.EchoSocketConfigurator; /** * Annotated echo socket, using all of the annotation configurations @@ -51,6 +50,7 @@ public class ConfiguredEchoSocket private EndpointConfig config; private ServerEndpointConfig serverConfig; + @SuppressWarnings("unused") @OnOpen public void onOpen(Session session, EndpointConfig config) { @@ -61,7 +61,8 @@ public class ConfiguredEchoSocket this.serverConfig = (ServerEndpointConfig)config; } } - + + @SuppressWarnings("unused") @OnMessage(maxMessageSize = 111222) public String echoText(String msg) { @@ -72,9 +73,9 @@ public class ConfiguredEchoSocket case "binary-max": return String.format(Locale.US, "%,d",session.getMaxBinaryMessageBufferSize()); case "decoders": - return join(config.getDecoders(),", "); + return config.getDecoders().stream().map(Class::getName).collect(joining(", ")); case "encoders": - return join(config.getEncoders(),", "); + return config.getEncoders().stream().map(Class::getName).collect(joining(", ")); case "subprotocols": if (serverConfig == null) { @@ -82,10 +83,7 @@ public class ConfiguredEchoSocket } else { - List protocols = new ArrayList<>(); - protocols.addAll(serverConfig.getSubprotocols()); - Collections.sort(protocols); - return join(protocols,", "); + return serverConfig.getSubprotocols().stream().sorted(naturalOrder()).collect(joining(", ")); } case "configurator": if (serverConfig == null) @@ -102,23 +100,7 @@ public class ConfiguredEchoSocket } } - private String join(Collection coll, String delim) - { - StringBuilder buf = new StringBuilder(); - boolean needDelim = false; - for (Object obj : coll) - { - if (needDelim) - { - buf.append(delim); - } - buf.append(Objects.toString(obj)); - needDelim = true; - } - - return buf.toString(); - } - + @SuppressWarnings("unused") @OnMessage(maxMessageSize = 333444) public ByteBuffer echoBinary(ByteBuffer buf) { diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/beans/DateTextSocket.java b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/sockets/DateTextSocket.java similarity index 87% rename from jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/beans/DateTextSocket.java rename to jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/sockets/DateTextSocket.java index 2203627177a..2c57af2d13b 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/beans/DateTextSocket.java +++ b/jetty-websocket/websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/jsr356/sockets/DateTextSocket.java @@ -16,7 +16,7 @@ // ======================================================================== // -package org.eclipse.jetty.websocket.jsr356.server.samples.beans; +package org.eclipse.jetty.websocket.tests.server.jsr356.sockets; import java.io.IOException; import java.util.Date; @@ -27,9 +27,11 @@ import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; +import org.eclipse.jetty.toolchain.test.StackUtils; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.websocket.common.util.StackUtil; +import org.eclipse.jetty.websocket.tests.server.jsr356.coders.DateDecoder; +import org.eclipse.jetty.websocket.tests.server.jsr356.coders.DateEncoder; @ServerEndpoint(value = "/echo/beans/date", decoders = { DateDecoder.class }, encoders = { DateEncoder.class }) public class DateTextSocket @@ -63,6 +65,6 @@ public class DateTextSocket public void onError(Throwable cause) throws IOException { LOG.warn("Error",cause); - session.getBasicRemote().sendText("Exception: " + StackUtil.toString(cause)); + session.getBasicRemote().sendText("Exception: " + StackUtils.toString(cause)); } } diff --git a/jetty-websocket/websocket-tests/src/test/resources/alt-filter-web.xml b/jetty-websocket/websocket-tests/src/test/resources/alt-filter-web.xml new file mode 100644 index 00000000000..24c506eb389 --- /dev/null +++ b/jetty-websocket/websocket-tests/src/test/resources/alt-filter-web.xml @@ -0,0 +1,23 @@ + + + + + org.eclipse.jetty.websocket.jsr356.addDynamicFilter + false + + + + wsuf-test + org.eclipse.jetty.websocket.server.WebSocketUpgradeFilter + + + + wsuf-test + /echo/* + + diff --git a/jetty-websocket/websocket-tests/src/test/resources/empty-web.xml b/jetty-websocket/websocket-tests/src/test/resources/empty-web.xml new file mode 100644 index 00000000000..18aafa59387 --- /dev/null +++ b/jetty-websocket/websocket-tests/src/test/resources/empty-web.xml @@ -0,0 +1,8 @@ + + + \ No newline at end of file diff --git a/jetty-websocket/websocket-tests/src/test/resources/jetty-logging.properties b/jetty-websocket/websocket-tests/src/test/resources/jetty-logging.properties index 484551fff03..167871d3674 100644 --- a/jetty-websocket/websocket-tests/src/test/resources/jetty-logging.properties +++ b/jetty-websocket/websocket-tests/src/test/resources/jetty-logging.properties @@ -25,18 +25,19 @@ org.eclipse.jetty.LEVEL=WARN # org.eclipse.jetty.io.WriteFlusher.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.io.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 -org.eclipse.jetty.websocket.common.WebSocketSession.LEVEL=DEBUG -org.eclipse.jetty.websocket.common.Parser.LEVEL=DEBUG +# org.eclipse.jetty.websocket.common.WebSocketSession.LEVEL=DEBUG +# org.eclipse.jetty.websocket.common.Parser.LEVEL=DEBUG # org.eclipse.jetty.websocket.common.Generator.LEVEL=DEBUG # org.eclipse.jetty.websocket.server.helper.LEVEL=DEBUG +# org.eclipse.jetty.websocket.common.message.LEVEL=DEBUG org.eclipse.jetty.websocket.common.CompletionCallback.LEVEL=ALL ### Disabling intentional error out of RFCSocket