SPDY: ensure SpdyHeaderBlockRawDecoder always reads entire input

This commit is contained in:
Jeff Pinner 2014-05-04 15:08:07 -07:00 committed by Norman Maurer
parent 3f50a9cde3
commit 1aca3863eb
4 changed files with 45 additions and 17 deletions

View File

@ -27,6 +27,8 @@ public class SpdyHeaderBlockRawDecoder extends SpdyHeaderBlockDecoder {
private State state; private State state;
private ByteBuf cumulation;
private int headerSize; private int headerSize;
private int numHeaders; private int numHeaders;
private int length; private int length;
@ -67,6 +69,24 @@ public class SpdyHeaderBlockRawDecoder extends SpdyHeaderBlockDecoder {
throw new NullPointerException("frame"); throw new NullPointerException("frame");
} }
if (cumulation == null) {
decodeHeaderBlock(headerBlock, frame);
if (headerBlock.isReadable()) {
cumulation = headerBlock.alloc().buffer(headerBlock.readableBytes());
cumulation.writeBytes(headerBlock);
}
} else {
cumulation.writeBytes(headerBlock);
decodeHeaderBlock(cumulation, frame);
if (cumulation.isReadable()) {
cumulation.discardReadBytes();
} else {
cumulation = null;
}
}
}
protected void decodeHeaderBlock(ByteBuf headerBlock, SpdyHeadersFrame frame) throws Exception {
int skipLength; int skipLength;
while (headerBlock.isReadable()) { while (headerBlock.isReadable()) {
switch(state) { switch(state) {
@ -267,6 +287,9 @@ public class SpdyHeaderBlockRawDecoder extends SpdyHeaderBlockDecoder {
if (state != State.END_HEADER_BLOCK) { if (state != State.END_HEADER_BLOCK) {
frame.setInvalid(); frame.setInvalid();
} }
releaseBuffer();
// Initialize header block decoding fields // Initialize header block decoding fields
headerSize = 0; headerSize = 0;
name = null; name = null;
@ -275,5 +298,13 @@ public class SpdyHeaderBlockRawDecoder extends SpdyHeaderBlockDecoder {
@Override @Override
void end() { void end() {
releaseBuffer();
}
private void releaseBuffer() {
if (cumulation != null) {
cumulation.release();
cumulation = null;
}
} }
} }

View File

@ -86,7 +86,7 @@ final class SpdyHeaderBlockZlibDecoder extends SpdyHeaderBlockRawDecoder {
} }
if (frame != null) { if (frame != null) {
decompressed.writerIndex(decompressed.writerIndex() + numBytes); decompressed.writerIndex(decompressed.writerIndex() + numBytes);
super.decode(decompressed, frame); super.decodeHeaderBlock(decompressed, frame);
decompressed.discardReadBytes(); decompressed.discardReadBytes();
} }

View File

@ -391,25 +391,21 @@ public class SpdyHeaderBlockRawDecoderTest {
@Test @Test
public void testMultipleDecodes() throws Exception { public void testMultipleDecodes() throws Exception {
ByteBuf numHeaders = Unpooled.buffer(4); ByteBuf headerBlock = Unpooled.buffer(21);
numHeaders.writeInt(1); headerBlock.writeInt(1);
headerBlock.writeInt(4);
headerBlock.writeBytes(nameBytes);
headerBlock.writeInt(5);
headerBlock.writeBytes(valueBytes);
ByteBuf nameBlock = Unpooled.buffer(8); int readableBytes = headerBlock.readableBytes();
nameBlock.writeInt(4); for (int i = 0; i < readableBytes; i++) {
nameBlock.writeBytes(nameBytes); ByteBuf headerBlockSegment = headerBlock.slice(i, 1);
decoder.decode(headerBlockSegment, frame);
ByteBuf valueBlock = Unpooled.buffer(9); assertFalse(headerBlockSegment.isReadable());
valueBlock.writeInt(5); }
valueBlock.writeBytes(valueBytes);
decoder.decode(numHeaders, frame);
decoder.decode(nameBlock, frame);
decoder.decode(valueBlock, frame);
decoder.endHeaderBlock(frame); decoder.endHeaderBlock(frame);
assertFalse(numHeaders.isReadable());
assertFalse(nameBlock.isReadable());
assertFalse(valueBlock.isReadable());
assertFalse(frame.isInvalid()); assertFalse(frame.isInvalid());
assertEquals(1, frame.headers().names().size()); assertEquals(1, frame.headers().names().size());
assertTrue(frame.headers().contains(name)); assertTrue(frame.headers().contains(name));

View File

@ -92,6 +92,7 @@ public class SpdyHeaderBlockZlibDecoderTest {
for (int i = 0; i < readableBytes; i++) { for (int i = 0; i < readableBytes; i++) {
ByteBuf headerBlockSegment = headerBlock.slice(i, 1); ByteBuf headerBlockSegment = headerBlock.slice(i, 1);
decoder.decode(headerBlockSegment, frame); decoder.decode(headerBlockSegment, frame);
assertFalse(headerBlockSegment.isReadable());
} }
decoder.endHeaderBlock(frame); decoder.endHeaderBlock(frame);