diff --git a/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/parser/FrameParser.java b/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/parser/FrameParser.java index dfb01321297..0f05d4365f1 100644 --- a/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/parser/FrameParser.java +++ b/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/parser/FrameParser.java @@ -144,7 +144,7 @@ public abstract class FrameParser getFrame().setMasked((b & 0x80) != 0); length = (byte)(0x7F & b); - if (b == 127) + if (length == 127) { // length 4 bytes (extended payload length) if (buffer.remaining() >= 4) @@ -159,7 +159,7 @@ public abstract class FrameParser break; // continue onto next state } } - else if (b == 126) + else if (length == 126) { // length 2 bytes (extended payload length) if (buffer.remaining() >= 2) diff --git a/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/parser/TextPayloadParser.java b/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/parser/TextPayloadParser.java index 39b7e01b155..fe773c30dcb 100644 --- a/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/parser/TextPayloadParser.java +++ b/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/parser/TextPayloadParser.java @@ -3,6 +3,7 @@ package org.eclipse.jetty.websocket.parser; import java.nio.ByteBuffer; import org.eclipse.jetty.util.BufferUtil; +import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.websocket.api.WebSocketSettings; import org.eclipse.jetty.websocket.frames.TextFrame; @@ -47,7 +48,7 @@ public class TextPayloadParser extends FrameParser if (payload.position() >= payloadLength) { payload.flip(); - frame.setData(BufferUtil.toString(payload)); + frame.setData(BufferUtil.toString(payload,StringUtil.__UTF8_CHARSET)); return true; } } diff --git a/jetty-websocket/websocket-core/src/test/java/org/eclipse/jetty/websocket/parser/TextPayloadParserTest.java b/jetty-websocket/websocket-core/src/test/java/org/eclipse/jetty/websocket/parser/TextPayloadParserTest.java index 0945ab81cc4..63a986f1ba5 100644 --- a/jetty-websocket/websocket-core/src/test/java/org/eclipse/jetty/websocket/parser/TextPayloadParserTest.java +++ b/jetty-websocket/websocket-core/src/test/java/org/eclipse/jetty/websocket/parser/TextPayloadParserTest.java @@ -16,17 +16,29 @@ public class TextPayloadParserTest { 0x00, (byte)0xF0, 0x0F, (byte)0xFF }; @Test - public void testShortMaskedText() throws Exception + public void testLongMaskedText() throws Exception { Debug.enableDebugLogging(Parser.class); Debug.enableDebugLogging(TextPayloadParser.class); - String expectedText = "Hello World"; - ByteBuffer buf = ByteBuffer.allocate(24); + StringBuffer sb = new StringBuffer(); ; + for (int i = 0; i < 3500; i++) + { + sb.append("Hell\uFF4f Big W\uFF4Frld "); + } + sb.append(". The end."); + + String expectedText = sb.toString(); + byte utf[] = expectedText.getBytes(StringUtil.__UTF8); + + Assert.assertThat("Must be a long length payload",utf.length,greaterThan(0xFFFF)); + + ByteBuffer buf = ByteBuffer.allocate(utf.length + 10); buf.put((byte)0x81); - buf.put((byte)(0x80 | expectedText.length())); + buf.put((byte)(0x80 | 0x7F)); // 0x7F == 127 (a 4 byte payload length) + buf.putInt(utf.length); writeMask(buf); - writeMasked(buf,expectedText.getBytes(StringUtil.__UTF8)); + writeMaskedPayload(buf,utf); buf.flip(); Parser parser = new Parser(); @@ -37,7 +49,133 @@ public class TextPayloadParserTest capture.assertNoErrors(); capture.assertHasFrame(TextFrame.class,1); TextFrame txt = (TextFrame)capture.getFrames().get(0); - Assert.assertThat("TextFrame.data",txt.getData().toString(),is("Hello World")); + Assert.assertThat("TextFrame.data",txt.getData().toString(),is(expectedText)); + } + + @Test + public void testMediumMaskedText() throws Exception + { + Debug.enableDebugLogging(Parser.class); + Debug.enableDebugLogging(TextPayloadParser.class); + + StringBuffer sb = new StringBuffer(); ; + for (int i = 0; i < 14; i++) + { + sb.append("Hell\uFF4f Medium W\uFF4Frld "); + } + sb.append(". The end."); + + String expectedText = sb.toString(); + byte utf[] = expectedText.getBytes(StringUtil.__UTF8); + + Assert.assertThat("Must be a medium length payload",utf.length,allOf(greaterThan(0x7E),lessThan(0xFFFF))); + + ByteBuffer buf = ByteBuffer.allocate(utf.length + 10); + buf.put((byte)0x81); + buf.put((byte)(0x80 | 0x7E)); // 0x7E == 126 (a 2 byte payload length) + buf.putShort((short)utf.length); + writeMask(buf); + writeMaskedPayload(buf,utf); + buf.flip(); + + Parser parser = new Parser(); + FrameParseCapture capture = new FrameParseCapture(); + parser.addListener(capture); + parser.parse(buf); + + capture.assertNoErrors(); + capture.assertHasFrame(TextFrame.class,1); + TextFrame txt = (TextFrame)capture.getFrames().get(0); + Assert.assertThat("TextFrame.data",txt.getData().toString(),is(expectedText)); + } + + @Test + public void testShortMaskedFragmentedText() throws Exception + { + Debug.enableDebugLogging(Parser.class); + Debug.enableDebugLogging(TextPayloadParser.class); + + String part1 = "Hello "; + String part2 = "World"; + + byte b1[] = part1.getBytes(StringUtil.__UTF8_CHARSET); + byte b2[] = part2.getBytes(StringUtil.__UTF8_CHARSET); + + ByteBuffer buf = ByteBuffer.allocate(32); + + // part 1 + buf.put((byte)0x01); // no fin + text + buf.put((byte)(0x80 | b1.length)); + writeMask(buf); + writeMaskedPayload(buf,b1); + + // part 2 + buf.put((byte)0x80); // fin + continuation + buf.put((byte)(0x80 | b2.length)); + writeMask(buf); + writeMaskedPayload(buf,b2); + + buf.flip(); + + Parser parser = new Parser(); + FrameParseCapture capture = new FrameParseCapture(); + parser.addListener(capture); + parser.parse(buf); + + capture.assertNoErrors(); + capture.assertHasFrame(TextFrame.class,2); + TextFrame txt = (TextFrame)capture.getFrames().get(0); + Assert.assertThat("TextFrame[0].data",txt.getData().toString(),is(part1)); + txt = (TextFrame)capture.getFrames().get(1); + Assert.assertThat("TextFrame[1].data",txt.getData().toString(),is(part2)); + } + + @Test + public void testShortMaskedText() throws Exception + { + String expectedText = "Hello World"; + + ByteBuffer buf = ByteBuffer.allocate(24); + buf.put((byte)0x81); + buf.put((byte)(0x80 | expectedText.length())); + writeMask(buf); + writeMaskedPayload(buf,expectedText.getBytes(StringUtil.__UTF8)); + buf.flip(); + + Parser parser = new Parser(); + FrameParseCapture capture = new FrameParseCapture(); + parser.addListener(capture); + parser.parse(buf); + + capture.assertNoErrors(); + capture.assertHasFrame(TextFrame.class,1); + TextFrame txt = (TextFrame)capture.getFrames().get(0); + Assert.assertThat("TextFrame.data",txt.getData().toString(),is(expectedText)); + } + + @Test + public void testShortMaskedUtf8Text() throws Exception + { + String expectedText = "Hell\uFF4f W\uFF4Frld"; + + byte utf[] = expectedText.getBytes(StringUtil.__UTF8); + + ByteBuffer buf = ByteBuffer.allocate(24); + buf.put((byte)0x81); + buf.put((byte)(0x80 | utf.length)); + writeMask(buf); + writeMaskedPayload(buf,utf); + buf.flip(); + + Parser parser = new Parser(); + FrameParseCapture capture = new FrameParseCapture(); + parser.addListener(capture); + parser.parse(buf); + + capture.assertNoErrors(); + capture.assertHasFrame(TextFrame.class,1); + TextFrame txt = (TextFrame)capture.getFrames().get(0); + Assert.assertThat("TextFrame.data",txt.getData().toString(),is(expectedText)); } private void writeMask(ByteBuffer buf) @@ -45,7 +183,7 @@ public class TextPayloadParserTest buf.put(mask,0,mask.length); } - private void writeMasked(ByteBuffer buf, byte[] bytes) + private void writeMaskedPayload(ByteBuffer buf, byte[] bytes) { int len = bytes.length; for (int i = 0; i < len; i++)