// 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 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()); }
@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()); }
@Override protected void doSessionClosed(HttpSession createSession) throws Exception { final WsebSession wsebSession = WSE_SESSION_KEY.get(createSession); assert (wsebSession != null); IoBufferEx buf = CREATE_RESPONSE_KEY.remove(createSession); if (buf == null || createSession.getStatus() != HttpStatus.SUCCESS_CREATED) { throw new IllegalStateException("Create handshake failed: invalid response"); } buf.flip(); String responseText = buf.getString(UTF_8.newDecoder()); String[] locations = responseText.split("\n"); if (locations.length < 2) { throw new IllegalStateException("Create handshake failed: invalid response"); } URI writeURI = URI.create(locations[0]); URI readURI = URI.create(locations[1]); ResourceAddress writeAddress = resourceAddressFactory.newResourceAddress(writeURI); ResourceAddress readAddress = resourceAddressFactory.newResourceAddress(readURI); if (!wsebSession.isClosing()) { wsebSession.setWriteAddress(writeAddress); wsebSession.setReadAddress(readAddress); sessionMap.put(writeAddress, wsebSession); sessionMap.put(readAddress, wsebSession); // attach downstream for read final BridgeConnector bridgeConnector = bridgeServiceFactory.newBridgeConnector(readAddress); bridgeConnector.connect( readAddress, selectReadHandler(readAddress), new IoSessionInitializer<ConnectFuture>() { @Override public void initializeSession(IoSession ioSession, ConnectFuture connectFuture) { HttpSession httpSession = (HttpSession) ioSession; httpSession.setWriteHeader( HttpHeaders.HEADER_X_SEQUENCE_NO, Long.toString(wsebSession.nextReaderSequenceNo())); } }); // activate upstream for write // TODO: Replace usage of suspendWrite/resumeWrite with a WSEB-specific "send queue" // upon which // TODO: locking of writes can be achieved. wsebSession.resumeWrite(); // We are always aligned now. if (session.isIoAligned()) { wsebSession.getProcessor().flush(wsebSession); } }
@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()); }
/** {@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; }
@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()); }
@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); }
@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()); } }
@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()); } }
/** {@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); }
// 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()); }
@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()); }