Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'jetty-websocket')
-rw-r--r--jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/api/StatusCode.java2
-rw-r--r--jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/io/AbstractWebSocketConnection.java42
-rw-r--r--jetty-websocket/websocket-core/src/test/java/org/eclipse/jetty/websocket/protocol/WebSocketFrameTest.java2
-rw-r--r--jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/AllTests.java6
-rw-r--r--jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/Fuzzer.java6
-rw-r--r--jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase6_GoodUTF.java1
-rw-r--r--jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase7.java416
-rw-r--r--jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase7_9.java185
-rw-r--r--jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase7_BadStatusCodes.java129
-rw-r--r--jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase7_GoodStatusCodes.java124
10 files changed, 707 insertions, 206 deletions
diff --git a/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/api/StatusCode.java b/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/api/StatusCode.java
index 9c3c98cbe6..596dcbb643 100644
--- a/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/api/StatusCode.java
+++ b/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/api/StatusCode.java
@@ -114,7 +114,7 @@ public class StatusCode
public final static int SERVER_ERROR = 1011;
/**
- * 1012 indicates that the service is restarted. a client may reconnect, and if it choses to do, should reconnect using a randomized delay of 5 - 30s.
+ * 1012 indicates that the service is restarted. a client may reconnect, and if it chooses to do, should reconnect using a randomized delay of 5 - 30s.
* <p>
* See <a href="https://www.ietf.org/mail-archive/web/hybi/current/msg09649.html">[hybi] Additional WebSocket Close Error Codes</a>
*/
diff --git a/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/io/AbstractWebSocketConnection.java b/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/io/AbstractWebSocketConnection.java
index fde5bcc1d6..3944be0eb3 100644
--- a/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/io/AbstractWebSocketConnection.java
+++ b/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/io/AbstractWebSocketConnection.java
@@ -23,12 +23,11 @@ import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicLong;
import org.eclipse.jetty.io.AbstractConnection;
+import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.EndPoint;
-import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.FutureCallback;
@@ -62,7 +61,6 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
private WebSocketSession session;
private List<ExtensionConfig> extensions;
private boolean flushing;
- private AtomicLong writes;
public AbstractWebSocketConnection(EndPoint endp, Executor executor, ScheduledExecutorService scheduler, WebSocketPolicy policy, ByteBufferPool bufferPool)
{
@@ -74,17 +72,9 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
this.scheduler = scheduler;
this.extensions = new ArrayList<>();
this.queue = new FrameQueue();
- this.writes = new AtomicLong(0);
}
@Override
- public void onOpen()
- {
- super.onOpen();
- fillInterested();
- }
-
- @Override
public void close() throws IOException
{
terminateConnection(StatusCode.NORMAL,null);
@@ -136,6 +126,13 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
frameBytes = queue.pop();
+ if (!isOpen())
+ {
+ // No longer have an open connection, drop the frame.
+ queue.clear();
+ return;
+ }
+
buffer = frameBytes.getByteBuffer();
if (buffer == null)
@@ -236,6 +233,13 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
}
}
+ @Override
+ public void onOpen()
+ {
+ super.onOpen();
+ fillInterested();
+ }
+
/**
* Enqueue internal frame from {@link OutgoingFrames} stack for eventual write out on the physical connection.
*/
@@ -261,13 +265,17 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
}
scheduleTimeout(bytes);
- if (frame.getOpCode() == OpCode.PING)
- {
- queue.prepend(bytes);
- }
- else
+
+ if (isOpen())
{
- queue.append(bytes);
+ if (frame.getOpCode() == OpCode.PING)
+ {
+ queue.prepend(bytes);
+ }
+ else
+ {
+ queue.append(bytes);
+ }
}
}
flush();
diff --git a/jetty-websocket/websocket-core/src/test/java/org/eclipse/jetty/websocket/protocol/WebSocketFrameTest.java b/jetty-websocket/websocket-core/src/test/java/org/eclipse/jetty/websocket/protocol/WebSocketFrameTest.java
index 19d46f4599..6bc817774e 100644
--- a/jetty-websocket/websocket-core/src/test/java/org/eclipse/jetty/websocket/protocol/WebSocketFrameTest.java
+++ b/jetty-websocket/websocket-core/src/test/java/org/eclipse/jetty/websocket/protocol/WebSocketFrameTest.java
@@ -74,7 +74,7 @@ public class WebSocketFrameTest
@Test
public void testStrictValidClose()
{
- CloseInfo close = new CloseInfo(StatusCode.NORMAL,null);
+ CloseInfo close = new CloseInfo(StatusCode.NORMAL);
ByteBuffer actual = strictGenerator.generate(close.asFrame());
ByteBuffer expected = ByteBuffer.allocate(4);
expected.put((byte)0x88);
diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/AllTests.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/AllTests.java
index ffd8e57e1a..e65f7e8eff 100644
--- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/AllTests.java
+++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/AllTests.java
@@ -13,8 +13,10 @@ import org.junit.runners.Suite;
TestABCase5.class,
TestABCase6.class,
TestABCase6_GoodUTF.class,
- TestABCase6_BadUTF.class,
- TestABCase7_9.class
+ TestABCase6_BadUTF.class,
+ TestABCase7.class,
+ TestABCase7_GoodStatusCodes.class,
+ TestABCase7_BadStatusCodes.class,
})
// @formatter:on
public class AllTests
diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/Fuzzer.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/Fuzzer.java
index fcf9a7f516..f6a7bbceb0 100644
--- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/Fuzzer.java
+++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/Fuzzer.java
@@ -127,6 +127,12 @@ public class Fuzzer
expect(Collections.singletonList(expect));
}
+ public void expectNoMoreFrames()
+ {
+ // TODO Should test for no more frames. success if connection closed.
+
+ }
+
public SendMode getSendMode()
{
return sendMode;
diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase6_GoodUTF.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase6_GoodUTF.java
index 14685fdd1d..2d8d5ab16f 100644
--- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase6_GoodUTF.java
+++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase6_GoodUTF.java
@@ -99,6 +99,7 @@ public class TestABCase6_GoodUTF extends AbstractABCase
return data;
}
+
private final byte[] msg;
public TestABCase6_GoodUTF(String testId, String hexMsg)
diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase7.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase7.java
new file mode 100644
index 0000000000..29f25be5be
--- /dev/null
+++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase7.java
@@ -0,0 +1,416 @@
+package org.eclipse.jetty.websocket.server.ab;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.jetty.util.BufferUtil;
+import org.eclipse.jetty.util.StringUtil;
+import org.eclipse.jetty.websocket.api.StatusCode;
+import org.eclipse.jetty.websocket.protocol.CloseInfo;
+import org.eclipse.jetty.websocket.protocol.OpCode;
+import org.eclipse.jetty.websocket.protocol.WebSocketFrame;
+import org.eclipse.jetty.websocket.server.helper.Hex;
+import org.junit.Ignore;
+import org.junit.Test;
+
+/**
+ * Test of Close Handling
+ */
+public class TestABCase7 extends AbstractABCase
+{
+ /**
+ * Basic message then close frame, normal behavior
+ */
+ @Test
+ public void testCase7_1_1() throws Exception
+ {
+ List<WebSocketFrame> send = new ArrayList<>();
+ send.add(WebSocketFrame.text("Hello World"));
+ send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
+
+ List<WebSocketFrame> expect = new ArrayList<>();
+ expect.add(WebSocketFrame.text("Hello World"));
+ expect.add(new CloseInfo(StatusCode.NORMAL).asFrame());
+
+ Fuzzer fuzzer = new Fuzzer(this);
+ try
+ {
+ fuzzer.connect();
+ fuzzer.setSendMode(Fuzzer.SendMode.BULK);
+ fuzzer.send(send);
+ fuzzer.expect(expect);
+ }
+ finally
+ {
+ fuzzer.close();
+ }
+ }
+
+ /**
+ * Close frame, then another close frame (send frame ignored)
+ */
+ @Test
+ public void testCase7_1_2() throws Exception
+ {
+ List<WebSocketFrame> send = new ArrayList<>();
+ send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
+ send.add(new CloseInfo().asFrame());
+
+ List<WebSocketFrame> expect = new ArrayList<>();
+ expect.add(new CloseInfo(StatusCode.NORMAL).asFrame());
+
+ Fuzzer fuzzer = new Fuzzer(this);
+ try
+ {
+ fuzzer.connect();
+ fuzzer.setSendMode(Fuzzer.SendMode.BULK);
+ fuzzer.send(send);
+ fuzzer.expect(expect);
+ fuzzer.expectNoMoreFrames();
+ }
+ finally
+ {
+ fuzzer.close();
+ }
+ }
+
+ /**
+ * Close frame, then ping frame (no pong received)
+ */
+ @Test
+ public void testCase7_1_3() throws Exception
+ {
+ List<WebSocketFrame> send = new ArrayList<>();
+ send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
+ send.add(WebSocketFrame.ping().setPayload("out of band ping"));
+
+ List<WebSocketFrame> expect = new ArrayList<>();
+ expect.add(new CloseInfo(StatusCode.NORMAL).asFrame());
+
+ Fuzzer fuzzer = new Fuzzer(this);
+ try
+ {
+ fuzzer.connect();
+ fuzzer.setSendMode(Fuzzer.SendMode.BULK);
+ fuzzer.send(send);
+ fuzzer.expect(expect);
+ fuzzer.expectNoMoreFrames();
+ }
+ finally
+ {
+ fuzzer.close();
+ }
+ }
+
+ /**
+ * Close frame, then ping frame (no pong received)
+ */
+ @Test
+ public void testCase7_1_4() throws Exception
+ {
+ List<WebSocketFrame> send = new ArrayList<>();
+ send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
+ send.add(WebSocketFrame.text("out of band text"));
+
+ List<WebSocketFrame> expect = new ArrayList<>();
+ expect.add(new CloseInfo(StatusCode.NORMAL).asFrame());
+
+ Fuzzer fuzzer = new Fuzzer(this);
+ try
+ {
+ fuzzer.connect();
+ fuzzer.setSendMode(Fuzzer.SendMode.BULK);
+ fuzzer.send(send);
+ fuzzer.expect(expect);
+ fuzzer.expectNoMoreFrames();
+ }
+ finally
+ {
+ fuzzer.close();
+ }
+ }
+
+ /**
+ * Text fin=false, close, then continuation fin=true
+ */
+ @Test
+ public void testCase7_1_5() throws Exception
+ {
+ List<WebSocketFrame> send = new ArrayList<>();
+ send.add(new WebSocketFrame(OpCode.TEXT).setPayload("an").setFin(false));
+ send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
+ send.add(new WebSocketFrame(OpCode.CONTINUATION).setPayload("ticipation").setFin(true));
+
+ List<WebSocketFrame> expect = new ArrayList<>();
+ expect.add(new CloseInfo(StatusCode.NORMAL).asFrame());
+
+ Fuzzer fuzzer = new Fuzzer(this);
+ try
+ {
+ fuzzer.connect();
+ fuzzer.setSendMode(Fuzzer.SendMode.BULK);
+ fuzzer.send(send);
+ fuzzer.expect(expect);
+ fuzzer.expectNoMoreFrames();
+ }
+ finally
+ {
+ fuzzer.close();
+ }
+ }
+
+ /**
+ * 256k msg, then close, then ping
+ */
+ @Test
+ @Ignore("Problematic")
+ public void testCase7_1_6() throws Exception
+ {
+ byte msg[] = new byte[256 * 1024];
+ Arrays.fill(msg,(byte)'*');
+
+ List<WebSocketFrame> send = new ArrayList<>();
+ send.add(new WebSocketFrame(OpCode.TEXT).setPayload(msg));
+ send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
+ send.add(new WebSocketFrame(OpCode.PING).setPayload("out of band"));
+
+ List<WebSocketFrame> expect = new ArrayList<>();
+ send.add(new WebSocketFrame(OpCode.TEXT).setPayload(msg));
+ expect.add(new CloseInfo(StatusCode.NORMAL).asFrame());
+
+ Fuzzer fuzzer = new Fuzzer(this);
+ try
+ {
+ fuzzer.connect();
+ fuzzer.setSendMode(Fuzzer.SendMode.BULK);
+ fuzzer.send(send);
+ fuzzer.expect(expect);
+ fuzzer.expectNoMoreFrames();
+ }
+ finally
+ {
+ fuzzer.close();
+ }
+ }
+
+ /**
+ * close with no payload (payload length 0)
+ */
+ @Test
+ public void testCase7_3_1() throws Exception
+ {
+ List<WebSocketFrame> send = new ArrayList<>();
+ send.add(new WebSocketFrame(OpCode.CLOSE));
+
+ List<WebSocketFrame> expect = new ArrayList<>();
+ expect.add(new WebSocketFrame(OpCode.CLOSE));
+
+ Fuzzer fuzzer = new Fuzzer(this);
+ try
+ {
+ fuzzer.connect();
+ fuzzer.setSendMode(Fuzzer.SendMode.BULK);
+ fuzzer.send(send);
+ fuzzer.expect(expect);
+ fuzzer.expectNoMoreFrames();
+ }
+ finally
+ {
+ fuzzer.close();
+ }
+ }
+
+ /**
+ * close with invalid payload (payload length 1)
+ */
+ @Test
+ public void testCase7_3_2() throws Exception
+ {
+ byte payload[] = new byte[]
+ { 0x00 };
+
+ List<WebSocketFrame> send = new ArrayList<>();
+ send.add(new WebSocketFrame(OpCode.CLOSE).setPayload(payload));
+
+ List<WebSocketFrame> expect = new ArrayList<>();
+ expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame());
+
+ Fuzzer fuzzer = new Fuzzer(this);
+ try
+ {
+ fuzzer.connect();
+ fuzzer.setSendMode(Fuzzer.SendMode.BULK);
+ fuzzer.send(send);
+ fuzzer.expect(expect);
+ fuzzer.expectNoMoreFrames();
+ }
+ finally
+ {
+ fuzzer.close();
+ }
+ }
+
+ /**
+ * close with valid payload (payload length 2)
+ */
+ @Test
+ public void testCase7_3_3() throws Exception
+ {
+ List<WebSocketFrame> send = new ArrayList<>();
+ send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
+
+ List<WebSocketFrame> expect = new ArrayList<>();
+ expect.add(new CloseInfo(StatusCode.NORMAL).asFrame());
+
+ Fuzzer fuzzer = new Fuzzer(this);
+ try
+ {
+ fuzzer.connect();
+ fuzzer.setSendMode(Fuzzer.SendMode.BULK);
+ fuzzer.send(send);
+ fuzzer.expect(expect);
+ fuzzer.expectNoMoreFrames();
+ }
+ finally
+ {
+ fuzzer.close();
+ }
+ }
+
+ /**
+ * close with valid payload (with reason)
+ */
+ @Test
+ public void testCase7_3_4() throws Exception
+ {
+ List<WebSocketFrame> send = new ArrayList<>();
+ send.add(new CloseInfo(StatusCode.NORMAL,"Hic").asFrame());
+
+ List<WebSocketFrame> expect = new ArrayList<>();
+ expect.add(new CloseInfo(StatusCode.NORMAL,"Hic").asFrame());
+
+ Fuzzer fuzzer = new Fuzzer(this);
+ try
+ {
+ fuzzer.connect();
+ fuzzer.setSendMode(Fuzzer.SendMode.BULK);
+ fuzzer.send(send);
+ fuzzer.expect(expect);
+ fuzzer.expectNoMoreFrames();
+ }
+ finally
+ {
+ fuzzer.close();
+ }
+ }
+
+ /**
+ * close with valid payload (with 123 byte reason)
+ */
+ @Test
+ public void testCase7_3_5() throws Exception
+ {
+ byte utf[] = new byte[123];
+ Arrays.fill(utf,(byte)'!');
+ String reason = StringUtil.toUTF8String(utf,0,utf.length);
+
+ List<WebSocketFrame> send = new ArrayList<>();
+ send.add(new CloseInfo(StatusCode.NORMAL,reason).asFrame());
+
+ List<WebSocketFrame> expect = new ArrayList<>();
+ expect.add(new CloseInfo(StatusCode.NORMAL,reason).asFrame());
+
+ Fuzzer fuzzer = new Fuzzer(this);
+ try
+ {
+ fuzzer.connect();
+ fuzzer.setSendMode(Fuzzer.SendMode.BULK);
+ fuzzer.send(send);
+ fuzzer.expect(expect);
+ fuzzer.expectNoMoreFrames();
+ }
+ finally
+ {
+ fuzzer.close();
+ }
+ }
+
+ /**
+ * close with invalid payload (124 byte reason) (exceeds total allowed control frame payload bytes)
+ */
+ @Test
+ public void testCase7_3_6() throws Exception
+ {
+ ByteBuffer payload = ByteBuffer.allocate(256);
+ BufferUtil.clearToFill(payload);
+ payload.put((byte)0xE8);
+ payload.put((byte)0x03);
+ byte reason[] = new byte[124]; // too big
+ Arrays.fill(reason,(byte)'!');
+ payload.put(reason);
+ BufferUtil.flipToFlush(payload,0);
+
+ List<WebSocketFrame> send = new ArrayList<>();
+ WebSocketFrame close = new WebSocketFrame();
+ close.setPayload(payload);
+ close.setOpCode(OpCode.CLOSE); // set opcode after payload (to prevent early bad payload detection)
+ send.add(close);
+
+ List<WebSocketFrame> expect = new ArrayList<>();
+ expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame());
+
+ Fuzzer fuzzer = new Fuzzer(this);
+ try
+ {
+ fuzzer.connect();
+ fuzzer.setSendMode(Fuzzer.SendMode.BULK);
+ fuzzer.send(send);
+ fuzzer.expect(expect);
+ fuzzer.expectNoMoreFrames();
+ }
+ finally
+ {
+ fuzzer.close();
+ }
+ }
+
+ /**
+ * close with invalid payload (124 byte reason) (exceeds total allowed control frame payload bytes)
+ */
+ @Test
+ public void testCase7_5_1() throws Exception
+ {
+ ByteBuffer payload = ByteBuffer.allocate(256);
+ BufferUtil.clearToFill(payload);
+ payload.put((byte)0xE8); // normal close
+ payload.put((byte)0x03);
+ byte invalidUtf[] = Hex.asByteArray("CEBAE1BDB9CF83CEBCCEB5EDA080656469746564");
+ payload.put(invalidUtf);
+ BufferUtil.flipToFlush(payload,0);
+
+ List<WebSocketFrame> send = new ArrayList<>();
+ WebSocketFrame close = new WebSocketFrame();
+ close.setPayload(payload);
+ close.setOpCode(OpCode.CLOSE); // set opcode after payload (to prevent early bad payload detection)
+ send.add(close);
+
+ List<WebSocketFrame> expect = new ArrayList<>();
+ expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame());
+
+ Fuzzer fuzzer = new Fuzzer(this);
+ try
+ {
+ fuzzer.connect();
+ fuzzer.setSendMode(Fuzzer.SendMode.BULK);
+ fuzzer.send(send);
+ fuzzer.expect(expect);
+ fuzzer.expectNoMoreFrames();
+ }
+ finally
+ {
+ fuzzer.close();
+ }
+ }
+}
diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase7_9.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase7_9.java
deleted file mode 100644
index 6c70281a6b..0000000000
--- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase7_9.java
+++ /dev/null
@@ -1,185 +0,0 @@
-// ========================================================================
-// Copyright 2011-2012 Mort Bay Consulting Pty. Ltd.
-// ------------------------------------------------------------------------
-// All rights reserved. This program and the accompanying materials
-// are made available under the terms of the Eclipse Public License v1.0
-// and Apache License v2.0 which accompanies this distribution.
-//
-// The Eclipse Public License is available at
-// http://www.eclipse.org/legal/epl-v10.html
-//
-// The Apache License v2.0 is available at
-// http://www.opensource.org/licenses/apache2.0.php
-//
-// You may elect to redistribute this code under either of these licenses.
-//========================================================================
-package org.eclipse.jetty.websocket.server.ab;
-
-import static org.hamcrest.Matchers.*;
-
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-import org.eclipse.jetty.util.BufferUtil;
-import org.eclipse.jetty.util.StringUtil;
-import org.eclipse.jetty.websocket.protocol.CloseInfo;
-import org.eclipse.jetty.websocket.protocol.Generator;
-import org.eclipse.jetty.websocket.protocol.OpCode;
-import org.eclipse.jetty.websocket.protocol.WebSocketFrame;
-import org.eclipse.jetty.websocket.server.SimpleServletServer;
-import org.eclipse.jetty.websocket.server.blockhead.BlockheadClient;
-import org.eclipse.jetty.websocket.server.examples.MyEchoServlet;
-import org.eclipse.jetty.websocket.server.helper.IncomingFramesCapture;
-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(value = Parameterized.class)
-public class TestABCase7_9
-{
- private static SimpleServletServer server;
-
- @Parameters
- public static Collection<Integer[]> data()
- {
- List<Integer[]> data = new ArrayList<>();
- // @formatter:off
- data.add(new Integer[] { new Integer(0) });
- data.add(new Integer[] { new Integer(999) });
- data.add(new Integer[] { new Integer(1004) });
- data.add(new Integer[] { new Integer(1005) });
- data.add(new Integer[] { new Integer(1006) });
- data.add(new Integer[] { new Integer(1012) });
- data.add(new Integer[] { new Integer(1013) });
- data.add(new Integer[] { new Integer(1014) });
- data.add(new Integer[] { new Integer(1015) });
- data.add(new Integer[] { new Integer(1016) });
- data.add(new Integer[] { new Integer(1100) });
- data.add(new Integer[] { new Integer(2000) });
- data.add(new Integer[] { new Integer(2999) });
-
- // @formatter:on
- return data;
- }
-
- @BeforeClass
- public static void startServer() throws Exception
- {
- server = new SimpleServletServer(new MyEchoServlet());
- server.start();
- }
-
- @AfterClass
- public static void stopServer()
- {
- server.stop();
- }
-
- private int invalidStatusCode;
-
- public TestABCase7_9(Integer invalidStatusCode)
- {
- this.invalidStatusCode = invalidStatusCode;
- }
-
- private void remask(ByteBuffer buf, int position, byte[] mask)
- {
- int end = buf.position();
- int off;
- for (int i = position; i < end; i++)
- {
- off = i - position;
- // Mask each byte by its absolute position in the bytebuffer
- buf.put(i,(byte)(buf.get(i) ^ mask[off % 4]));
- }
- }
-
- /**
- * Test the requirement of issuing
- */
- @Test
- public void testCase7_9_XInvalidCloseStatusCodes() throws Exception
- {
- BlockheadClient client = new BlockheadClient(server.getServerUri());
- try
- {
- client.connect();
- client.sendStandardRequest();
- client.expectUpgradeResponse();
-
- ByteBuffer buf = ByteBuffer.allocate(Generator.OVERHEAD + 2);
- BufferUtil.clearToFill(buf);
-
- // Create Close Frame manually, as we are testing the server's behavior of a bad client.
- buf.put((byte)(0x80 | OpCode.CLOSE));
- buf.put((byte)(0x80 | 2));
- byte mask[] = new byte[]
- { 0x44, 0x44, 0x44, 0x44 };
- buf.put(mask);
- int position = buf.position();
- buf.putChar((char)this.invalidStatusCode);
- remask(buf,position,mask);
- BufferUtil.flipToFlush(buf,0);
- client.writeRaw(buf);
-
- // Read frame (hopefully text frame)
- IncomingFramesCapture capture = client.readFrames(1,TimeUnit.MILLISECONDS,500);
- WebSocketFrame closeFrame = capture.getFrames().pop();
- Assert.assertThat("CloseFrame.status code",new CloseInfo(closeFrame).getStatusCode(),is(1002));
- }
- finally
- {
- client.close();
- }
- }
-
- /**
- * Test the requirement of issuing
- */
- @Test
- public void testCase7_9_XInvalidCloseStatusCodesWithReason() throws Exception
- {
- String reason = "closing time";
-
- BlockheadClient client = new BlockheadClient(server.getServerUri());
- try
- {
- client.connect();
- client.sendStandardRequest();
- client.expectUpgradeResponse();
-
- ByteBuffer buf = ByteBuffer.allocate(Generator.OVERHEAD + 2);
- BufferUtil.clearToFill(buf);
-
- // Create Close Frame manually, as we are testing the server's behavior of a bad client.
- buf.put((byte)(0x80 | OpCode.CLOSE));
- buf.put((byte)(0x80 | (2 + reason.length())));
- byte mask[] = new byte[]
- { 0x44, 0x44, 0x44, 0x44 };
- buf.put(mask);
- int position = buf.position();
- buf.putChar((char)this.invalidStatusCode);
- buf.put(reason.getBytes(StringUtil.__UTF8_CHARSET));
- remask(buf,position,mask);
- BufferUtil.flipToFlush(buf,0);
- client.writeRaw(buf);
-
- // Read frame (hopefully text frame)
- IncomingFramesCapture capture = client.readFrames(1,TimeUnit.MILLISECONDS,500);
- WebSocketFrame closeFrame = capture.getFrames().pop();
- Assert.assertThat("CloseFrame.status code",new CloseInfo(closeFrame).getStatusCode(),is(1002));
- }
- finally
- {
- client.close();
- }
- }
-
-}
diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase7_BadStatusCodes.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase7_BadStatusCodes.java
new file mode 100644
index 0000000000..6d490355a6
--- /dev/null
+++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase7_BadStatusCodes.java
@@ -0,0 +1,129 @@
+package org.eclipse.jetty.websocket.server.ab;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collection;
+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.protocol.CloseInfo;
+import org.eclipse.jetty.websocket.protocol.OpCode;
+import org.eclipse.jetty.websocket.protocol.WebSocketFrame;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+/**
+ * Test Bad Close Status Codes
+ */
+@RunWith(value = Parameterized.class)
+public class TestABCase7_BadStatusCodes extends AbstractABCase
+{
+ private static final Logger LOG = Log.getLogger(TestABCase7_GoodStatusCodes.class);
+
+ @Parameters
+ public static Collection<Object[]> data()
+ {
+ // The various Good UTF8 sequences as a String (hex form)
+ List<Object[]> data = new ArrayList<>();
+
+ // @formatter:off
+ data.add(new Object[] { "7.9.1", 0 });
+ data.add(new Object[] { "7.9.2", 999 });
+ data.add(new Object[] { "7.9.3", 1004 });
+ data.add(new Object[] { "7.9.4", 1005 });
+ data.add(new Object[] { "7.9.5", 1006 });
+ data.add(new Object[] { "7.9.6", 1012 });
+ data.add(new Object[] { "7.9.7", 1013 });
+ data.add(new Object[] { "7.9.8", 1014 });
+ data.add(new Object[] { "7.9.9", 1015 });
+ data.add(new Object[] { "7.9.10", 1016 });
+ data.add(new Object[] { "7.9.11", 1100 });
+ data.add(new Object[] { "7.9.12", 2000 });
+ data.add(new Object[] { "7.9.13", 2999 });
+ // -- close status codes, with undefined events in spec
+ data.add(new Object[] { "7.13.1", 5000 });
+ data.add(new Object[] { "7.13.2", 65536 });
+ // @formatter:on
+
+ return data;
+ }
+
+ private final int statusCode;
+
+ public TestABCase7_BadStatusCodes(String testId, int statusCode)
+ {
+ LOG.debug("Test ID: {}",testId);
+ this.statusCode = statusCode;
+ }
+
+ /**
+ * just the close code, no reason
+ */
+ @Test
+ public void testBadStatusCode() throws Exception
+ {
+ ByteBuffer payload = ByteBuffer.allocate(256);
+ BufferUtil.clearToFill(payload);
+ payload.putChar((char)statusCode);
+ BufferUtil.flipToFlush(payload,0);
+
+ List<WebSocketFrame> send = new ArrayList<>();
+ send.add(new WebSocketFrame(OpCode.CLOSE).setPayload(payload.slice()));
+
+ List<WebSocketFrame> expect = new ArrayList<>();
+ expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame());
+
+ Fuzzer fuzzer = new Fuzzer(this);
+ try
+ {
+ fuzzer.connect();
+ fuzzer.setSendMode(Fuzzer.SendMode.BULK);
+ fuzzer.send(send);
+ fuzzer.expect(expect);
+ fuzzer.expectNoMoreFrames();
+ }
+ finally
+ {
+ fuzzer.close();
+ }
+ }
+
+ /**
+ * the bad close code, with reason
+ */
+ @Test
+ public void testBadStatusCodeWithReason() throws Exception
+ {
+ ByteBuffer payload = ByteBuffer.allocate(256);
+ BufferUtil.clearToFill(payload);
+ payload.putChar((char)statusCode);
+ payload.put(StringUtil.getBytes("Reason"));
+ BufferUtil.flipToFlush(payload,0);
+
+ List<WebSocketFrame> send = new ArrayList<>();
+ send.add(new WebSocketFrame(OpCode.CLOSE).setPayload(payload.slice()));
+
+ List<WebSocketFrame> expect = new ArrayList<>();
+ expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame());
+
+ Fuzzer fuzzer = new Fuzzer(this);
+ try
+ {
+ fuzzer.connect();
+ fuzzer.setSendMode(Fuzzer.SendMode.BULK);
+ fuzzer.send(send);
+ fuzzer.expect(expect);
+ fuzzer.expectNoMoreFrames();
+ }
+ finally
+ {
+ fuzzer.close();
+ }
+ }
+}
diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase7_GoodStatusCodes.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase7_GoodStatusCodes.java
new file mode 100644
index 0000000000..cbb94bf0f8
--- /dev/null
+++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase7_GoodStatusCodes.java
@@ -0,0 +1,124 @@
+package org.eclipse.jetty.websocket.server.ab;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collection;
+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.protocol.OpCode;
+import org.eclipse.jetty.websocket.protocol.WebSocketFrame;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+/**
+ * Test Good Close Status Codes
+ */
+@RunWith(value = Parameterized.class)
+public class TestABCase7_GoodStatusCodes extends AbstractABCase
+{
+ private static final Logger LOG = Log.getLogger(TestABCase7_GoodStatusCodes.class);
+
+ @Parameters
+ public static Collection<Object[]> data()
+ {
+ // The various Good UTF8 sequences as a String (hex form)
+ List<Object[]> data = new ArrayList<>();
+
+ // @formatter:off
+ data.add(new Object[] { "7.7.1", 1000 });
+ data.add(new Object[] { "7.7.2", 1001 });
+ data.add(new Object[] { "7.7.3", 1002 });
+ data.add(new Object[] { "7.7.4", 1003 });
+ data.add(new Object[] { "7.7.5", 1007 });
+ data.add(new Object[] { "7.7.6", 1008 });
+ data.add(new Object[] { "7.7.7", 1009 });
+ data.add(new Object[] { "7.7.8", 1010 });
+ data.add(new Object[] { "7.7.9", 1011 });
+ data.add(new Object[] { "7.7.10", 3000 });
+ data.add(new Object[] { "7.7.11", 3999 });
+ data.add(new Object[] { "7.7.12", 4000 });
+ data.add(new Object[] { "7.7.13", 4999 });
+ // @formatter:on
+
+ return data;
+ }
+
+ private final int statusCode;
+
+ public TestABCase7_GoodStatusCodes(String testId, int statusCode)
+ {
+ LOG.debug("Test ID: {}",testId);
+ this.statusCode = statusCode;
+ }
+
+ /**
+ * just the close code, no reason
+ */
+ @Test
+ public void testStatusCode() throws Exception
+ {
+ ByteBuffer payload = ByteBuffer.allocate(256);
+ BufferUtil.clearToFill(payload);
+ payload.putChar((char)statusCode);
+ BufferUtil.flipToFlush(payload,0);
+
+ List<WebSocketFrame> send = new ArrayList<>();
+ send.add(new WebSocketFrame(OpCode.CLOSE).setPayload(payload.slice()));
+
+ List<WebSocketFrame> expect = new ArrayList<>();
+ expect.add(new WebSocketFrame(OpCode.CLOSE).setPayload(payload.slice()));
+
+ Fuzzer fuzzer = new Fuzzer(this);
+ try
+ {
+ fuzzer.connect();
+ fuzzer.setSendMode(Fuzzer.SendMode.BULK);
+ fuzzer.send(send);
+ fuzzer.expect(expect);
+ fuzzer.expectNoMoreFrames();
+ }
+ finally
+ {
+ fuzzer.close();
+ }
+ }
+
+ /**
+ * the good close code, with reason
+ */
+ @Test
+ public void testStatusCodeWithReason() throws Exception
+ {
+ ByteBuffer payload = ByteBuffer.allocate(256);
+ BufferUtil.clearToFill(payload);
+ payload.putChar((char)statusCode);
+ payload.put(StringUtil.getBytes("Reason"));
+ BufferUtil.flipToFlush(payload,0);
+
+ List<WebSocketFrame> send = new ArrayList<>();
+ send.add(new WebSocketFrame(OpCode.CLOSE).setPayload(payload.slice()));
+
+ List<WebSocketFrame> expect = new ArrayList<>();
+ expect.add(new WebSocketFrame(OpCode.CLOSE).setPayload(payload.slice()));
+
+ Fuzzer fuzzer = new Fuzzer(this);
+ try
+ {
+ fuzzer.connect();
+ fuzzer.setSendMode(Fuzzer.SendMode.BULK);
+ fuzzer.send(send);
+ fuzzer.expect(expect);
+ fuzzer.expectNoMoreFrames();
+ }
+ finally
+ {
+ fuzzer.close();
+ }
+ }
+}

Back to the top