Search in sources :

Example 1 with CloseFrame

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

the class AbstractEventDriver method incomingFrame.

@Override
public void incomingFrame(Frame frame) {
    if (LOG.isDebugEnabled()) {
        LOG.debug("incomingFrame({})", 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);
                    // 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:
                {
                    if (LOG.isDebugEnabled())
                        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);
    }
}
Also used : CloseException(org.eclipse.jetty.websocket.api.CloseException) CloseFrame(org.eclipse.jetty.websocket.common.frames.CloseFrame) CloseInfo(org.eclipse.jetty.websocket.common.CloseInfo) ByteBuffer(java.nio.ByteBuffer) NotUtf8Exception(org.eclipse.jetty.util.Utf8Appendable.NotUtf8Exception)

Example 2 with CloseFrame

use of org.eclipse.jetty.websocket.common.frames.CloseFrame 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 3 with CloseFrame

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

the class CloseInfo method asFrame.

public CloseFrame asFrame() {
    CloseFrame frame = new CloseFrame();
    frame.setFin(true);
    if ((statusCode >= 1000) && (statusCode != StatusCode.NO_CLOSE) && (statusCode != StatusCode.NO_CODE)) {
        if (statusCode == StatusCode.FAILED_TLS_HANDSHAKE) {
            throw new ProtocolException("Close Frame with status code " + statusCode + " not allowed (per RFC6455)");
        }
        frame.setPayload(asByteBuffer());
    }
    return frame;
}
Also used : ProtocolException(org.eclipse.jetty.websocket.api.ProtocolException) CloseFrame(org.eclipse.jetty.websocket.common.frames.CloseFrame)

Example 4 with CloseFrame

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

the class CloseInfoTest method testAnonymousClose.

/**
     * A test where no close is provided
     */
@Test
public void testAnonymousClose() {
    CloseInfo close = new CloseInfo();
    assertThat("close.code", close.getStatusCode(), is(NO_CODE));
    assertThat("close.reason", close.getReason(), nullValue());
    CloseFrame frame = close.asFrame();
    assertThat("close frame op code", frame.getOpCode(), is(OpCode.CLOSE));
    // should result in no payload
    assertThat("close frame has payload", frame.hasPayload(), is(false));
    assertThat("close frame payload length", frame.getPayloadLength(), is(0));
}
Also used : CloseFrame(org.eclipse.jetty.websocket.common.frames.CloseFrame) Test(org.junit.Test)

Example 5 with CloseFrame

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

the class WebSocketFrameTest method testLaxInvalidClose.

@Test
public void testLaxInvalidClose() {
    WebSocketFrame frame = new CloseFrame().setFin(false);
    ByteBuffer actual = generateWholeFrame(laxGenerator, frame);
    String expected = "0800";
    assertFrameHex("Lax Invalid Close Frame", expected, actual);
}
Also used : CloseFrame(org.eclipse.jetty.websocket.common.frames.CloseFrame) ByteBuffer(java.nio.ByteBuffer) Test(org.junit.Test)

Aggregations

CloseFrame (org.eclipse.jetty.websocket.common.frames.CloseFrame)20 Test (org.junit.Test)15 ByteBuffer (java.nio.ByteBuffer)10 ArrayList (java.util.ArrayList)6 WebSocketFrame (org.eclipse.jetty.websocket.common.WebSocketFrame)6 Fuzzer (org.eclipse.jetty.websocket.common.test.Fuzzer)6 CloseInfo (org.eclipse.jetty.websocket.common.CloseInfo)4 ProtocolException (org.eclipse.jetty.websocket.api.ProtocolException)3 BinaryFrame (org.eclipse.jetty.websocket.common.frames.BinaryFrame)2 ContinuationFrame (org.eclipse.jetty.websocket.common.frames.ContinuationFrame)2 PingFrame (org.eclipse.jetty.websocket.common.frames.PingFrame)2 PongFrame (org.eclipse.jetty.websocket.common.frames.PongFrame)2 TextFrame (org.eclipse.jetty.websocket.common.frames.TextFrame)2 NotUtf8Exception (org.eclipse.jetty.util.Utf8Appendable.NotUtf8Exception)1 StacklessLogging (org.eclipse.jetty.util.log.StacklessLogging)1 CloseException (org.eclipse.jetty.websocket.api.CloseException)1