From 4d020de810a0d5e420f445bbc94b173e9e00faa2 Mon Sep 17 00:00:00 2001 From: Joakim Erdfelt Date: Fri, 6 Jul 2012 13:07:58 -0700 Subject: [PATCH] Fixing parser --- .../jetty/websocket/parser/FrameParser.java | 128 ++++++++++++------ .../jetty/websocket/parser/Parser.java | 109 +-------------- .../websocket/protocol/WebSocketFrame.java | 12 +- 3 files changed, 93 insertions(+), 156 deletions(-) diff --git a/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/parser/FrameParser.java b/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/parser/FrameParser.java index 9e2f37c6c54..ced5432d46c 100644 --- a/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/parser/FrameParser.java +++ b/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/parser/FrameParser.java @@ -6,8 +6,11 @@ import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.websocket.api.CloseException; +import org.eclipse.jetty.websocket.api.ProtocolException; import org.eclipse.jetty.websocket.api.StatusCode; +import org.eclipse.jetty.websocket.api.WebSocketException; import org.eclipse.jetty.websocket.api.WebSocketPolicy; +import org.eclipse.jetty.websocket.protocol.CloseInfo; import org.eclipse.jetty.websocket.protocol.OpCode; import org.eclipse.jetty.websocket.protocol.WebSocketFrame; @@ -39,6 +42,8 @@ public class FrameParser { private enum State { + START, + FINOP, PAYLOAD_LEN, PAYLOAD_LEN_BYTES, MASK, @@ -49,8 +54,7 @@ public class FrameParser private static final Logger LOG = Log.getLogger(FrameParser.class); private WebSocketPolicy policy; // State specific - private State state = State.PAYLOAD_LEN; - private long length = 0; + private State state = State.START; private int cursor = 0; // Frame private WebSocketFrame frame; @@ -123,25 +127,6 @@ public class FrameParser return policy; } - /** - * Initialize the base framing values. - * - * @param fin - * @param rsv1 - * @param rsv2 - * @param rsv3 - * @param opcode - */ - public final void initFrame(boolean fin, boolean rsv1, boolean rsv2, boolean rsv3, OpCode opcode) - { - WebSocketFrame frame = new WebSocketFrame(); - frame.setFin(fin); - frame.setRsv1(rsv1); - frame.setRsv2(rsv2); - frame.setRsv3(rsv3); - frame.setOpCode(opcode); - } - /** * Parse the base framing protocol buffer. *

@@ -153,37 +138,91 @@ public class FrameParser * 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. */ - public final boolean parseBaseFraming(ByteBuffer buffer) + public boolean parse(ByteBuffer buffer) { LOG.debug("Parsing {} bytes",buffer.remaining()); while (buffer.hasRemaining()) { switch (state) { + case START: + { + if ((frame != null) && (frame.isFin())) + { + frame.reset(); + } + + state = State.FINOP; + break; + } + case FINOP: + { + // peek at byte + byte b = buffer.get(); + boolean fin = ((b & 0x80) != 0); + boolean rsv1 = ((b & 0x40) != 0); + boolean rsv2 = ((b & 0x20) != 0); + boolean rsv3 = ((b & 0x10) != 0); + byte opc = (byte)(b & 0x0F); + OpCode opcode = OpCode.from(opc); + + if (opcode == null) + { + throw new WebSocketException("Unknown opcode: " + opc); + } + + LOG.debug("OpCode {}, fin={}",opcode.name(),fin); + + if (opcode.isControlFrame() && !fin) + { + throw new ProtocolException("Fragmented Control Frame [" + opcode.name() + "]"); + } + + if (opcode == OpCode.CONTINUATION) + { + if (frame == null) + { + throw new ProtocolException("Fragment continuation frame without prior !FIN"); + } + // Be careful to use the original opcode + opcode = frame.getOpCode(); + } + + // base framing flags + frame = new WebSocketFrame(); + frame.setFin(fin); + frame.setRsv1(rsv1); + frame.setRsv2(rsv2); + frame.setRsv3(rsv3); + frame.setOpCode(opcode); + + state = State.PAYLOAD_LEN; + break; + } case PAYLOAD_LEN: { byte b = buffer.get(); getFrame().setMasked((b & 0x80) != 0); - length = (byte)(0x7F & b); + payloadLength = (byte)(0x7F & b); - if (length == 127) + if (payloadLength == 127) { // length 8 bytes (extended payload length) - length = 0; + payloadLength = 0; state = State.PAYLOAD_LEN_BYTES; cursor = 8; break; // continue onto next state } - else if (length == 126) + else if (payloadLength == 126) { // length 2 bytes (extended payload length) - length = 0; + payloadLength = 0; state = State.PAYLOAD_LEN_BYTES; cursor = 2; break; // continue onto next state } - assertSanePayloadLength(length); + assertSanePayloadLength(payloadLength); if (getFrame().isMasked()) { state = State.MASK; @@ -199,10 +238,10 @@ public class FrameParser { byte b = buffer.get(); --cursor; - length |= (b & 0xFF) << (8 * cursor); + payloadLength |= (b & 0xFF) << (8 * cursor); if (cursor == 0) { - assertSanePayloadLength(length); + assertSanePayloadLength(payloadLength); if (getFrame().isMasked()) { state = State.MASK; @@ -241,11 +280,21 @@ public class FrameParser } break; } - } - - if (state == State.PAYLOAD) - { - return true; + case PAYLOAD: + { + if (parsePayload(buffer)) + { + // special check for close + if (frame.getOpCode() == OpCode.CLOSE) + { + new CloseInfo(frame); + } + state = State.START; + // we have a frame! + return true; + } + break; + } } } @@ -261,7 +310,6 @@ public class FrameParser */ public boolean parsePayload(ByteBuffer buffer) { - payloadLength = getFrame().getPayloadLength(); while (buffer.hasRemaining()) { if (payload == null) @@ -283,12 +331,4 @@ public class FrameParser } return false; } - - /** - * Reset the frame and parser states - */ - public void reset() { - // reset parser - state = State.PAYLOAD_LEN; - } } diff --git a/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/parser/Parser.java b/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/parser/Parser.java index d5312a2049e..d5340f19f97 100644 --- a/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/parser/Parser.java +++ b/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/parser/Parser.java @@ -7,12 +7,9 @@ import java.util.concurrent.CopyOnWriteArrayList; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.websocket.api.ProtocolException; import org.eclipse.jetty.websocket.api.WebSocketException; import org.eclipse.jetty.websocket.api.WebSocketPolicy; -import org.eclipse.jetty.websocket.protocol.OpCode; import org.eclipse.jetty.websocket.protocol.WebSocketFrame; -import org.eclipse.jetty.websocket.util.CloseUtil; /** * Parsing of a frames in WebSocket land. @@ -26,18 +23,10 @@ public class Parser public void onWebSocketException(WebSocketException e); } - private enum State - { - FINOP, - BASE_FRAMING, - PAYLOAD - } - private static final Logger LOG = Log.getLogger(Parser.class); private final List listeners = new CopyOnWriteArrayList<>(); private final FrameParser parser; private WebSocketPolicy policy; - private State state = State.FINOP; public Parser(WebSocketPolicy wspolicy) { @@ -47,7 +36,6 @@ public class Parser this.policy = wspolicy; this.parser = new FrameParser(wspolicy); - reset(); } public void addListener(Listener listener) @@ -55,11 +43,6 @@ public class Parser listeners.add(listener); } - private void assertValidClose() - { - CloseUtil.assertValidPayload(parser.getFrame()); - } - public WebSocketPolicy getPolicy() { return policy; @@ -102,91 +85,11 @@ public class Parser LOG.debug("Parsing {} bytes",buffer.remaining()); while (buffer.hasRemaining()) { - switch (state) + if (parser.parse(buffer)) { - case FINOP: - { - // peek at byte - byte b = buffer.get(); - boolean fin = ((b & 0x80) != 0); - boolean rsv1 = ((b & 0x40) != 0); - boolean rsv2 = ((b & 0x20) != 0); - boolean rsv3 = ((b & 0x10) != 0); - byte opc = (byte)(b & 0x0F); - OpCode opcode = OpCode.from(opc); - - if (opcode == null) - { - throw new WebSocketException("Unknown opcode: " + opc); - } - - LOG.debug("OpCode {}, fin={}",opcode.name(),fin); - - if (opcode.isControlFrame() && !fin) - { - throw new ProtocolException("Fragmented Control Frame [" + opcode.name() + "]"); - } - - if (opcode == OpCode.CONTINUATION) - { - if (parser.getFrame() == null) - { - throw new ProtocolException("Fragment continuation frame without prior !FIN"); - } - // Be careful to use the original opcode - opcode = parser.getFrame().getOpCode(); - } - - parser.reset(); - parser.initFrame(fin,rsv1,rsv2,rsv3,opcode); - - state = State.BASE_FRAMING; - break; - } - case BASE_FRAMING: - { - if (parser.parseBaseFraming(buffer)) - { - state = State.PAYLOAD; - } - break; - } - case PAYLOAD: - { - if (parser.parsePayload(buffer)) - { - // special check for close - if (parser.getFrame().getOpCode() == OpCode.CLOSE) - { - assertValidClose(); - } - notifyFrame(parser.getFrame()); - parser.reset(); - if (parser.getFrame().isFin()) - { - reset(); - } - state = State.FINOP; - } - break; - } + notifyFrame(parser.getFrame()); } } - - /* - * if the payload was empty we could end up in this state because there was no remaining bits to process - */ - if (state == State.PAYLOAD) - { - notifyFrame(parser.getFrame()); - parser.reset(); - if (parser.getFrame().isFin()) - { - reset(); - } - state = State.FINOP; - } - } catch (WebSocketException e) { @@ -208,15 +111,9 @@ public class Parser listeners.remove(listener); } - public void reset() - { - state = State.FINOP; - parser.reset(); - } - @Override public String toString() { - return String.format("%s(state=%s, parser=%s)", getClass().getSimpleName(), state, parser); + return String.format("%s(parser=%s)",getClass().getSimpleName(),parser); } } diff --git a/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/protocol/WebSocketFrame.java b/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/protocol/WebSocketFrame.java index 2aa5cbc7b1b..c538736101a 100644 --- a/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/protocol/WebSocketFrame.java +++ b/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/protocol/WebSocketFrame.java @@ -76,19 +76,19 @@ public class WebSocketFrame implements Frame throw new ProtocolException("Cannot have FIN==false on Control frames"); } - if (rsv1 == false) + if (rsv1 == true) { - throw new ProtocolException("Cannot have RSV1==false on Control frames"); + throw new ProtocolException("Cannot have RSV1==true on Control frames"); } - if (rsv2 == false) + if (rsv2 == true) { - throw new ProtocolException("Cannot have RSV2==false on Control frames"); + throw new ProtocolException("Cannot have RSV2==true on Control frames"); } - if (rsv3 == false) + if (rsv3 == true) { - throw new ProtocolException("Cannot have RSV3==false on Control frames"); + throw new ProtocolException("Cannot have RSV3==true on Control frames"); } if (isContinuation())