diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/UnknownControlFrameBodyParser.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/UnknownControlFrameBodyParser.java index 2083249e8d8..ea5890ff6f0 100644 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/UnknownControlFrameBodyParser.java +++ b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/UnknownControlFrameBodyParser.java @@ -20,19 +20,51 @@ import java.nio.ByteBuffer; public class UnknownControlFrameBodyParser extends ControlFrameBodyParser { + private final ControlFrameParser controlFrameParser; + private State state = State.BODY; private int remaining; public UnknownControlFrameBodyParser(ControlFrameParser controlFrameParser) { - this.remaining = controlFrameParser.getLength(); + this.controlFrameParser = controlFrameParser; } @Override public boolean parse(ByteBuffer buffer) { - int consumed = Math.min(remaining, buffer.remaining()); - buffer.position(buffer.position() + consumed); - remaining -= consumed; - return remaining == 0; + switch (state) + { + case BODY: + { + remaining = controlFrameParser.getLength(); + state = State.CONSUME; + // Fall down + } + case CONSUME: + { + int consume = Math.min(remaining, buffer.remaining()); + buffer.position(buffer.position() + consume); + remaining -= consume; + if (remaining > 0) + return false; + reset(); + return true; + } + default: + { + throw new IllegalStateException(); + } + } + } + + private void reset() + { + state = State.BODY; + remaining = 0; + } + + private enum State + { + BODY, CONSUME } } diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/parser/UnknownControlFrameTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/parser/UnknownControlFrameTest.java new file mode 100644 index 00000000000..750f407d4b4 --- /dev/null +++ b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/parser/UnknownControlFrameTest.java @@ -0,0 +1,64 @@ +package org.eclipse.jetty.spdy.parser; + +import java.nio.ByteBuffer; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.eclipse.jetty.spdy.SessionException; +import org.eclipse.jetty.spdy.StandardByteBufferPool; +import org.eclipse.jetty.spdy.StandardCompressionFactory; +import org.eclipse.jetty.spdy.StreamException; +import org.eclipse.jetty.spdy.api.Headers; +import org.eclipse.jetty.spdy.api.SPDY; +import org.eclipse.jetty.spdy.api.SynInfo; +import org.eclipse.jetty.spdy.frames.ControlFrame; +import org.eclipse.jetty.spdy.frames.DataFrame; +import org.eclipse.jetty.spdy.frames.SynStreamFrame; +import org.eclipse.jetty.spdy.generator.Generator; +import org.junit.Assert; +import org.junit.Test; + +public class UnknownControlFrameTest +{ + @Test + public void testUnknownControlFrame() throws Exception + { + SynStreamFrame frame = new SynStreamFrame(SPDY.V2, SynInfo.FLAG_CLOSE, 1, 0, (byte)0, new Headers()); + Generator generator = new Generator(new StandardByteBufferPool(), new StandardCompressionFactory.StandardCompressor()); + ByteBuffer buffer = generator.control(frame); + // Change the frame type to unknown + buffer.putShort(2, (short)0); + + final CountDownLatch latch = new CountDownLatch(1); + Parser parser = new Parser(new StandardCompressionFactory.StandardDecompressor()); + parser.addListener(new Parser.Listener.Adapter() + { + @Override + public void onControlFrame(ControlFrame frame) + { + latch.countDown(); + } + + @Override + public void onDataFrame(DataFrame frame, ByteBuffer data) + { + latch.countDown(); + } + + @Override + public void onStreamException(StreamException x) + { + latch.countDown(); + } + + @Override + public void onSessionException(SessionException x) + { + latch.countDown(); + } + }); + parser.parse(buffer); + + Assert.assertFalse(latch.await(1, TimeUnit.SECONDS)); + } +}