diff --git a/jetty-websocket/websocket-core/src/test/java/org/eclipse/jetty/websocket/protocol/AcceptHashTest.java b/jetty-websocket/websocket-core/src/test/java/org/eclipse/jetty/websocket/protocol/AcceptHashTest.java new file mode 100644 index 00000000000..32c31ca69d0 --- /dev/null +++ b/jetty-websocket/websocket-core/src/test/java/org/eclipse/jetty/websocket/protocol/AcceptHashTest.java @@ -0,0 +1,15 @@ +package org.eclipse.jetty.websocket.protocol; + +import static org.hamcrest.Matchers.*; + +import org.junit.Assert; +import org.junit.Test; + +public class AcceptHashTest +{ + @Test + public void testHash() + { + Assert.assertThat(AcceptHash.hashKey("dGhlIHNhbXBsZSBub25jZQ=="),is("s3pPLMBiTxaQ9kYGzzhZRbK+xOo=")); + } +} diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/DeflateExtensionTest.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/DeflateExtensionTest.java new file mode 100644 index 00000000000..873333b3dce --- /dev/null +++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/DeflateExtensionTest.java @@ -0,0 +1,72 @@ +package org.eclipse.jetty.websocket.server; + +import static org.hamcrest.Matchers.*; + +import java.util.Queue; +import java.util.concurrent.TimeUnit; + +import org.eclipse.jetty.websocket.protocol.FrameBuilder; +import org.eclipse.jetty.websocket.protocol.WebSocketFrame; +import org.eclipse.jetty.websocket.server.WebSocketServletRFCTest.RFCServlet; +import org.eclipse.jetty.websocket.server.blockhead.BlockheadClient; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class DeflateExtensionTest +{ + private static SimpleServletServer server; + + @BeforeClass + public static void startServer() throws Exception + { + server = new SimpleServletServer(new RFCServlet()); + server.start(); + } + + @AfterClass + public static void stopServer() + { + server.stop(); + } + + @Test + public void testDeflateFrameExtension() throws Exception + { + BlockheadClient client = new BlockheadClient(server.getServerUri()); + client.clearExtensions(); + client.addExtensions("x-deflate-frame;minLength=64"); + // client.addExtensions("fragment;minFragments=2"); + client.setProtocols("echo"); + + try + { + // Make sure the read times out if there are problems with the implementation + client.setTimeout(TimeUnit.SECONDS,1); + client.connect(); + client.sendStandardRequest(); + String resp = client.expectUpgradeResponse(); + + Assert.assertThat("Response",resp,containsString("x-deflate")); + + // Server sends a big message + String text = "0123456789ABCDEF "; + text = text + text + text + text; + text = text + text + text + text; + text = text + text + text + text + 'X'; + + client.write(FrameBuilder.text(text).asFrame()); + + // TODO: use socket that captures frame payloads to verify fragmentation + + Queue frames = client.readFrames(1,TimeUnit.MILLISECONDS,1000); + WebSocketFrame frame = frames.remove(); + Assert.assertThat("TEXT.payload",frame.getPayloadAsUTF8(),is(text)); + } + finally + { + client.close(); + } + } +} diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/FragmentExtensionTest.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/FragmentExtensionTest.java new file mode 100644 index 00000000000..327bab765f5 --- /dev/null +++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/FragmentExtensionTest.java @@ -0,0 +1,67 @@ +package org.eclipse.jetty.websocket.server; + +import static org.hamcrest.Matchers.*; + +import java.util.Queue; +import java.util.concurrent.TimeUnit; + +import org.eclipse.jetty.websocket.protocol.FrameBuilder; +import org.eclipse.jetty.websocket.protocol.WebSocketFrame; +import org.eclipse.jetty.websocket.server.WebSocketServletRFCTest.RFCServlet; +import org.eclipse.jetty.websocket.server.blockhead.BlockheadClient; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class FragmentExtensionTest +{ + private static SimpleServletServer server; + + @BeforeClass + public static void startServer() throws Exception + { + server = new SimpleServletServer(new RFCServlet()); + server.start(); + } + + @AfterClass + public static void stopServer() + { + server.stop(); + } + + @Test + public void testFragmentExtension() throws Exception + { + + BlockheadClient client = new BlockheadClient(server.getServerUri()); + client.clearExtensions(); + client.addExtensions("fragment;maxLength=4;minFragments=7"); + client.setProtocols("onConnect"); + + try + { + // Make sure the read times out if there are problems with the implementation + client.setTimeout(TimeUnit.SECONDS,1); + client.connect(); + client.sendStandardRequest(); + String resp = client.expectUpgradeResponse(); + + Assert.assertThat("Response",resp,containsString("fragment")); + + String msg = "Sent as a long message that should be split"; + client.write(FrameBuilder.text(msg).asFrame()); + + // TODO: use socket that captures frame counts to verify fragmentation + + Queue frames = client.readFrames(1,TimeUnit.MILLISECONDS,1000); + WebSocketFrame frame = frames.remove(); + Assert.assertThat("TEXT.payload",frame.getPayloadAsUTF8(),is(msg)); + } + finally + { + client.close(); + } + } +} diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/IdentityExtensionTest.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/IdentityExtensionTest.java new file mode 100644 index 00000000000..1936bedbdea --- /dev/null +++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/IdentityExtensionTest.java @@ -0,0 +1,64 @@ +package org.eclipse.jetty.websocket.server; + +import static org.hamcrest.Matchers.*; + +import java.util.Queue; +import java.util.concurrent.TimeUnit; + +import org.eclipse.jetty.websocket.protocol.FrameBuilder; +import org.eclipse.jetty.websocket.protocol.WebSocketFrame; +import org.eclipse.jetty.websocket.server.WebSocketServletRFCTest.RFCServlet; +import org.eclipse.jetty.websocket.server.blockhead.BlockheadClient; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class IdentityExtensionTest +{ + private static SimpleServletServer server; + + @BeforeClass + public static void startServer() throws Exception + { + server = new SimpleServletServer(new RFCServlet()); + server.start(); + } + + @AfterClass + public static void stopServer() + { + server.stop(); + } + + @Test + public void testIdentityExtension() throws Exception + { + BlockheadClient client = new BlockheadClient(server.getServerUri()); + client.clearExtensions(); + client.addExtensions("identity;param=0"); + client.addExtensions("identity;param=1, identity ; param = '2' ; other = ' some = value '"); + client.setProtocols("onConnect"); + + try + { + // Make sure the read times out if there are problems with the implementation + client.setTimeout(TimeUnit.SECONDS,1); + client.connect(); + client.sendStandardRequest(); + String resp = client.expectUpgradeResponse(); + + Assert.assertThat("Response",resp,containsString("identity")); + + client.write(FrameBuilder.text("Hello").asFrame()); + + Queue frames = client.readFrames(1,TimeUnit.MILLISECONDS,1000); + WebSocketFrame frame = frames.remove(); + Assert.assertThat("TEXT.payload",frame.getPayloadAsUTF8(),is("Hello")); + } + finally + { + client.close(); + } + } +} diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketMessageRFC6455Test.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketMessageRFC6455Test.java index 8792e09f33d..3e8330a1d8a 100644 --- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketMessageRFC6455Test.java +++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketMessageRFC6455Test.java @@ -27,9 +27,6 @@ import java.net.SocketException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; -import java.util.zip.Deflater; -import java.util.zip.Inflater; import org.eclipse.jetty.server.SelectChannelConnector; import org.eclipse.jetty.server.Server; @@ -37,7 +34,6 @@ import org.eclipse.jetty.server.handler.DefaultHandler; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.FutureCallback; import org.eclipse.jetty.util.StringUtil; -import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.Utf8StringBuilder; import org.eclipse.jetty.websocket.annotations.OnWebSocketClose; import org.eclipse.jetty.websocket.annotations.OnWebSocketConnect; @@ -45,7 +41,6 @@ import org.eclipse.jetty.websocket.annotations.OnWebSocketMessage; import org.eclipse.jetty.websocket.annotations.WebSocket; import org.eclipse.jetty.websocket.api.StatusCode; import org.eclipse.jetty.websocket.api.WebSocketConnection; -import org.eclipse.jetty.websocket.protocol.AcceptHash; import org.eclipse.jetty.websocket.protocol.OpCode; import org.junit.AfterClass; import org.junit.Assert; @@ -263,699 +258,6 @@ public class WebSocketMessageRFC6455Test } } - @Test - public void testBinaryAggregate() throws Exception - { - Socket socket = new Socket("localhost",__connector.getLocalPort()); - OutputStream output = socket.getOutputStream(); - output.write(("GET /chat HTTP/1.1\r\n" + "Host: server.example.com\r\n" + "Upgrade: websocket\r\n" + "Connection: Upgrade\r\n" - + "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" + "Sec-WebSocket-Origin: http://example.com\r\n" + "Sec-WebSocket-Protocol: aggregate\r\n" - + "Sec-WebSocket-Version: " + WSVERSION + "\r\n" + "\r\n").getBytes("ISO-8859-1")); - output.flush(); - - socket.setSoTimeout(1000); - InputStream input = socket.getInputStream(); - - lookFor("HTTP/1.1 101 Switching Protocols\r\n",input); - skipTo("Sec-WebSocket-Accept: ",input); - lookFor("s3pPLMBiTxaQ9kYGzzhZRbK+xOo=",input); - skipTo("\r\n\r\n",input); - - assertTrue(__serverWebSocket.awaitConnected(1000)); - assertNotNull(__serverWebSocket.connection); - - output.write(OpCode.BINARY.getCode()); - output.write(0x8a); - output.write(0xff); - output.write(0xff); - output.write(0xff); - output.write(0xff); - byte[] bytes = "0123456789".getBytes(StringUtil.__ISO_8859_1); - for (byte b : bytes) - { - output.write(b ^ 0xff); - } - output.flush(); - - output.write(0x80); - output.write(0x8a); - output.write(0xff); - output.write(0xff); - output.write(0xff); - output.write(0xff); - for (byte b : bytes) - { - output.write(b ^ 0xff); - } - output.flush(); - - assertEquals(0x80 + OpCode.BINARY.getCode(),input.read()); - assertEquals(20,input.read()); - lookFor("01234567890123456789",input); - } - - @Test - public void testBlockedConsumer() throws Exception - { - Socket socket = new Socket("localhost",__connector.getLocalPort()); - OutputStream output = socket.getOutputStream(); - - byte[] bytes = "This is a long message of text that we will send again and again".getBytes(StringUtil.__ISO_8859_1); - byte[] mesg = new byte[bytes.length + 6]; - mesg[0] = (byte)(0x80 + OpCode.TEXT.getCode()); - mesg[1] = (byte)(0x80 + bytes.length); - mesg[2] = (byte)0xff; - mesg[3] = (byte)0xff; - mesg[4] = (byte)0xff; - mesg[5] = (byte)0xff; - for (int i = 0; i < bytes.length; i++) - { - mesg[6 + i] = (byte)(bytes[i] ^ 0xff); - } - - final int count = 100000; - - output.write(("GET /chat HTTP/1.1\r\n" + "Host: server.example.com\r\n" + "Upgrade: websocket\r\n" + "Connection: Upgrade\r\n" - + "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" + "Sec-WebSocket-Origin: http://example.com\r\n" + "Sec-WebSocket-Protocol: latch\r\n" - + "Sec-WebSocket-Version: " + WSVERSION + "\r\n" + "\r\n").getBytes("ISO-8859-1")); - output.flush(); - - // Make sure the read times out if there are problems with the implementation - socket.setSoTimeout(60000); - - InputStream input = socket.getInputStream(); - - lookFor("HTTP/1.1 101 Switching Protocols\r\n",input); - skipTo("Sec-WebSocket-Accept: ",input); - lookFor("s3pPLMBiTxaQ9kYGzzhZRbK+xOo=",input); - skipTo("\r\n\r\n",input); - - assertTrue(__serverWebSocket.awaitConnected(1000)); - assertNotNull(__serverWebSocket.connection); - - // Send and receive 1 message - output.write(mesg); - output.flush(); - while (__textCount.get() == 0) - { - Thread.sleep(10); - } - - // unblock the latch in 4s - new Thread() - { - @Override - public void run() - { - try - { - Thread.sleep(4000); - __latch.countDown(); - // System.err.println("latched"); - } - catch (Exception e) - { - e.printStackTrace(); - } - } - }.start(); - - // Send enough messages to fill receive buffer - long max = 0; - long start = System.currentTimeMillis(); - for (int i = 0; i < count; i++) - { - output.write(mesg); - if ((i % 100) == 0) - { - // System.err.println(">>> "+i); - output.flush(); - - long now = System.currentTimeMillis(); - long duration = now - start; - start = now; - if (max < duration) - { - max = duration; - } - } - } - - Thread.sleep(50); - while (__textCount.get() < (count + 1)) - { - System.err.println(__textCount.get() + "<" + (count + 1)); - Thread.sleep(10); - } - assertEquals(count + 1,__textCount.get()); // all messages - assertTrue(max > 2000); // was blocked - } - - @Test - public void testBlockedProducer() throws Exception - { - final Socket socket = new Socket("localhost",__connector.getLocalPort()); - OutputStream output = socket.getOutputStream(); - - final int count = 100000; - - output.write(("GET /chat HTTP/1.1\r\n" + "Host: server.example.com\r\n" + "Upgrade: websocket\r\n" + "Connection: Upgrade\r\n" - + "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" + "Sec-WebSocket-Origin: http://example.com\r\n" + "Sec-WebSocket-Protocol: latch\r\n" - + "Sec-WebSocket-Version: " + WSVERSION + "\r\n" + "\r\n").getBytes("ISO-8859-1")); - output.flush(); - - // Make sure the read times out if there are problems with the implementation - socket.setSoTimeout(60000); - - InputStream input = socket.getInputStream(); - - lookFor("HTTP/1.1 101 Switching Protocols\r\n",input); - skipTo("Sec-WebSocket-Accept: ",input); - lookFor("s3pPLMBiTxaQ9kYGzzhZRbK+xOo=",input); - skipTo("\r\n\r\n",input); - - assertTrue(__serverWebSocket.awaitConnected(1000)); - assertNotNull(__serverWebSocket.connection); - __latch.countDown(); - - // wait 2s and then consume messages - final AtomicLong totalB = new AtomicLong(); - new Thread() - { - @Override - public void run() - { - try - { - Thread.sleep(2000); - - byte[] recv = new byte[32 * 1024]; - - int len = 0; - while (len >= 0) - { - totalB.addAndGet(len); - len = socket.getInputStream().read(recv,0,recv.length); - Thread.sleep(10); - } - } - catch (Exception e) - { - e.printStackTrace(); - } - } - }.start(); - - // Send enough messages to fill receive buffer - long max = 0; - long start = System.currentTimeMillis(); - String mesg = "How Now Brown Cow"; - for (int i = 0; i < count; i++) - { - __serverWebSocket.connection.write(null,fnf(),mesg); - if ((i % 100) == 0) - { - output.flush(); - - long now = System.currentTimeMillis(); - long duration = now - start; - start = now; - if (max < duration) - { - max = duration; - } - } - } - - while (totalB.get() < (count * (mesg.length() + 2))) - { - Thread.sleep(100); - } - - assertEquals(count * (mesg.length() + 2),totalB.get()); // all messages - Assert.assertThat("Was blocked (max time)",max,greaterThan(1000L)); // was blocked - } - - @Test - public void testCloseIn() throws Exception - { - int[][] tests = - { - { -1, 0, -1 }, - { -1, 0, -1 }, - { 1000, 2, 1000 }, - { 1000, 2 + 4, 1000 }, - { 1005, 2 + 23, 1002 }, - { 1005, 2 + 23, 1002 }, - { 1006, 2 + 23, 1002 }, - { 1006, 2 + 23, 1002 }, - { 4000, 2, 4000 }, - { 4000, 2 + 4, 4000 }, - { 9000, 2 + 23, 1002 }, - { 9000, 2 + 23, 1002 } }; - - String[] mesg = - { "", "", "", "mesg", "", "mesg", "", "mesg", "", "mesg", "", "mesg" }; - - String[] resp = - { "", "", "", "mesg", "Invalid close code 1005", "Invalid close code 1005", "Invalid close code 1006", "Invalid close code 1006", "", "mesg", - "Invalid close code 9000", "Invalid close code 9000" }; - - for (int t = 0; t < tests.length; t++) - { - String tst = "" + t; - Socket socket = new Socket("localhost",__connector.getLocalPort()); - OutputStream output = socket.getOutputStream(); - output.write(("GET /chat HTTP/1.1\r\n" + "Host: server.example.com\r\n" + "Upgrade: websocket\r\n" + "Connection: Upgrade\r\n" - + "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" + "Sec-WebSocket-Origin: http://example.com\r\n" + "Sec-WebSocket-Protocol: chat\r\n" - + "Sec-WebSocket-Version: " + WSVERSION + "\r\n" + "\r\n").getBytes("ISO-8859-1")); - output.flush(); - - socket.setSoTimeout(100000); - InputStream input = socket.getInputStream(); - - lookFor("HTTP/1.1 101 Switching Protocols\r\n",input); - skipTo("Sec-WebSocket-Accept: ",input); - lookFor("s3pPLMBiTxaQ9kYGzzhZRbK+xOo=",input); - skipTo("\r\n\r\n",input); - - assertTrue(__serverWebSocket.awaitConnected(1000)); - assertNotNull(__serverWebSocket.connection); - - int code = tests[t][0]; - String m = mesg[t]; - - output.write(0x88); - output.write(0x80 + (code <= 0?0:(2 + m.length()))); - output.write(0x00); - output.write(0x00); - output.write(0x00); - output.write(0x00); - - if (code > 0) - { - output.write(code / 0x100); - output.write(code % 0x100); - output.write(m.getBytes()); - } - output.flush(); - - __serverWebSocket.awaitDisconnected(1000); - - byte[] buf = new byte[128]; - int len = input.read(buf); - - assertEquals(tst,2 + tests[t][1],len); - assertEquals(tst,(byte)0x88,buf[0]); - - if (len >= 4) - { - code = ((0xff & buf[2]) * 0x100) + (0xff & buf[3]); - assertEquals(tst,tests[t][2],code); - - if (len > 4) - { - m = new String(buf,4,len - 4,"UTF-8"); - assertEquals(tst,resp[t],m); - } - } - else - { - assertEquals(tst,tests[t][2],-1); - } - - len = input.read(buf); - assertEquals(tst,-1,len); - } - } - - @Test - public void testCloseOut() throws Exception - { - int[][] tests = - { - { -1, 0, -1 }, - { -1, 0, -1 }, - { 0, 2, 1000 }, - { 0, 2 + 4, 1000 }, - { 1000, 2, 1000 }, - { 1000, 2 + 4, 1000 }, - { 1005, 0, -1 }, - { 1005, 0, -1 }, - { 1006, 0, -1 }, - { 1006, 0, -1 }, - { 9000, 2, 9000 }, - { 9000, 2 + 4, 9000 } }; - - String[] mesg = - { null, "Not Sent", null, "mesg", null, "mesg", null, "mesg", null, "mesg", null, "mesg" }; - - for (int t = 0; t < tests.length; t++) - { - String tst = "" + t; - Socket socket = new Socket("localhost",__connector.getLocalPort()); - OutputStream output = socket.getOutputStream(); - output.write(("GET /chat HTTP/1.1\r\n" + "Host: server.example.com\r\n" + "Upgrade: websocket\r\n" + "Connection: Upgrade\r\n" - + "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" + "Sec-WebSocket-Origin: http://example.com\r\n" + "Sec-WebSocket-Protocol: chat\r\n" - + "Sec-WebSocket-Version: " + WSVERSION + "\r\n" + "\r\n").getBytes("ISO-8859-1")); - output.flush(); - - socket.setSoTimeout(100000); - InputStream input = socket.getInputStream(); - - lookFor("HTTP/1.1 101 Switching Protocols\r\n",input); - skipTo("Sec-WebSocket-Accept: ",input); - lookFor("s3pPLMBiTxaQ9kYGzzhZRbK+xOo=",input); - skipTo("\r\n\r\n",input); - - assertTrue(__serverWebSocket.awaitConnected(1000)); - assertNotNull(__serverWebSocket.connection); - - __serverWebSocket.connection.close(tests[t][0],mesg[t]); - - byte[] buf = new byte[128]; - int len = input.read(buf); - assertEquals(tst,2 + tests[t][1],len); - assertEquals(tst,(byte)0x88,buf[0]); - - if (len >= 4) - { - int code = ((0xff & buf[2]) * 0x100) + (0xff & buf[3]); - assertEquals(tst,tests[t][2],code); - - if (len > 4) - { - String m = new String(buf,4,len - 4,"UTF-8"); - assertEquals(tst,mesg[t],m); - } - } - else - { - assertEquals(tst,tests[t][2],-1); - } - - try - { - output.write(0x88); - output.write(0x80); - output.write(0x00); - output.write(0x00); - output.write(0x00); - output.write(0x00); - output.flush(); - } - catch (IOException e) - { - System.err.println("socket " + socket); - throw e; - } - - len = input.read(buf); - assertEquals(tst,-1,len); - } - } - - @Test - public void testDeflateFrameExtension() throws Exception - { - Socket socket = new Socket("localhost",__connector.getLocalPort()); - OutputStream output = socket.getOutputStream(); - output.write(("GET /chat HTTP/1.1\r\n" + "Host: server.example.com\r\n" + "Upgrade: websocket\r\n" + "Connection: Upgrade\r\n" - + "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" + "Sec-WebSocket-Origin: http://example.com\r\n" + "Sec-WebSocket-Protocol: echo\r\n" - + "Sec-WebSocket-Version: " + WSVERSION + "\r\n" + "Sec-WebSocket-Extensions: x-deflate-frame;minLength=64\r\n" - + "Sec-WebSocket-Extensions: fragment;minFragments=2\r\n" + "\r\n").getBytes("ISO-8859-1")); - output.flush(); - - // Make sure the read times out if there are problems with the implementation - socket.setSoTimeout(1000); - - InputStream input = socket.getInputStream(); - lookFor("HTTP/1.1 101 Switching Protocols\r\n",input); - skipTo("Sec-WebSocket-Accept: ",input); - lookFor("s3pPLMBiTxaQ9kYGzzhZRbK+xOo=",input); - skipTo("Sec-WebSocket-Extensions: ",input); - lookFor("x-deflate-frame;minLength=64",input); - skipTo("Sec-WebSocket-Extensions: ",input); - lookFor("fragment;",input); - skipTo("\r\n\r\n",input); - - assertTrue(__serverWebSocket.awaitConnected(1000)); - assertNotNull(__serverWebSocket.connection); - - // Server sends a big message - String text = "0123456789ABCDEF "; - text = text + text + text + text; - text = text + text + text + text; - text = text + text + text + text + 'X'; - byte[] data = text.getBytes("utf-8"); - Deflater deflater = new Deflater(); - deflater.setInput(data); - deflater.finish(); - byte[] buf = new byte[data.length]; - - buf[0] = ((byte)0x7e); - buf[1] = (byte)(data.length >> 8); - buf[2] = (byte)(data.length & 0xff); - - int l = deflater.deflate(buf,3,buf.length - 3); - - assertTrue(deflater.finished()); - - output.write(0xC1); - output.write((byte)(0x80 | (0xff & (l + 3)))); - output.write(0x00); - output.write(0x00); - output.write(0x00); - output.write(0x00); - output.write(buf,0,l + 3); - output.flush(); - - assertEquals(0x40 + OpCode.TEXT.getCode(),input.read()); - assertEquals(0x20 + 3,input.read()); - assertEquals(0x7e,input.read()); - assertEquals(0x02,input.read()); - assertEquals(0x20,input.read()); - - byte[] raw = new byte[32]; - assertEquals(32,input.read(raw)); - - Inflater inflater = new Inflater(); - inflater.setInput(raw); - - byte[] result = new byte[544]; - assertEquals(544,inflater.inflate(result)); - assertEquals(TypeUtil.toHexString(data,0,544),TypeUtil.toHexString(result)); - - assertEquals((byte)0xC0,(byte)input.read()); - assertEquals(0x21 + 3,input.read()); - assertEquals(0x7e,input.read()); - assertEquals(0x02,input.read()); - assertEquals(0x21,input.read()); - - assertEquals(32,input.read(raw)); - - inflater.reset(); - inflater.setInput(raw); - result = new byte[545]; - assertEquals(545,inflater.inflate(result)); - assertEquals(TypeUtil.toHexString(data,544,545),TypeUtil.toHexString(result)); - - } - - @Test - public void testFragmentExtension() throws Exception - { - Socket socket = new Socket("localhost",__connector.getLocalPort()); - OutputStream output = socket.getOutputStream(); - output.write(("GET /chat HTTP/1.1\r\n" + "Host: server.example.com\r\n" + "Upgrade: websocket\r\n" + "Connection: Upgrade\r\n" - + "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" + "Sec-WebSocket-Origin: http://example.com\r\n" + "Sec-WebSocket-Protocol: onConnect\r\n" - + "Sec-WebSocket-Version: " + WSVERSION + "\r\n" + "Sec-WebSocket-Extensions: fragment;maxLength=4;minFragments=7\r\n" + "\r\n") - .getBytes("ISO-8859-1")); - output.flush(); - - // Make sure the read times out if there are problems with the implementation - socket.setSoTimeout(1000); - - InputStream input = socket.getInputStream(); - lookFor("HTTP/1.1 101 Switching Protocols\r\n",input); - skipTo("Sec-WebSocket-Accept: ",input); - lookFor("s3pPLMBiTxaQ9kYGzzhZRbK+xOo=",input); - skipTo("Sec-WebSocket-Extensions: ",input); - lookFor("fragment;",input); - skipTo("\r\n\r\n",input); - - assertTrue(__serverWebSocket.awaitConnected(1000)); - assertNotNull(__serverWebSocket.connection); - - assertEquals(0x01,input.read()); - assertEquals(0x04,input.read()); - lookFor("sent",input); - assertEquals(0x00,input.read()); - assertEquals(0x04,input.read()); - lookFor(" on ",input); - assertEquals(0x00,input.read()); - assertEquals(0x04,input.read()); - lookFor("conn",input); - assertEquals(0x00,input.read()); - assertEquals(0x01,input.read()); - lookFor("e",input); - assertEquals(0x00,input.read()); - assertEquals(0x01,input.read()); - lookFor("c",input); - assertEquals(0x00,input.read()); - assertEquals(0x00,input.read()); - assertEquals(0x80,input.read()); - assertEquals(0x01,input.read()); - lookFor("t",input); - } - - @Test - public void testHash() - { - assertEquals("s3pPLMBiTxaQ9kYGzzhZRbK+xOo=",AcceptHash.hashKey("dGhlIHNhbXBsZSBub25jZQ==")); - } - - @Test - public void testIdentityExtension() throws Exception - { - Socket socket = new Socket("localhost",__connector.getLocalPort()); - OutputStream output = socket.getOutputStream(); - output.write(("GET /chat HTTP/1.1\r\n" + "Host: server.example.com\r\n" + "Upgrade: websocket\r\n" + "Connection: Upgrade\r\n" - + "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" + "Sec-WebSocket-Origin: http://example.com\r\n" + "Sec-WebSocket-Protocol: onConnect\r\n" - + "Sec-WebSocket-Version: " + WSVERSION + "\r\n" + "Sec-WebSocket-Extensions: identity;param=0\r\n" - + "Sec-WebSocket-Extensions: identity;param=1, identity ; param = '2' ; other = ' some = value ' \r\n" + "\r\n").getBytes("ISO-8859-1")); - output.flush(); - - // Make sure the read times out if there are problems with the implementation - socket.setSoTimeout(1000); - - InputStream input = socket.getInputStream(); - lookFor("HTTP/1.1 101 Switching Protocols\r\n",input); - skipTo("Sec-WebSocket-Accept: ",input); - lookFor("s3pPLMBiTxaQ9kYGzzhZRbK+xOo=",input); - skipTo("Sec-WebSocket-Extensions: ",input); - lookFor("identity;param=0",input); - skipTo("Sec-WebSocket-Extensions: ",input); - lookFor("identity;param=1",input); - skipTo("Sec-WebSocket-Extensions: ",input); - lookFor("identity;",input); - skipTo("\r\n\r\n",input); - - assertTrue(__serverWebSocket.awaitConnected(1000)); - assertNotNull(__serverWebSocket.connection); - - assertEquals(0x81,input.read()); - assertEquals(0x0f,input.read()); - lookFor("sent on connect",input); - } - - @Test - public void testIdle() throws Exception - { - Socket socket = new Socket("localhost",__connector.getLocalPort()); - OutputStream output = socket.getOutputStream(); - output.write(("GET /chat HTTP/1.1\r\n" + "Host: server.example.com\r\n" + "Upgrade: websocket\r\n" + "Connection: Upgrade\r\n" - + "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" + "Sec-WebSocket-Origin: http://example.com\r\n" + "Sec-WebSocket-Protocol: onConnect\r\n" - + "Sec-WebSocket-Version: " + WSVERSION + "\r\n" + "\r\n").getBytes("ISO-8859-1")); - output.flush(); - - // Make sure the read times out if there are problems with the implementation - socket.setSoTimeout(10000); - - InputStream input = socket.getInputStream(); - - lookFor("HTTP/1.1 101 Switching Protocols\r\n",input); - skipTo("Sec-WebSocket-Accept: ",input); - lookFor("s3pPLMBiTxaQ9kYGzzhZRbK+xOo=",input); - skipTo("\r\n\r\n",input); - - assertTrue(__serverWebSocket.awaitConnected(1000)); - assertNotNull(__serverWebSocket.connection); - - assertEquals(0x81,input.read()); - assertEquals(0x0f,input.read()); - lookFor("sent on connect",input); - - assertEquals((byte)0x88,(byte)input.read()); - assertEquals(26,input.read()); - assertEquals(1000 / 0x100,input.read()); - assertEquals(1000 % 0x100,input.read()); - lookFor("Idle",input); - - // respond to close - output.write(0x88 ^ 0xff); - output.write(0x80 ^ 0xff); - output.write(0xff); - output.write(0xff); - output.write(0xff); - output.write(0xff); - output.flush(); - - assertTrue(__serverWebSocket.awaitDisconnected(5000)); - try - { - __serverWebSocket.connection.write(null,fnf(),"Don't send"); - Assert.fail("Should have thrown IOException"); - } - catch (IOException e) - { - Assert.assertThat("IOException",e.getMessage(),containsString("TODO")); - } - } - - @Test - public void testMaxBinarySize() throws Exception - { - Socket socket = new Socket("localhost",__connector.getLocalPort()); - OutputStream output = socket.getOutputStream(); - output.write(("GET /chat HTTP/1.1\r\n" + "Host: server.example.com\r\n" + "Upgrade: websocket\r\n" + "Connection: Upgrade\r\n" - + "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" + "Sec-WebSocket-Origin: http://example.com\r\n" + "Sec-WebSocket-Protocol: other\r\n" - + "Sec-WebSocket-Version: " + WSVERSION + "\r\n" + "\r\n").getBytes("ISO-8859-1")); - output.flush(); - - socket.setSoTimeout(100000); - InputStream input = socket.getInputStream(); - - lookFor("HTTP/1.1 101 Switching Protocols\r\n",input); - skipTo("Sec-WebSocket-Accept: ",input); - lookFor("s3pPLMBiTxaQ9kYGzzhZRbK+xOo=",input); - skipTo("\r\n\r\n",input); - - assertTrue(__serverWebSocket.awaitConnected(1000)); - assertNotNull(__serverWebSocket.connection); - - output.write(0x02); - output.write(0x8a); - output.write(0xff); - output.write(0xff); - output.write(0xff); - output.write(0xff); - byte[] bytes = "0123456789".getBytes(StringUtil.__ISO_8859_1); - for (byte b : bytes) - { - output.write(b ^ 0xff); - } - output.flush(); - - output.write(0x80); - output.write(0x8a); - output.write(0xff); - output.write(0xff); - output.write(0xff); - output.write(0xff); - for (byte b : bytes) - { - output.write(b ^ 0xff); - } - output.flush(); - - assertEquals(0x80 | OpCode.CLOSE.getCode(),input.read()); - assertEquals(19,input.read()); - int code = ((0xff & input.read()) * 0x100) + (0xff & input.read()); - assertEquals(StatusCode.MESSAGE_TOO_LARGE,code); - lookFor("Message size > 15",input); - } - @Test public void testMaxBinarySize2() throws Exception { diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketServletRFCTest.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketServletRFCTest.java index 23df2569a8c..7d48772357f 100644 --- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketServletRFCTest.java +++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketServletRFCTest.java @@ -3,10 +3,12 @@ package org.eclipse.jetty.websocket.server; import static org.hamcrest.Matchers.*; import java.io.IOException; +import java.nio.ByteBuffer; import java.util.Arrays; import java.util.Queue; import java.util.concurrent.TimeUnit; +import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.FutureCallback; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -15,13 +17,16 @@ import org.eclipse.jetty.websocket.annotations.OnWebSocketMessage; import org.eclipse.jetty.websocket.annotations.WebSocket; import org.eclipse.jetty.websocket.api.StatusCode; import org.eclipse.jetty.websocket.api.WebSocketConnection; +import org.eclipse.jetty.websocket.generator.FrameGenerator; import org.eclipse.jetty.websocket.protocol.CloseInfo; import org.eclipse.jetty.websocket.protocol.FrameBuilder; +import org.eclipse.jetty.websocket.protocol.OpCode; import org.eclipse.jetty.websocket.protocol.WebSocketFrame; import org.eclipse.jetty.websocket.server.blockhead.BlockheadClient; import org.junit.AfterClass; import org.junit.Assert; import org.junit.BeforeClass; +import org.junit.Ignore; import org.junit.Test; /** @@ -208,6 +213,32 @@ public class WebSocketServletRFCTest } } + @Test + @Ignore("Idle Timeouts not working (yet)") + public void testIdle() throws Exception + { + BlockheadClient client = new BlockheadClient(server.getServerUri()); + client.setProtocols("onConnect"); + try + { + client.connect(); + client.sendStandardRequest(); + client.expectUpgradeResponse(); + + client.write(FrameBuilder.text("Hello").asFrame()); + + // now wait for the server to time out + // should be 2 frames, the TextFrame echo, and then the Close on disconnect + Queue frames = client.readFrames(2,TimeUnit.SECONDS,5); + Assert.assertThat("frames[0].opcode",frames.remove().getOpCode(),is(OpCode.TEXT)); + Assert.assertThat("frames[1].opcode",frames.remove().getOpCode(),is(OpCode.CLOSE)); + } + finally + { + client.close(); + } + } + /** * Test the requirement of responding with server terminated close code 1011 when there is an unhandled (internal server error) being produced by the * WebSocket POJO. @@ -237,4 +268,34 @@ public class WebSocketServletRFCTest } } + @Test + public void testMaxBinarySize() throws Exception + { + BlockheadClient client = new BlockheadClient(server.getServerUri()); + client.setProtocols("other"); + try + { + client.connect(); + client.sendStandardRequest(); + client.expectUpgradeResponse(); + + int dataSize = 1024 * 100; + byte buf[] = new byte[dataSize]; + Arrays.fill(buf,(byte)0x44); + ByteBuffer bb = ByteBuffer.allocate(dataSize + FrameGenerator.OVERHEAD); + BufferUtil.clearToFill(bb); + FrameBuilder.binary(buf).fill(bb); + BufferUtil.flipToFlush(bb,0); + client.writeRaw(bb); + + Queue frames = client.readFrames(2,TimeUnit.SECONDS,1); + Assert.assertThat("frames[0].opcode",frames.remove().getOpCode(),is(OpCode.BINARY)); + Assert.assertThat("frames[1].opcode",frames.remove().getOpCode(),is(OpCode.CLOSE)); + } + finally + { + client.close(); + } + } + } diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/blockhead/BlockheadClient.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/blockhead/BlockheadClient.java index c12c5b5e94f..a9d729753c1 100644 --- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/blockhead/BlockheadClient.java +++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/blockhead/BlockheadClient.java @@ -15,6 +15,8 @@ import java.net.Socket; import java.net.URI; import java.net.URISyntaxException; import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; import java.util.Queue; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.TimeUnit; @@ -63,9 +65,10 @@ public class BlockheadClient implements Parser.Listener private InputStream in; private int version = 13; // default to RFC-6455 private String protocols; - private String extensions; + private List extensions = new ArrayList<>(); private byte[] clientmask = new byte[] { (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF }; + private int timeout = 1000; public BlockheadClient(URI destWebsocketURI) throws URISyntaxException { @@ -87,6 +90,16 @@ public class BlockheadClient implements Parser.Listener incomingFrameQueue = new LinkedBlockingDeque<>(); } + public void addExtensions(String xtension) + { + this.extensions.add(xtension); + } + + public void clearExtensions() + { + extensions.clear(); + } + public void close() { IO.close(in); @@ -108,7 +121,7 @@ public class BlockheadClient implements Parser.Listener socket = new Socket(destAddr,port); out = socket.getOutputStream(); - // socket.setSoTimeout(1000); + socket.setSoTimeout(timeout); in = socket.getInputStream(); } @@ -121,7 +134,7 @@ public class BlockheadClient implements Parser.Listener return respHeader; } - public String getExtensions() + public List getExtensions() { return extensions; } @@ -285,25 +298,26 @@ public class BlockheadClient implements Parser.Listener { req.append("Sec-WebSocket-Protocol: ").append(protocols).append("\r\n"); } - if (StringUtil.isNotBlank(extensions)) + + for (String xtension : extensions) { - req.append("Sec-WebSocket-Extensions: ").append(extensions).append("\r\n"); + req.append("Sec-WebSocket-Extensions: ").append(xtension).append("\r\n"); } req.append("Sec-WebSocket-Version: ").append(version).append("\r\n"); req.append("\r\n"); writeRaw(req.toString()); } - public void setExtensions(String extensions) - { - this.extensions = extensions; - } - public void setProtocols(String protocols) { this.protocols = protocols; } + public void setTimeout(TimeUnit unit, int duration) + { + this.timeout = (int)TimeUnit.MILLISECONDS.convert(duration,unit); + } + public void setVersion(int version) { this.version = version;