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;
}
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);
}
}
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();
}
}
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);
}
}
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);
}
}
Aggregations