HpackDecoder implements 413 limit
This commit is contained in:
parent
140e7ed0c5
commit
30affa57c7
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue