diff options
author | Greg Wilkins | 2014-06-18 09:11:23 +0000 |
---|---|---|
committer | Greg Wilkins | 2014-06-18 09:11:23 +0000 |
commit | 30affa57c7e2aed1f26902e13e7f476395aa253d (patch) | |
tree | 26eb9d524ee9201d8463ba74a55fdf4258fc7187 | |
parent | 140e7ed0c56ea0afcabba1e1e142ad76d044220c (diff) | |
download | org.eclipse.jetty.project-30affa57c7e2aed1f26902e13e7f476395aa253d.tar.gz org.eclipse.jetty.project-30affa57c7e2aed1f26902e13e7f476395aa253d.tar.xz org.eclipse.jetty.project-30affa57c7e2aed1f26902e13e7f476395aa253d.zip |
HpackDecoder implements 413 limit
4 files changed, 114 insertions, 10 deletions
diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java index 6771ff3983..4a2ec08720 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java @@ -27,6 +27,7 @@ import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpScheme; +import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http2.hpack.HpackContext.Entry; import org.eclipse.jetty.util.TypeUtil; @@ -43,18 +44,21 @@ public class HpackDecoder public static final Logger LOG = Log.getLogger(HpackDecoder.class); private final HpackContext _context; - private final MetaDataBuilder _builder = new MetaDataBuilder(); + private final MetaDataBuilder _builder; private int _localMaxHeaderTableSize; + @Deprecated public HpackDecoder() { - this(4096); + this(4*1024,8*1024); + LOG.warn("USE HpackDecoder constructor with maxHeaderSize!!!"); } - public HpackDecoder(int localMaxHeaderTableSize) + public HpackDecoder(int localMaxHeaderTableSize, int maxHeaderSize) { _context=new HpackContext(localMaxHeaderTableSize); _localMaxHeaderTableSize=localMaxHeaderTableSize; + _builder = new MetaDataBuilder(maxHeaderSize); } public void setLocalMaxHeaderTableSize(int localMaxHeaderTableSize) @@ -63,9 +67,15 @@ public class HpackDecoder } public MetaData decode(ByteBuffer buffer) - { + { if (LOG.isDebugEnabled()) - LOG.debug(String.format("CtxTbl[%x] decoding",_context.hashCode())); + LOG.debug(String.format("CtxTbl[%x] decoding %d octets",_context.hashCode(),buffer.remaining())); + + // If the buffer is big, don't even think about decoding it + if (buffer.remaining()>_builder.getMaxSize()) + throw new BadMessageException(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413,"Header frame size "+buffer.remaining()+">"+_builder.getMaxSize()); + + while(buffer.hasRemaining()) { if (LOG.isDebugEnabled()) @@ -129,6 +139,7 @@ public class HpackDecoder { huffmanName = (buffer.get()&0x80)==0x80; int length = NBitInteger.decode(buffer,7); + _builder.checkSize(length,huffmanName); if (huffmanName) name=Huffman.decode(buffer,length); else @@ -147,6 +158,7 @@ public class HpackDecoder // decode the value boolean huffmanValue = (buffer.get()&0x80)==0x80; int length = NBitInteger.decode(buffer,7); + _builder.checkSize(length,huffmanValue); if (huffmanValue) value=Huffman.decode(buffer,length); else diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java index a372667d0c..2ff9510b32 100644 --- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java +++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java @@ -20,10 +20,12 @@ package org.eclipse.jetty.http2.hpack; +import org.eclipse.jetty.http.BadMessageException; import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpScheme; +import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; @@ -32,16 +34,44 @@ import org.eclipse.jetty.http.MetaData; /* -------------------------------------------------------- */ public class MetaDataBuilder { + private final int _maxSize; + private int _size; private int _status; private String _method; private HttpScheme _scheme; private HostPortHttpField _authority; private String _path; - HttpFields _fields = new HttpFields(10); + private HttpFields _fields = new HttpFields(10); + MetaDataBuilder(int maxSize) + { + _maxSize=maxSize; + } + + /** Get the maxSize. + * @return the maxSize + */ + public int getMaxSize() + { + return _maxSize; + } + + /** Get the size. + * @return the current size in bytes + */ + public int getSize() + { + return _size; + } + public void emit(HttpField field) { + int field_size = field.getName().length()+field.getValue().length(); + _size+=field_size; + if (_size>_maxSize) + throw new BadMessageException(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413,"Header size "+_size+">"+_maxSize); + if (field instanceof StaticValueHttpField) { StaticValueHttpField value = (StaticValueHttpField)field; @@ -65,7 +95,6 @@ public class MetaDataBuilder } else { - switch(field.getName()) { case ":status": @@ -114,6 +143,21 @@ public class MetaDataBuilder _scheme=null; _authority=null; _path=null; + _size=0; } } + + /* ------------------------------------------------------------ */ + /** Check that the max size will not be exceeded. + * @param length + * @param huffmanName + */ + public void checkSize(int length, boolean huffman) + { + // Apply a huffman fudge factor + if (huffman) + length=(length*4)/3; + if ((_size+length)>_maxSize) + throw new BadMessageException(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413,"Header size "+(_size+length)+">"+_maxSize); + } } diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java index 7857a1bdbf..9fcb6ac5e9 100644 --- a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java @@ -43,7 +43,7 @@ public class HpackDecoderTest @Test public void testDecodeD_3() { - HpackDecoder decoder = new HpackDecoder(); + HpackDecoder decoder = new HpackDecoder(4096,8192); // First request String encoded="828786440f7777772e6578616d706c652e636f6d"; @@ -93,7 +93,7 @@ public class HpackDecoderTest @Test public void testDecodeD_4() { - HpackDecoder decoder = new HpackDecoder(); + HpackDecoder decoder = new HpackDecoder(4096,8192); // First request String encoded="828786448ce7cf9bebe89b6fb16fa9b6ff"; diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java index 7cc665b4fd..5a4b4a13f2 100644 --- a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java +++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java @@ -19,11 +19,16 @@ package org.eclipse.jetty.http2.hpack; +import static org.junit.Assert.assertEquals; + import java.nio.ByteBuffer; +import org.eclipse.jetty.http.BadMessageException; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpHeader; +import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.http.MetaData; import org.junit.Assert; import org.junit.Test; import org.eclipse.jetty.http.MetaData.Request; @@ -37,7 +42,7 @@ public class HpackTest public void encodeDecodeResponseTest() { HpackEncoder encoder = new HpackEncoder(); - HpackDecoder decoder = new HpackDecoder(); + HpackDecoder decoder = new HpackDecoder(4096,8192); ByteBuffer buffer = BufferUtil.allocate(16*1024); HttpFields fields0 = new HttpFields(); @@ -80,4 +85,47 @@ public class HpackTest Assert.assertEquals("custom-key",decoded1.getFields().getField("Custom-Key").getName()); } + + + @Test + public void encodeDecodeTooLargeTest() + { + HpackEncoder encoder = new HpackEncoder(); + HpackDecoder decoder = new HpackDecoder(4096,101); + ByteBuffer buffer = BufferUtil.allocate(16*1024); + + HttpFields fields0 = new HttpFields(); + fields0.add("1234567890","1234567890123456789012345678901234567890"); + fields0.add("Cookie","abcdeffhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR"); + MetaData original0= new MetaData(HttpVersion.HTTP_2,fields0); + + BufferUtil.clearToFill(buffer); + encoder.encode(buffer,original0); + BufferUtil.flipToFlush(buffer,0); + MetaData decoded0 = (MetaData)decoder.decode(buffer); + + Assert.assertEquals(original0,decoded0); + + HttpFields fields1 = new HttpFields(); + fields1.add("1234567890","1234567890123456789012345678901234567890"); + fields1.add("Cookie","abcdeffhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR"); + fields1.add("x","y"); + MetaData original1 = new MetaData(HttpVersion.HTTP_2,fields1); + + BufferUtil.clearToFill(buffer); + encoder.encode(buffer,original1); + BufferUtil.flipToFlush(buffer,0); + try + { + decoder.decode(buffer); + Assert.fail(); + } + catch(BadMessageException e) + { + assertEquals(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413,e.getCode()); + } + + } + + } |