Search in sources :

Example 1 with PingFrame

use of org.eclipse.jetty.websocket.common.frames.PingFrame in project jetty.project by eclipse.

the class Parser method parseFrame.

/**
     * Parse the base framing protocol buffer.
     * <p>
     * Note the first byte (fin,rsv1,rsv2,rsv3,opcode) are parsed by the {@link Parser#parse(ByteBuffer)} method
     * <p>
     * Not overridable
     * 
     * @param buffer
     *            the buffer to parse from.
     * @return true if done parsing base framing protocol and ready for parsing of the payload. false if incomplete parsing of base framing protocol.
     */
private boolean parseFrame(ByteBuffer buffer) {
    if (LOG.isDebugEnabled()) {
        LOG.debug("{} Parsing {} bytes", policy.getBehavior(), buffer.remaining());
    }
    while (buffer.hasRemaining()) {
        switch(state) {
            case START:
                {
                    // peek at byte
                    byte b = buffer.get();
                    boolean fin = ((b & 0x80) != 0);
                    byte opcode = (byte) (b & 0x0F);
                    if (!OpCode.isKnown(opcode)) {
                        throw new ProtocolException("Unknown opcode: " + opcode);
                    }
                    if (LOG.isDebugEnabled())
                        LOG.debug("{} OpCode {}, fin={} rsv={}{}{}", policy.getBehavior(), OpCode.name(opcode), fin, (((b & 0x40) != 0) ? '1' : '.'), (((b & 0x20) != 0) ? '1' : '.'), (((b & 0x10) != 0) ? '1' : '.'));
                    // base framing flags
                    switch(opcode) {
                        case OpCode.TEXT:
                            frame = new TextFrame();
                            // data validation
                            if (priorDataFrame) {
                                throw new ProtocolException("Unexpected " + OpCode.name(opcode) + " frame, was expecting CONTINUATION");
                            }
                            break;
                        case OpCode.BINARY:
                            frame = new BinaryFrame();
                            // data validation
                            if (priorDataFrame) {
                                throw new ProtocolException("Unexpected " + OpCode.name(opcode) + " frame, was expecting CONTINUATION");
                            }
                            break;
                        case OpCode.CONTINUATION:
                            frame = new ContinuationFrame();
                            // continuation validation
                            if (!priorDataFrame) {
                                throw new ProtocolException("CONTINUATION frame without prior !FIN");
                            }
                            // Be careful to use the original opcode
                            break;
                        case OpCode.CLOSE:
                            frame = new CloseFrame();
                            // control frame validation
                            if (!fin) {
                                throw new ProtocolException("Fragmented Close Frame [" + OpCode.name(opcode) + "]");
                            }
                            break;
                        case OpCode.PING:
                            frame = new PingFrame();
                            // control frame validation
                            if (!fin) {
                                throw new ProtocolException("Fragmented Ping Frame [" + OpCode.name(opcode) + "]");
                            }
                            break;
                        case OpCode.PONG:
                            frame = new PongFrame();
                            // control frame validation
                            if (!fin) {
                                throw new ProtocolException("Fragmented Pong Frame [" + OpCode.name(opcode) + "]");
                            }
                            break;
                    }
                    frame.setFin(fin);
                    // Are any flags set?
                    if ((b & 0x70) != 0) {
                        /*
                         * RFC 6455 Section 5.2
                         * 
                         * MUST be 0 unless an extension is negotiated that defines meanings for non-zero values. If a nonzero value is received and none of the
                         * negotiated extensions defines the meaning of such a nonzero value, the receiving endpoint MUST _Fail the WebSocket Connection_.
                         */
                        if ((b & 0x40) != 0) {
                            if (isRsv1InUse())
                                frame.setRsv1(true);
                            else {
                                String err = "RSV1 not allowed to be set";
                                if (LOG.isDebugEnabled()) {
                                    LOG.debug(err + ": Remaining buffer: {}", BufferUtil.toDetailString(buffer));
                                }
                                throw new ProtocolException(err);
                            }
                        }
                        if ((b & 0x20) != 0) {
                            if (isRsv2InUse())
                                frame.setRsv2(true);
                            else {
                                String err = "RSV2 not allowed to be set";
                                if (LOG.isDebugEnabled()) {
                                    LOG.debug(err + ": Remaining buffer: {}", BufferUtil.toDetailString(buffer));
                                }
                                throw new ProtocolException(err);
                            }
                        }
                        if ((b & 0x10) != 0) {
                            if (isRsv3InUse())
                                frame.setRsv3(true);
                            else {
                                String err = "RSV3 not allowed to be set";
                                if (LOG.isDebugEnabled()) {
                                    LOG.debug(err + ": Remaining buffer: {}", BufferUtil.toDetailString(buffer));
                                }
                                throw new ProtocolException(err);
                            }
                        }
                    }
                    state = State.PAYLOAD_LEN;
                    break;
                }
            case PAYLOAD_LEN:
                {
                    byte b = buffer.get();
                    frame.setMasked((b & 0x80) != 0);
                    payloadLength = (byte) (0x7F & b);
                    if (// 0x7F
                    payloadLength == 127) {
                        // length 8 bytes (extended payload length)
                        payloadLength = 0;
                        state = State.PAYLOAD_LEN_BYTES;
                        cursor = 8;
                        // continue onto next state
                        break;
                    } else if (// 0x7E
                    payloadLength == 126) {
                        // length 2 bytes (extended payload length)
                        payloadLength = 0;
                        state = State.PAYLOAD_LEN_BYTES;
                        cursor = 2;
                        // continue onto next state
                        break;
                    }
                    assertSanePayloadLength(payloadLength);
                    if (frame.isMasked()) {
                        state = State.MASK;
                    } else {
                        // special case for empty payloads (no more bytes left in buffer)
                        if (payloadLength == 0) {
                            state = State.START;
                            return true;
                        }
                        maskProcessor.reset(frame);
                        state = State.PAYLOAD;
                    }
                    break;
                }
            case PAYLOAD_LEN_BYTES:
                {
                    byte b = buffer.get();
                    --cursor;
                    payloadLength |= (b & 0xFF) << (8 * cursor);
                    if (cursor == 0) {
                        assertSanePayloadLength(payloadLength);
                        if (frame.isMasked()) {
                            state = State.MASK;
                        } else {
                            // special case for empty payloads (no more bytes left in buffer)
                            if (payloadLength == 0) {
                                state = State.START;
                                return true;
                            }
                            maskProcessor.reset(frame);
                            state = State.PAYLOAD;
                        }
                    }
                    break;
                }
            case MASK:
                {
                    byte[] m = new byte[4];
                    frame.setMask(m);
                    if (buffer.remaining() >= 4) {
                        buffer.get(m, 0, 4);
                        // special case for empty payloads (no more bytes left in buffer)
                        if (payloadLength == 0) {
                            state = State.START;
                            return true;
                        }
                        maskProcessor.reset(frame);
                        state = State.PAYLOAD;
                    } else {
                        state = State.MASK_BYTES;
                        cursor = 4;
                    }
                    break;
                }
            case MASK_BYTES:
                {
                    byte b = buffer.get();
                    frame.getMask()[4 - cursor] = b;
                    --cursor;
                    if (cursor == 0) {
                        // special case for empty payloads (no more bytes left in buffer)
                        if (payloadLength == 0) {
                            state = State.START;
                            return true;
                        }
                        maskProcessor.reset(frame);
                        state = State.PAYLOAD;
                    }
                    break;
                }
            case PAYLOAD:
                {
                    frame.assertValid();
                    if (parsePayload(buffer)) {
                        // special check for close
                        if (frame.getOpCode() == OpCode.CLOSE) {
                            // TODO: yuck. Don't create an object to do validation checks!
                            new CloseInfo(frame);
                        }
                        state = State.START;
                        // we have a frame!
                        return true;
                    }
                    break;
                }
        }
    }
    return false;
}
Also used : PongFrame(org.eclipse.jetty.websocket.common.frames.PongFrame) ProtocolException(org.eclipse.jetty.websocket.api.ProtocolException) BinaryFrame(org.eclipse.jetty.websocket.common.frames.BinaryFrame) PingFrame(org.eclipse.jetty.websocket.common.frames.PingFrame) TextFrame(org.eclipse.jetty.websocket.common.frames.TextFrame) CloseFrame(org.eclipse.jetty.websocket.common.frames.CloseFrame) ContinuationFrame(org.eclipse.jetty.websocket.common.frames.ContinuationFrame)

Example 2 with PingFrame

use of org.eclipse.jetty.websocket.common.frames.PingFrame in project jetty.project by eclipse.

the class TestABCase5 method testCase5_20.

/**
     * send text message fragmented in 5 frames, with 2 pings and wait between. (framewise)
     * @throws Exception on test failure
     */
@Test
public void testCase5_20() throws Exception {
    List<WebSocketFrame> send1 = new ArrayList<>();
    send1.add(new TextFrame().setPayload("f1").setFin(false));
    send1.add(new ContinuationFrame().setPayload(",f2").setFin(false));
    send1.add(new PingFrame().setPayload("pong-1"));
    List<WebSocketFrame> send2 = new ArrayList<>();
    send2.add(new ContinuationFrame().setPayload(",f3").setFin(false));
    send2.add(new ContinuationFrame().setPayload(",f4").setFin(false));
    send2.add(new PingFrame().setPayload("pong-2"));
    send2.add(new ContinuationFrame().setPayload(",f5").setFin(true));
    send2.add(new CloseInfo(StatusCode.NORMAL).asFrame());
    List<WebSocketFrame> expect1 = new ArrayList<>();
    expect1.add(new PongFrame().setPayload("pong-1"));
    List<WebSocketFrame> expect2 = new ArrayList<>();
    expect2.add(new PongFrame().setPayload("pong-2"));
    expect2.add(new TextFrame().setPayload("f1,f2,f3,f4,f5"));
    expect2.add(new CloseInfo(StatusCode.NORMAL).asFrame());
    try (Fuzzer fuzzer = new Fuzzer(this);
        StacklessLogging supress = new StacklessLogging(Parser.class)) {
        fuzzer.connect();
        fuzzer.setSendMode(Fuzzer.SendMode.PER_FRAME);
        fuzzer.send(send1);
        fuzzer.expect(expect1);
        TimeUnit.SECONDS.sleep(1);
        fuzzer.send(send2);
        fuzzer.expect(expect2);
    }
}
Also used : PongFrame(org.eclipse.jetty.websocket.common.frames.PongFrame) Fuzzer(org.eclipse.jetty.websocket.common.test.Fuzzer) PingFrame(org.eclipse.jetty.websocket.common.frames.PingFrame) ArrayList(java.util.ArrayList) TextFrame(org.eclipse.jetty.websocket.common.frames.TextFrame) WebSocketFrame(org.eclipse.jetty.websocket.common.WebSocketFrame) ContinuationFrame(org.eclipse.jetty.websocket.common.frames.ContinuationFrame) StacklessLogging(org.eclipse.jetty.util.log.StacklessLogging) CloseInfo(org.eclipse.jetty.websocket.common.CloseInfo) Test(org.junit.Test)

Example 3 with PingFrame

use of org.eclipse.jetty.websocket.common.frames.PingFrame in project jetty.project by eclipse.

the class TestABCase7 method testCase7_1_6.

/**
     * 256k msg, then close, then ping
     * @throws Exception on test failure
     */
@Test
public void testCase7_1_6() throws Exception {
    byte[] msg = new byte[256 * 1024];
    Arrays.fill(msg, (byte) '*');
    ByteBuffer buf = ByteBuffer.wrap(msg);
    List<WebSocketFrame> send = new ArrayList<>();
    send.add(new TextFrame().setPayload(buf));
    send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
    send.add(new PingFrame().setPayload("out of band"));
    List<WebSocketFrame> expect = new ArrayList<>();
    expect.add(new TextFrame().setPayload(clone(buf)));
    expect.add(new CloseInfo(StatusCode.NORMAL).asFrame());
    try (Fuzzer fuzzer = new Fuzzer(this)) {
        fuzzer.connect();
        fuzzer.setSendMode(Fuzzer.SendMode.BULK);
        fuzzer.send(send);
        fuzzer.expect(expect);
        fuzzer.expectNoMoreFrames();
    }
}
Also used : Fuzzer(org.eclipse.jetty.websocket.common.test.Fuzzer) PingFrame(org.eclipse.jetty.websocket.common.frames.PingFrame) ArrayList(java.util.ArrayList) TextFrame(org.eclipse.jetty.websocket.common.frames.TextFrame) WebSocketFrame(org.eclipse.jetty.websocket.common.WebSocketFrame) ByteBuffer(java.nio.ByteBuffer) CloseInfo(org.eclipse.jetty.websocket.common.CloseInfo) Test(org.junit.Test)

Example 4 with PingFrame

use of org.eclipse.jetty.websocket.common.frames.PingFrame in project jetty.project by eclipse.

the class TestABCase5 method testCase5_7.

/**
     * Send text fragmented in 2 packets, with ping between them (framewise)
     * @throws Exception on test failure
     */
@Test
public void testCase5_7() throws Exception {
    List<WebSocketFrame> send = new ArrayList<>();
    send.add(new TextFrame().setPayload("hello, ").setFin(false));
    send.add(new PingFrame().setPayload("ping"));
    send.add(new ContinuationFrame().setPayload("world").setFin(true));
    send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
    List<WebSocketFrame> expect = new ArrayList<>();
    expect.add(new PongFrame().setPayload("ping"));
    expect.add(new TextFrame().setPayload("hello, world"));
    expect.add(new CloseInfo(StatusCode.NORMAL).asFrame());
    try (Fuzzer fuzzer = new Fuzzer(this);
        StacklessLogging supress = new StacklessLogging(Parser.class)) {
        fuzzer.connect();
        fuzzer.setSendMode(Fuzzer.SendMode.PER_FRAME);
        fuzzer.send(send);
        fuzzer.expect(expect);
    }
}
Also used : PongFrame(org.eclipse.jetty.websocket.common.frames.PongFrame) Fuzzer(org.eclipse.jetty.websocket.common.test.Fuzzer) PingFrame(org.eclipse.jetty.websocket.common.frames.PingFrame) ArrayList(java.util.ArrayList) TextFrame(org.eclipse.jetty.websocket.common.frames.TextFrame) WebSocketFrame(org.eclipse.jetty.websocket.common.WebSocketFrame) ContinuationFrame(org.eclipse.jetty.websocket.common.frames.ContinuationFrame) StacklessLogging(org.eclipse.jetty.util.log.StacklessLogging) CloseInfo(org.eclipse.jetty.websocket.common.CloseInfo) Test(org.junit.Test)

Example 5 with PingFrame

use of org.eclipse.jetty.websocket.common.frames.PingFrame in project jetty.project by eclipse.

the class TestABCase5 method testCase5_19.

/**
     * send text message fragmented in 5 frames, with 2 pings and wait between.
     * @throws Exception on test failure
     */
@Test
@Slow
public void testCase5_19() throws Exception {
    // phase 1
    List<WebSocketFrame> send1 = new ArrayList<>();
    send1.add(new TextFrame().setPayload("f1").setFin(false));
    send1.add(new ContinuationFrame().setPayload(",f2").setFin(false));
    send1.add(new PingFrame().setPayload("pong-1"));
    List<WebSocketFrame> expect1 = new ArrayList<>();
    expect1.add(new PongFrame().setPayload("pong-1"));
    // phase 2
    List<WebSocketFrame> send2 = new ArrayList<>();
    send2.add(new ContinuationFrame().setPayload(",f3").setFin(false));
    send2.add(new ContinuationFrame().setPayload(",f4").setFin(false));
    send2.add(new PingFrame().setPayload("pong-2"));
    send2.add(new ContinuationFrame().setPayload(",f5").setFin(true));
    send2.add(new CloseInfo(StatusCode.NORMAL).asFrame());
    List<WebSocketFrame> expect2 = new ArrayList<>();
    expect2.add(new PongFrame().setPayload("pong-2"));
    expect2.add(new TextFrame().setPayload("f1,f2,f3,f4,f5"));
    expect2.add(new CloseInfo(StatusCode.NORMAL).asFrame());
    try (Fuzzer fuzzer = new Fuzzer(this);
        StacklessLogging supress = new StacklessLogging(Parser.class)) {
        fuzzer.connect();
        fuzzer.setSendMode(Fuzzer.SendMode.BULK);
        // phase 1
        fuzzer.send(send1);
        fuzzer.expect(expect1);
        // delay
        TimeUnit.SECONDS.sleep(1);
        // phase 2
        fuzzer.send(send2);
        fuzzer.expect(expect2);
    }
}
Also used : PongFrame(org.eclipse.jetty.websocket.common.frames.PongFrame) Fuzzer(org.eclipse.jetty.websocket.common.test.Fuzzer) PingFrame(org.eclipse.jetty.websocket.common.frames.PingFrame) ArrayList(java.util.ArrayList) TextFrame(org.eclipse.jetty.websocket.common.frames.TextFrame) WebSocketFrame(org.eclipse.jetty.websocket.common.WebSocketFrame) ContinuationFrame(org.eclipse.jetty.websocket.common.frames.ContinuationFrame) StacklessLogging(org.eclipse.jetty.util.log.StacklessLogging) CloseInfo(org.eclipse.jetty.websocket.common.CloseInfo) Test(org.junit.Test) Slow(org.eclipse.jetty.toolchain.test.annotation.Slow)

Aggregations

PingFrame (org.eclipse.jetty.websocket.common.frames.PingFrame)48 Test (org.junit.Test)45 WebSocketFrame (org.eclipse.jetty.websocket.common.WebSocketFrame)33 CloseInfo (org.eclipse.jetty.websocket.common.CloseInfo)30 ArrayList (java.util.ArrayList)28 Fuzzer (org.eclipse.jetty.websocket.common.test.Fuzzer)27 TextFrame (org.eclipse.jetty.websocket.common.frames.TextFrame)24 ByteBuffer (java.nio.ByteBuffer)19 PongFrame (org.eclipse.jetty.websocket.common.frames.PongFrame)19 StacklessLogging (org.eclipse.jetty.util.log.StacklessLogging)17 ContinuationFrame (org.eclipse.jetty.websocket.common.frames.ContinuationFrame)14 ExtensionConfig (org.eclipse.jetty.websocket.api.extensions.ExtensionConfig)4 Frame (org.eclipse.jetty.websocket.api.extensions.Frame)4 IncomingFramesCapture (org.eclipse.jetty.websocket.common.test.IncomingFramesCapture)4 BinaryFrame (org.eclipse.jetty.websocket.common.frames.BinaryFrame)3 CloseableLocalWebSocketSession (org.eclipse.jetty.websocket.common.io.CloseableLocalWebSocketSession)3 LocalWebSocketSession (org.eclipse.jetty.websocket.common.io.LocalWebSocketSession)3 ListenerPingPongSocket (examples.ListenerPingPongSocket)2 AbstractExtensionTest (org.eclipse.jetty.websocket.common.extensions.AbstractExtensionTest)2 FragmentExtension (org.eclipse.jetty.websocket.common.extensions.fragment.FragmentExtension)2