@Test public void decodeTextFrame() throws Exception { ProtocolCodecSessionEx session = new ProtocolCodecSessionEx(); IoBufferAllocatorEx<?> allocator = session.getBufferAllocator(); ProtocolDecoder decoder = new WsFrameDecoder(allocator, 0); IoBufferEx in = allocator .wrap(allocator.allocate(14)) .put((byte) 0x81) .put((byte) 0x0C) .putString("Hello, world", UTF_8.newEncoder()) .flip(); decoder.decode(session, (IoBuffer) in, session.getDecoderOutput()); WsMessage out = (WsMessage) session.getDecoderOutputQueue().poll(); assertEquals( new WsTextMessage(allocator.wrap(ByteBuffer.wrap("Hello, world".getBytes(UTF_8)))), out); assertTrue(session.getDecoderOutputQueue().isEmpty()); decoder.finishDecode(session, session.getDecoderOutput()); assertTrue(session.getDecoderOutputQueue().isEmpty()); assertFalse(in.hasRemaining()); }
/** {@inheritDoc} */ @Override public DecodingState decode(IoBuffer in, ProtocolDecoderOutput out) throws Exception { IoBufferEx inEx = (IoBufferEx) in; if (buffer == null) { if (in.remaining() >= length) { int limit = in.limit(); in.limit(in.position() + length); IoBufferEx product = inEx.slice(); in.position(in.position() + length); in.limit(limit); return finishDecode((IoBuffer) product, out); } buffer = allocator.wrap(allocator.allocate(length)); buffer.put(inEx); return this; } if (in.remaining() >= length - buffer.position()) { int limit = in.limit(); in.limit(in.position() + length - buffer.position()); buffer.put(inEx); in.limit(limit); buffer.flip(); IoBufferEx product = buffer; buffer = null; return finishDecode((IoBuffer) product, out); } buffer.put(inEx); return this; }
// Decode a 200-byte binary frame private void sizeLimitDecodeBinaryFrame(int maxSize) throws Exception { ProtocolCodecSessionEx session = new ProtocolCodecSessionEx(); IoBufferAllocatorEx<?> allocator = session.getBufferAllocator(); ProtocolDecoder decoder = new WsFrameDecoder(allocator, maxSize); IoBufferEx in = allocator .wrap(allocator.allocate(204)) .put((byte) 0x82) .put((byte) 126) .put((byte) 0x00) .put((byte) 0xC8) .fill(200) .flip(); decoder.decode(session, (IoBuffer) in, session.getDecoderOutput()); WsMessage out = (WsMessage) session.getDecoderOutputQueue().poll(); assertEquals( new WsBinaryMessage(allocator.wrap(allocator.allocate(200)).fill(200).flip()), out); assertTrue(session.getDecoderOutputQueue().isEmpty()); decoder.finishDecode(session, session.getDecoderOutput()); assertTrue(session.getDecoderOutputQueue().isEmpty()); assertFalse(in.hasRemaining()); }
// Decode a 12-byte text frame and a 15 byte text frame written in one go (one network packet) private void sizeLimitDecodeDoubleTextFrame(int maxSize) throws Exception { ProtocolCodecSessionEx session = new ProtocolCodecSessionEx(); IoBufferAllocatorEx<?> allocator = session.getBufferAllocator(); ProtocolDecoder decoder = new WsFrameDecoder(allocator, maxSize); IoBufferEx in = allocator .wrap(allocator.allocate(12 + 2 + 15 + 2)) .put((byte) 0x81) .put((byte) 12) .putString("123456789012", UTF_8.newEncoder()) .put((byte) 0x81) .put((byte) 15) .putString("123456789012345", UTF_8.newEncoder()) .flip(); decoder.decode(session, (IoBuffer) in, session.getDecoderOutput()); WsMessage out = (WsMessage) session.getDecoderOutputQueue().poll(); assertEquals( new WsTextMessage(allocator.wrap(ByteBuffer.wrap("123456789012".getBytes(UTF_8)))), out); WsMessage out2 = (WsMessage) session.getDecoderOutputQueue().poll(); assertEquals( new WsTextMessage(allocator.wrap(ByteBuffer.wrap("123456789012345".getBytes(UTF_8)))), out2); assertTrue(session.getDecoderOutputQueue().isEmpty()); decoder.finishDecode(session, session.getDecoderOutput()); assertTrue(session.getDecoderOutputQueue().isEmpty()); assertFalse(in.hasRemaining()); }
@Test public void decodeZeroLengthMaskedPongFrame() throws Exception { ProtocolCodecSessionEx session = new ProtocolCodecSessionEx(); IoBufferAllocatorEx<?> allocator = session.getBufferAllocator(); ProtocolDecoder decoder = new WsFrameDecoder(allocator, 0); IoBufferEx in = allocator .wrap(allocator.allocate(6)) .put((byte) 0x8A) .put((byte) 0x80) .fill(4) // mask .flip(); decoder.decode(session, (IoBuffer) in, session.getDecoderOutput()); WsMessage out = (WsMessage) session.getDecoderOutputQueue().poll(); assertEquals(new WsPongMessage(allocator.wrap(allocator.allocate(0)).flip()), out); assertTrue(session.getDecoderOutputQueue().isEmpty()); decoder.finishDecode(session, session.getDecoderOutput()); assertTrue(session.getDecoderOutputQueue().isEmpty()); assertFalse(in.hasRemaining()); }
/** {@inheritDoc} */ @Override public DecodingState finishDecode(ProtocolDecoderOutput out) throws Exception { IoBufferEx readData; if (buffer == null) { readData = allocator.wrap(allocator.allocate(0)); } else { buffer.flip(); readData = buffer; buffer = null; } return finishDecode((IoBuffer) readData, out); }
@Override protected void doMessageReceived(HttpSession createSession, Object message) throws Exception { // Handle fragmentation of response body IoBufferEx in = (IoBufferEx) message; IoBufferEx buf = CREATE_RESPONSE_KEY.get(createSession); if (buf == null) { IoBufferAllocatorEx<?> allocator = createSession.getBufferAllocator(); buf = allocator.wrap(allocator.allocate(in.remaining())).setAutoExpander(allocator); CREATE_RESPONSE_KEY.set(createSession, buf); } buf.put(in); }
// Make sure we fail early for case of large text messages: we should fail as soon as we process // a network packet that exceeds the limit (first packet in this case) @Test(expected = ProtocolDecoderException.class) public void sizeLimitDecodeTextFrameFailEarly1() throws Exception { ProtocolCodecSessionEx session = new ProtocolCodecSessionEx(); IoBufferAllocatorEx<?> allocator = session.getBufferAllocator(); ProtocolDecoder decoder = new WsFrameDecoder(allocator, 20); int dataSize = 30; StringBuilder data = new StringBuilder(dataSize); for (int i = 0; i < (dataSize); i++) { data.append((i % 10)); } IoBufferEx in = allocator .wrap(allocator.allocate(dataSize + 2)) .put((byte) 0x81) .put((byte) 30) .putString(data.toString(), UTF_8.newEncoder()) .flip(); // As soon as we sent part of a message that exceeds the limit it should throw the exception decoder.decode(session, (IoBuffer) in, session.getDecoderOutput()); }
@Test public void decodeFragmentedBinaryFrame() throws Exception { ProtocolCodecSessionEx session = new ProtocolCodecSessionEx(); IoBufferAllocatorEx<?> allocator = session.getBufferAllocator(); ProtocolDecoder decoder = new WsFrameDecoder(allocator, 0); IoBufferEx[] array = new IoBufferEx[] { allocator .wrap(allocator.allocate(104)) .put((byte) 0x82) .put((byte) 126) .put((byte) 0x00) .put((byte) 0xC8) .fill(100) .flip(), allocator .wrap(allocator.allocate(102)) .fill(100) .put((byte) 0x82) .put((byte) 0x00) .flip(), }; for (IoBufferEx in : array) { decoder.decode(session, (IoBuffer) in, session.getDecoderOutput()); } WsMessage fragmented = (WsMessage) session.getDecoderOutputQueue().poll(); assertEquals( new WsBinaryMessage(allocator.wrap(allocator.allocate(200)).fill(200).flip()), fragmented); WsMessage empty = (WsMessage) session.getDecoderOutputQueue().poll(); assertEquals(new WsBinaryMessage(allocator.wrap(allocator.allocate(0))), empty); assertTrue(session.getDecoderOutputQueue().isEmpty()); decoder.finishDecode(session, session.getDecoderOutput()); assertTrue(session.getDecoderOutputQueue().isEmpty()); for (IoBufferEx in : array) { assertFalse(in.hasRemaining()); } }
// Make sure we fail early for case of large text messages: we should fail as soon as we process // a network packet that exceeds the limit (2nd packet in this case) @Test(expected = ProtocolDecoderException.class) public void sizeLimitDecodeTextFrameFailEarly2() throws Exception { ProtocolCodecSessionEx session = new ProtocolCodecSessionEx(); IoBufferAllocatorEx<?> allocator = session.getBufferAllocator(); ProtocolDecoder decoder = new WsFrameDecoder(allocator, 20); int dataSize = 30; StringBuilder data = new StringBuilder(dataSize); for (int i = 0; i < (dataSize); i++) { data.append((i % 10)); } IoBufferEx in = allocator .wrap(allocator.allocate(dataSize + 2)) .put((byte) 0x81) .put((byte) 30) .putString(data.toString(), UTF_8.newEncoder()) .flip(); decoder.decode(session, (IoBuffer) in.getSlice(10), session.getDecoderOutput()); // Now if we send the next 12 bytes that should exceed the limit (first byte is control byte, // doesn't count) decoder.decode(session, (IoBuffer) in.getSlice(12), session.getDecoderOutput()); }
private IoBufferEx getMaxMessageSizeBuffer(IoBufferAllocatorEx<?> allocator) throws Exception { int firstPayload = 125; String first = createString('a', firstPayload); int secondPayload = 125; String second = createString('b', secondPayload); int thirdPayload = 4; String third = createString('c', thirdPayload); int fourthPayload = 6; byte[] fourth = createString('d', fourthPayload).getBytes("UTF-8"); return allocator .wrap( allocator.allocate(firstPayload + secondPayload + 2 + thirdPayload + fourthPayload + 8)) // text frame .put((byte) 0x01) .put((byte) firstPayload) .putString(first, UTF_8.newEncoder()) // continuation frame .put((byte) 0x00) .put((byte) secondPayload) .putString(second, UTF_8.newEncoder()) // ping frame .put((byte) 0x89) .put((byte) 0x00) // continuation frame with FIN .put((byte) 0x80) .put((byte) thirdPayload) .putString(third, UTF_8.newEncoder()) // binary frame .put((byte) 0x82) .put((byte) fourthPayload) .put(fourth) .flip(); }
@Test(expected = ProtocolDecoderException.class) public void decodeFragmentedContinuationFrameExceedingMaxMessageSize() throws Exception { ProtocolCodecSessionEx session = new ProtocolCodecSessionEx(); IoBufferAllocatorEx<?> allocator = session.getBufferAllocator(); ProtocolDecoder decoder = new WsFrameDecoder(allocator, 150); String textFramePayload = createString('a', 100); IoBufferEx textFrameBuffer = allocator .wrap(allocator.allocate(102)) // text frame .put((byte) 0x01) .put((byte) 100) .putString(textFramePayload, UTF_8.newEncoder()) .flip(); // the decoder should fail fast when message size exceeds the max message size without waiting // for // payload IoBufferEx continuationFrameBuffer = allocator .wrap(allocator.allocate(2)) // continuation frame fragment (opcode and payload length) .put((byte) 0x80) .put((byte) 0x64) .flip(); decoder.decode(session, (IoBuffer) textFrameBuffer, session.getDecoderOutput()); // since the maximum message size is 150, the following statement will // cause the message size(200) to exceed maximum message size // The decoder should fail fast once the payload length is decoded regardless of the // availability of payload decoder.decode(session, (IoBuffer) continuationFrameBuffer, session.getDecoderOutput()); }
@Test public void decodeFragmentedTextFrame() throws Exception { ProtocolCodecSessionEx session = new ProtocolCodecSessionEx(); IoBufferAllocatorEx<?> allocator = session.getBufferAllocator(); ProtocolDecoder decoder = new WsFrameDecoder(allocator, 0); IoBufferEx[] array = new IoBufferEx[] { allocator .wrap(allocator.allocate(103)) .put((byte) 0x81) .put((byte) 0x0C) .putString("Hello", UTF_8.newEncoder()) .flip(), allocator .wrap(allocator.allocate(102)) .putString(", world", UTF_8.newEncoder()) .put((byte) 0x81) .put((byte) 0x00) .flip(), }; for (IoBufferEx in : array) { decoder.decode(session, (IoBuffer) in, session.getDecoderOutput()); } WsMessage fragmented = (WsMessage) session.getDecoderOutputQueue().poll(); assertEquals( new WsTextMessage(allocator.wrap(ByteBuffer.wrap("Hello, world".getBytes(UTF_8)))), fragmented); WsMessage empty = (WsMessage) session.getDecoderOutputQueue().poll(); assertEquals(new WsTextMessage(allocator.wrap(allocator.allocate(0))), empty); assertTrue(session.getDecoderOutputQueue().isEmpty()); decoder.finishDecode(session, session.getDecoderOutput()); assertTrue(session.getDecoderOutputQueue().isEmpty()); for (IoBufferEx in : array) { assertFalse(in.hasRemaining()); } }
@Test public void decodeTextContinuationFrame() throws Exception { ProtocolCodecSessionEx session = new ProtocolCodecSessionEx(); IoBufferAllocatorEx<?> allocator = session.getBufferAllocator(); ProtocolDecoder decoder = new WsFrameDecoder(allocator, 200); int firstPayload = 125; String first = createString('a', firstPayload); int secondPayload = 2; String second = createString('b', secondPayload); int thirdPayload = 4; String thrid = createString('c', thirdPayload); IoBufferEx in = allocator .wrap(allocator.allocate(firstPayload + secondPayload + thirdPayload + 6)) // text frame .put((byte) 0x01) .put((byte) firstPayload) .putString(first, UTF_8.newEncoder()) // continuation frame with FIN .put((byte) 0x80) .put((byte) secondPayload) .putString(second, UTF_8.newEncoder()) // text frame with FIN .put((byte) 0x81) .put((byte) thirdPayload) .putString(thrid, UTF_8.newEncoder()) .flip(); decoder.decode(session, (IoBuffer) in, session.getDecoderOutput()); WsMessage out1 = (WsMessage) session.getDecoderOutputQueue().poll(); assertEquals( new WsTextMessage(allocator.wrap(ByteBuffer.wrap(first.getBytes(UTF_8))), false), out1); WsMessage out2 = (WsMessage) session.getDecoderOutputQueue().poll(); assertEquals( new WsContinuationMessage(allocator.wrap(ByteBuffer.wrap(second.getBytes(UTF_8)))), out2); WsMessage out3 = (WsMessage) session.getDecoderOutputQueue().poll(); assertEquals(new WsTextMessage(allocator.wrap(ByteBuffer.wrap(thrid.getBytes(UTF_8)))), out3); assertTrue(session.getDecoderOutputQueue().isEmpty()); decoder.finishDecode(session, session.getDecoderOutput()); assertTrue(session.getDecoderOutputQueue().isEmpty()); assertFalse(in.hasRemaining()); }
@Test public void decodeBinaryContinuationFrame() throws Exception { ProtocolCodecSessionEx session = new ProtocolCodecSessionEx(); IoBufferAllocatorEx<?> allocator = session.getBufferAllocator(); ProtocolDecoder decoder = new WsFrameDecoder(allocator, 200); int firstPayload = 125; byte[] first = createString('a', firstPayload).getBytes("UTF-8"); int secondPayload = 2; byte[] second = createString('b', secondPayload).getBytes("UTF-8"); int thirdPayload = 4; byte[] thrid = createString('c', thirdPayload).getBytes("UTF-8"); IoBufferEx in = allocator .wrap(allocator.allocate(firstPayload + secondPayload + thirdPayload + 6)) // binary frame .put((byte) 0x02) .put((byte) firstPayload) .put(first) // continuation frame with FIN .put((byte) 0x80) .put((byte) secondPayload) .put(second) // binary frame with FIN .put((byte) 0x82) .put((byte) thirdPayload) .put(thrid) .flip(); decoder.decode(session, (IoBuffer) in, session.getDecoderOutput()); WsMessage out1 = (WsMessage) session.getDecoderOutputQueue().poll(); assertEquals(new WsBinaryMessage(allocator.wrap(ByteBuffer.wrap(first)), false), out1); WsMessage out2 = (WsMessage) session.getDecoderOutputQueue().poll(); assertEquals(new WsContinuationMessage(allocator.wrap(ByteBuffer.wrap(second))), out2); WsMessage out3 = (WsMessage) session.getDecoderOutputQueue().poll(); assertEquals(new WsBinaryMessage(allocator.wrap(ByteBuffer.wrap(thrid))), out3); assertTrue(session.getDecoderOutputQueue().isEmpty()); decoder.finishDecode(session, session.getDecoderOutput()); assertTrue(session.getDecoderOutputQueue().isEmpty()); assertFalse(in.hasRemaining()); }
@Test public void decodeTextContinuationFrameWithFragmentedPayload() throws Exception { ProtocolCodecSessionEx session = new ProtocolCodecSessionEx(); IoBufferAllocatorEx<?> allocator = session.getBufferAllocator(); ProtocolDecoder decoder = new WsFrameDecoder(allocator, 250); String textFramePayload = createString('a', 100); String continuationFramePayloadFirstFragment = createString('b', 50); String continuationFramePayloadSecondFragment = createString('b', 50); IoBufferEx in = allocator .wrap(allocator.allocate(102)) // text frame .put((byte) 0x01) .put((byte) 100) .putString(textFramePayload, UTF_8.newEncoder()) .flip(); IoBufferEx[] array = new IoBufferEx[] { allocator .wrap(allocator.allocate(2)) // continuation frame fragment (opcode and payload length) .put((byte) 0x80) .put((byte) 0x64) .flip(), allocator .wrap(allocator.allocate(50)) // continuation frame payload first fragment .putString(continuationFramePayloadFirstFragment, UTF_8.newEncoder()) .flip(), allocator .wrap(allocator.allocate(50)) // continuation frame payload second fragment .putString(continuationFramePayloadSecondFragment, UTF_8.newEncoder()) .flip() }; decoder.decode(session, (IoBuffer) in, session.getDecoderOutput()); for (IoBufferEx buffer : array) { decoder.decode(session, (IoBuffer) buffer, session.getDecoderOutput()); } WsMessage out1 = (WsMessage) session.getDecoderOutputQueue().poll(); assertEquals( new WsTextMessage(allocator.wrap(ByteBuffer.wrap(textFramePayload.getBytes(UTF_8))), false), out1); WsMessage out2 = (WsMessage) session.getDecoderOutputQueue().poll(); assertEquals( new WsContinuationMessage( allocator.wrap(ByteBuffer.wrap(createString('b', 100).getBytes(UTF_8)))), out2); }
@Test public void pingInBinaryContinuationSequence() throws Exception { ProtocolCodecSessionEx session = new ProtocolCodecSessionEx(); IoBufferAllocatorEx<?> allocator = session.getBufferAllocator(); ProtocolDecoder decoder = new WsFrameDecoder(allocator, 400); int firstPayload = 125; byte[] first = createString('a', firstPayload).getBytes("UTF-8"); int secondPayload = 125; byte[] second = createString('b', secondPayload).getBytes("UTF-8"); int thirdPayload = 4; byte[] third = createString('c', thirdPayload).getBytes("UTF-8"); int fourthPayload = 6; String fourth = createString('d', fourthPayload); IoBufferEx in = allocator .wrap( allocator.allocate( firstPayload + secondPayload + 2 + thirdPayload + fourthPayload + 8)) // text frame .put((byte) 0x01) .put((byte) firstPayload) .put(first) // continuation frame .put((byte) 0x00) .put((byte) secondPayload) .put(second) // ping frame .put((byte) 0x89) .put((byte) 0x00) // continuation frame with FIN .put((byte) 0x80) .put((byte) thirdPayload) .put(third) // binary frame .put((byte) 0x82) .put((byte) fourthPayload) .putString(fourth, UTF_8.newEncoder()) .flip(); decoder.decode(session, (IoBuffer) in, session.getDecoderOutput()); WsMessage out1 = (WsMessage) session.getDecoderOutputQueue().poll(); assertEquals(new WsTextMessage(allocator.wrap(ByteBuffer.wrap(first)), false), out1); WsMessage out2 = (WsMessage) session.getDecoderOutputQueue().poll(); assertEquals(new WsContinuationMessage(allocator.wrap(ByteBuffer.wrap(second)), false), out2); WsMessage out = (WsMessage) session.getDecoderOutputQueue().poll(); assertEquals(new WsPingMessage(allocator.wrap(allocator.allocate(0))), out); WsMessage out3 = (WsMessage) session.getDecoderOutputQueue().poll(); assertEquals(new WsContinuationMessage(allocator.wrap(ByteBuffer.wrap(third))), out3); WsMessage out4 = (WsMessage) session.getDecoderOutputQueue().poll(); assertEquals( new WsBinaryMessage(allocator.wrap(ByteBuffer.wrap(fourth.getBytes(UTF_8)))), out4); assertTrue(session.getDecoderOutputQueue().isEmpty()); decoder.finishDecode(session, session.getDecoderOutput()); assertTrue(session.getDecoderOutputQueue().isEmpty()); assertFalse(in.hasRemaining()); }
@Test public void decodeBinaryContinuationFrameWithFragmentedPayload() throws Exception { ProtocolCodecSessionEx session = new ProtocolCodecSessionEx(); IoBufferAllocatorEx<?> allocator = session.getBufferAllocator(); ProtocolDecoder decoder = new WsFrameDecoder(allocator, 250); byte[] binaryFramePayload = createString('a', 100).getBytes(); byte[] continuationFramePayload = createString('b', 100).getBytes(); IoBufferEx in = allocator .wrap(allocator.allocate(102)) // binary frame .put((byte) 0x02) .put((byte) 100) .put(binaryFramePayload) .flip(); IoBufferEx[] array = new IoBufferEx[] { allocator .wrap(allocator.allocate(2)) // continuation frame fragment (opcode and payload length) .put((byte) 0x80) .put((byte) 0x64) .flip(), allocator .wrap(allocator.allocate(50)) // continuation frame first fragment .put(continuationFramePayload, 0, 50) .flip(), allocator .wrap(allocator.allocate(50)) // continuation frame second fragment .put(continuationFramePayload, 50, 50) .flip() }; decoder.decode(session, (IoBuffer) in, session.getDecoderOutput()); for (IoBufferEx buffer : array) { decoder.decode(session, (IoBuffer) buffer, session.getDecoderOutput()); } WsMessage out1 = (WsMessage) session.getDecoderOutputQueue().poll(); assertEquals( new WsBinaryMessage(allocator.wrap(ByteBuffer.wrap(binaryFramePayload)), false), out1); WsMessage out2 = (WsMessage) session.getDecoderOutputQueue().poll(); assertEquals( new WsContinuationMessage(allocator.wrap(ByteBuffer.wrap(continuationFramePayload))), out2); }