@Test public void testParse65536ByteBinaryCase1_2_7() { int length = 65536; ByteBuffer expected = ByteBuffer.allocate(length + 11); expected.put(new byte[] {(byte) 0x82}); byte b = 0x00; // no masking b |= 0x7F; expected.put(b); expected.put(new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00}); for (int i = 0; i < length; ++i) { expected.put("*".getBytes()); } expected.flip(); WebSocketPolicy policy = new WebSocketPolicy(WebSocketBehavior.SERVER); policy.setMaxMessageSize(length); Parser parser = new UnitParser(policy); IncomingFramesCapture capture = new IncomingFramesCapture(); parser.setIncomingFramesHandler(capture); parser.parse(expected); capture.assertNoErrors(); capture.assertHasFrame(OpCode.BINARY, 1); Frame pActual = capture.getFrames().get(0); Assert.assertThat("BinaryFrame.payloadLength", pActual.getPayloadLength(), is(length)); // Assert.assertEquals("BinaryFrame.payload",length,pActual.getPayloadData().length); }
@Test public void testParse128ByteBinaryCase1_2_5() { int length = 128; ByteBuffer expected = ByteBuffer.allocate(length + 5); expected.put(new byte[] {(byte) 0x82}); byte b = 0x00; // no masking b |= 0x7E; expected.put(b); expected.putShort((short) length); for (int i = 0; i < length; ++i) { expected.put("*".getBytes()); } expected.flip(); Parser parser = new UnitParser(policy); IncomingFramesCapture capture = new IncomingFramesCapture(); parser.setIncomingFramesHandler(capture); parser.parse(expected); capture.assertNoErrors(); capture.assertHasFrame(OpCode.BINARY, 1); Frame pActual = capture.getFrames().get(0); Assert.assertThat("BinaryFrame.payloadLength", pActual.getPayloadLength(), is(length)); // Assert.assertEquals("BinaryFrame.payload",length,pActual.getPayloadData().length); }
@OnWebSocketFrame public void onWebSocketFrame(Frame frame) { if (OpCode.PONG == frame.getOpCode()) { ByteBuffer payload = frame.getPayload() != null ? frame.getPayload() : EMPTY_PAYLOAD; PongMessage message = new PongMessage(payload); try { this.webSocketHandler.handleMessage(this.wsSession, message); } catch (Throwable t) { ExceptionWebSocketHandlerDecorator.tryCloseWithError(this.wsSession, t, logger); } } }
@Override public void outgoingFrame(Frame frame, WriteCallback callback, BatchMode batchMode) { ByteBuffer payload = frame.getPayload(); int length = payload != null ? payload.remaining() : 0; if (OpCode.isControlFrame(frame.getOpCode()) || maxLength <= 0 || length <= maxLength) { nextOutgoingFrame(frame, callback, batchMode); return; } FrameEntry entry = new FrameEntry(frame, callback, batchMode); if (LOG.isDebugEnabled()) LOG.debug("Queuing {}", entry); entries.offer(entry); flusher.iterate(); }
/** * Construct new DataFrame based on headers of provided frame, overriding for continuations if * needed. * * <p>Useful for when working in extensions and a new frame needs to be created. */ public DataFrame(Frame basedOn, boolean continuation) { super(basedOn.getOpCode()); copyHeaders(basedOn); if (continuation) { setOpCode(OpCode.CONTINUATION); } }
@Override protected void nextOutgoingFrame(Frame frame, WriteCallback callback, BatchMode batchMode) { if (frame.isFin() && !outgoingContextTakeover) { LOG.debug("Outgoing Context Reset"); getDeflater().reset(); } super.nextOutgoingFrame(frame, callback, batchMode); }
@Override protected void nextIncomingFrame(Frame frame) { if (frame.isFin() && !incomingContextTakeover) { LOG.debug("Incoming Context Reset"); getInflater().reset(); } super.nextIncomingFrame(frame); }
@Override public void incomingFrame(Frame frame) { // Incoming frames are always non concurrent because // they are read and parsed with a single thread, and // therefore there is no need for synchronization. // This extension requires the RSV1 bit set only in the first frame. // Subsequent continuation frames don't have RSV1 set, but are compressed. if (frame.getType().isData()) incomingCompressed = frame.isRsv1(); if (OpCode.isControlFrame(frame.getOpCode()) || !frame.hasPayload() || !incomingCompressed) { nextIncomingFrame(frame); return; } boolean appendTail = frame.isFin(); ByteBuffer payload = frame.getPayload(); int remaining = payload.remaining(); byte[] input = new byte[remaining + (appendTail ? TAIL_BYTES.length : 0)]; payload.get(input, 0, remaining); if (appendTail) System.arraycopy(TAIL_BYTES, 0, input, remaining, TAIL_BYTES.length); forwardIncoming(frame, decompress(input)); if (frame.isFin()) incomingCompressed = false; }
@Test public void testParseEmptyBinaryCase1_2_1() { ByteBuffer expected = ByteBuffer.allocate(5); expected.put(new byte[] {(byte) 0x82, (byte) 0x00}); expected.flip(); Parser parser = new UnitParser(policy); IncomingFramesCapture capture = new IncomingFramesCapture(); parser.setIncomingFramesHandler(capture); parser.parse(expected); capture.assertNoErrors(); capture.assertHasFrame(OpCode.BINARY, 1); Frame pActual = capture.getFrames().get(0); Assert.assertThat("BinaryFrame.payloadLength", pActual.getPayloadLength(), is(0)); // Assert.assertNull("BinaryFrame.payload",pActual.getPayloadData()); }
private void fragment(FrameEntry entry, boolean first) { Frame frame = entry.frame; ByteBuffer payload = frame.getPayload(); int remaining = payload.remaining(); int length = Math.min(remaining, maxLength); finished = length == remaining; boolean continuation = frame.getType().isContinuation() || !first; DataFrame fragment = new DataFrame(frame, continuation); boolean fin = frame.isFin() && finished; fragment.setFin(fin); int limit = payload.limit(); int newLimit = payload.position() + length; payload.limit(newLimit); ByteBuffer payloadFragment = payload.slice(); payload.limit(limit); fragment.setPayload(payloadFragment); if (LOG.isDebugEnabled()) LOG.debug("Fragmented {}->{}", frame, fragment); payload.position(newLimit); nextOutgoingFrame(fragment, this, entry.batchMode); }
public void enqueue(Frame frame, WriteCallback callback, BatchMode batchMode) { if (closed.get()) { notifyCallbackFailure(callback, new EOFException("Connection has been closed locally")); return; } if (flusher.isFailed()) { notifyCallbackFailure(callback, failure); return; } FrameEntry entry = new FrameEntry(frame, callback, batchMode); synchronized (lock) { switch (frame.getOpCode()) { case OpCode.PING: { // Prepend PINGs so they are processed first. queue.add(0, entry); break; } case OpCode.CLOSE: { // There may be a chance that other frames are // added after this close frame, but we will // fail them later to keep it simple here. closed.set(true); queue.add(entry); break; } default: { queue.add(entry); break; } } } if (LOG.isDebugEnabled()) { LOG.debug("{} queued {}", this, entry); } flusher.iterate(); }
@Override public void incomingFrame(Frame frame) { if (LOG.isDebugEnabled()) { LOG.debug("{}.onFrame({})", websocket.getClass().getSimpleName(), frame); } try { onFrame(frame); byte opcode = frame.getOpCode(); switch (opcode) { case OpCode.CLOSE: { boolean validate = true; CloseFrame closeframe = (CloseFrame) frame; CloseInfo close = new CloseInfo(closeframe, validate); // notify user websocket pojo onClose(close); // process handshake session.getConnection().getIOState().onCloseRemote(close); return; } case OpCode.PING: { if (LOG.isDebugEnabled()) { LOG.debug("PING: {}", BufferUtil.toDetailString(frame.getPayload())); } ByteBuffer pongBuf; if (frame.hasPayload()) { pongBuf = ByteBuffer.allocate(frame.getPayload().remaining()); BufferUtil.put(frame.getPayload().slice(), pongBuf); BufferUtil.flipToFlush(pongBuf, 0); } else { pongBuf = ByteBuffer.allocate(0); } onPing(frame.getPayload()); session.getRemote().sendPong(pongBuf); break; } case OpCode.PONG: { if (LOG.isDebugEnabled()) { LOG.debug("PONG: {}", BufferUtil.toDetailString(frame.getPayload())); } onPong(frame.getPayload()); break; } case OpCode.BINARY: { onBinaryFrame(frame.getPayload(), frame.isFin()); return; } case OpCode.TEXT: { onTextFrame(frame.getPayload(), frame.isFin()); return; } case OpCode.CONTINUATION: { onContinuationFrame(frame.getPayload(), frame.isFin()); return; } default: { LOG.debug("Unhandled OpCode: {}", opcode); } } } catch (NotUtf8Exception e) { terminateConnection(StatusCode.BAD_PAYLOAD, e.getMessage()); } catch (CloseException e) { terminateConnection(e.getStatusCode(), e.getMessage()); } catch (Throwable t) { unhandled(t); } }
@Override public String toString() { return frame.toString(); }