misc optimisation of http2 field creation

This commit is contained in:
Greg Wilkins 2014-08-05 12:55:12 +10:00
parent 636c7eaeae
commit d7f2c42e2d
6 changed files with 107 additions and 61 deletions

View File

@ -69,9 +69,14 @@ public class HttpField
return _value;
}
public int getIntValue()
{
return Integer.valueOf(_value);
}
public long getLongValue()
{
return StringUtil.toLong(_value);
return Long.valueOf(_value);
}
public String[] getValues()
@ -416,21 +421,65 @@ public class HttpField
return true;
}
public static class IntValueHttpField extends HttpField
{
final int _int;
public IntValueHttpField(HttpHeader header, String value, int intValue)
{
super(header,value);
_int=intValue;
}
public IntValueHttpField(HttpHeader header, String value)
{
this(header,value,Integer.valueOf(value));
}
public IntValueHttpField(HttpHeader header, int value)
{
this(header,Integer.toString(value),value);
}
@Override
public int getIntValue()
{
return _int;
}
@Override
public long getLongValue()
{
return _int;
}
}
public static class LongValueHttpField extends HttpField
{
final long _long;
public LongValueHttpField(HttpHeader header, long value)
public LongValueHttpField(HttpHeader header, String value, long longValue)
{
super(header,Long.toString(value));
_long=value;
super(header,value);
_long=longValue;
}
public LongValueHttpField(HttpHeader header, String value)
{
super(header,value);
_long=StringUtil.toLong(value);
this(header,value,StringUtil.toLong(value));
}
public LongValueHttpField(HttpHeader header,long value)
{
this(header,Long.toString(value),value);
}
@Override
public int getIntValue()
{
return (int)_long;
}
@Override

View File

@ -119,20 +119,20 @@ public class HpackContext
switch(i)
{
case 2:
entry=new StaticEntry(i,new StaticValueHttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1],HttpMethod.GET));
entry=new StaticEntry(i,new StaticTableHttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1],HttpMethod.GET));
break;
case 3:
entry=new StaticEntry(i,new StaticValueHttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1],HttpMethod.POST));
entry=new StaticEntry(i,new StaticTableHttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1],HttpMethod.POST));
break;
case 6:
entry=new StaticEntry(i,new StaticValueHttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1],HttpScheme.HTTP));
entry=new StaticEntry(i,new StaticTableHttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1],HttpScheme.HTTP));
break;
case 7:
entry=new StaticEntry(i,new StaticValueHttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1],HttpScheme.HTTPS));
entry=new StaticEntry(i,new StaticTableHttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1],HttpScheme.HTTPS));
break;
case 8:
case 11:
entry=new StaticEntry(i,new StaticValueHttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1],Integer.valueOf(STATIC_TABLE[i][1])));
entry=new StaticEntry(i,new StaticTableHttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1],Integer.valueOf(STATIC_TABLE[i][1])));
break;
case 9:
@ -140,7 +140,7 @@ public class HpackContext
case 12:
case 13:
case 14:
entry=new StaticEntry(i,new StaticValueHttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1],Integer.valueOf(STATIC_TABLE[i][1])));
entry=new StaticEntry(i,new StaticTableHttpField(STATIC_TABLE[i][0],STATIC_TABLE[i][1],Integer.valueOf(STATIC_TABLE[i][1])));
break;
default:
@ -429,6 +429,7 @@ public class HpackContext
public static class StaticEntry extends Entry
{
private final byte[] _huffmanValue;
private final byte _encodedField;
StaticEntry(int index,HttpField field)
{
@ -450,6 +451,8 @@ public class HpackContext
}
else
_huffmanValue=null;
_encodedField=(byte)(0x80|index);
}
@Override
@ -463,6 +466,11 @@ public class HpackContext
{
return _huffmanValue;
}
public byte getEncodedField()
{
return _encodedField;
}
}

View File

@ -41,7 +41,8 @@ import org.eclipse.jetty.util.log.Logger;
public class HpackDecoder
{
public static final Logger LOG = Log.getLogger(HpackDecoder.class);
public final static HttpField.LongValueHttpField CONTENT_LENGTH_0 = new HttpField.LongValueHttpField(HttpHeader.CONTENT_LENGTH,0L);
public final static HttpField.LongValueHttpField CONTENT_LENGTH_0 =
new HttpField.LongValueHttpField(HttpHeader.CONTENT_LENGTH,0L);
private final HpackContext _context;
private final MetaDataBuilder _builder;
@ -191,41 +192,26 @@ public class HpackDecoder
HttpField field;
if (header==null)
{
// just make a normal field and bypass header name lookup
field = new HttpField(null,name,value);
}
else
{
// might be worthwhile to create a value HttpField if it is indexed
// and/or of a type that may be looked up multiple times.
switch(header)
{
case C_METHOD:
HttpMethod method=HttpMethod.CACHE.get(value);
if (method!=null)
field = new StaticValueHttpField(HttpHeader.C_METHOD,method.asString(),method);
else
field = new AuthorityHttpField(value);
break;
case C_STATUS:
Integer code = Integer.valueOf(value);
field = new StaticValueHttpField(HttpHeader.C_STATUS,value,code);
break;
case C_SCHEME:
HttpScheme scheme=HttpScheme.CACHE.get(value);
if (scheme!=null)
field = new StaticValueHttpField(HttpHeader.C_SCHEME,scheme.asString(),scheme);
if (indexed)
field = new HttpField.IntValueHttpField(header,value);
else
field = new AuthorityHttpField(value);
field = new HttpField(header,name,value);
break;
case C_AUTHORITY:
field = new AuthorityHttpField(value);
break;
case C_PATH:
field = new HttpField(HttpHeader.C_PATH,value);
break;
case CONTENT_LENGTH:
if ("0".equals(value))
field = CONTENT_LENGTH_0;

View File

@ -28,6 +28,7 @@ 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.http2.hpack.HpackContext.StaticEntry;
import org.eclipse.jetty.io.ByteBufferPool.Lease;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.TypeUtil;
@ -78,6 +79,7 @@ public class HpackEncoder
}
private final HpackContext _context;
private final boolean _debug;
private int _remoteMaxHeaderTableSize;
private int _localMaxHeaderTableSize;
@ -96,6 +98,7 @@ public class HpackEncoder
_context=new HpackContext(remoteMaxHeaderTableSize);
_remoteMaxHeaderTableSize=remoteMaxHeaderTableSize;
_localMaxHeaderTableSize=localMaxHeaderTableSize;
_debug=LOG.isDebugEnabled();
}
public HpackContext getContext()
@ -154,15 +157,13 @@ public class HpackEncoder
int code=response.getStatus();
HttpField status = code<__status.length?__status[code]:null;
if (status==null)
status=new HttpField(HttpHeader.C_STATUS,Integer.toString(code));
status=new HttpField.IntValueHttpField(HttpHeader.C_STATUS,code);
encode(buffer,status);
}
// Add all the other fields
for (HttpField field : metadata)
{
encode(buffer,field);
}
if (LOG.isDebugEnabled())
LOG.debug(String.format("CtxTbl[%x] encoded %d octets",_context.hashCode(), buffer.position() - pos));
@ -179,7 +180,7 @@ public class HpackEncoder
private void encode(ByteBuffer buffer, HttpField field)
{
final int p=LOG.isDebugEnabled()?buffer.position():-1;
final int p=_debug?buffer.position():-1;
String encoding=null;
@ -190,16 +191,24 @@ public class HpackEncoder
if (entry!=null)
{
// Known field entry, so encode it as indexed
int index=_context.index(entry);
if (p>=0)
encoding="IdxField"+(entry.isStatic()?"S":"")+(1+NBitInteger.octectsNeeded(7,index));
buffer.put((byte)0x80);
NBitInteger.encode(buffer,7,index);
if (entry.isStatic())
{
buffer.put(((StaticEntry)entry).getEncodedField());
if (_debug)
encoding="IdxFieldS1";
}
else
{
int index=_context.index(entry);
buffer.put((byte)0x80);
NBitInteger.encode(buffer,7,index);
if (_debug)
encoding="IdxField"+(entry.isStatic()?"S":"")+(1+NBitInteger.octectsNeeded(7,index));
}
}
else
{
// Unknown field entry, so we will have to send literally.
final Entry name;
final boolean indexed;
final boolean never_index;
@ -211,6 +220,7 @@ public class HpackEncoder
if (header==null)
{
name = _context.get(field.getName());
// has the custom header name been seen before?
if (name==null)
{
@ -226,7 +236,7 @@ public class HpackEncoder
else
{
// known custom name, but unknown value.
// This is probably a custom field with changing value, so don't index now.
// This is probably a custom field with changing value, so don't index.
indexed=false;
never_index=false;
huffman=true;
@ -267,7 +277,7 @@ public class HpackEncoder
}
}
if (p>=0)
if (_debug)
{
encoding="Lit"+
((name==null)?"HuffN":("IdxN"+(name.isStatic()?"S":"")+(1+NBitInteger.octectsNeeded(bits,_context.index(name)))))+
@ -316,7 +326,7 @@ public class HpackEncoder
_context.add(field);
}
if (p>=0)
if (_debug)
{
int e=buffer.position();
if (LOG.isDebugEnabled())

View File

@ -72,9 +72,9 @@ public class MetaDataBuilder
if (_size>_maxSize)
throw new BadMessageException(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413,"Header size "+_size+">"+_maxSize);
if (field instanceof StaticValueHttpField)
if (field instanceof StaticTableHttpField)
{
StaticValueHttpField value = (StaticValueHttpField)field;
StaticTableHttpField value = (StaticTableHttpField)field;
switch(field.getHeader())
{
case C_STATUS:
@ -98,7 +98,7 @@ public class MetaDataBuilder
switch(field.getHeader())
{
case C_STATUS:
_status=Integer.parseInt(field.getValue());
_status=field.getIntValue();
break;
case C_METHOD:
@ -114,6 +114,7 @@ public class MetaDataBuilder
break;
case HOST:
// :authority fields must come first. If we have one, ignore the host header as far as authority goes.
if (_authority==null)
_authority=(field instanceof HostPortHttpField)?((HostPortHttpField)field):new AuthorityHttpField(field.getValue());
_fields.add(field);

View File

@ -23,19 +23,11 @@ import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpHeader;
/* ------------------------------------------------------------ */
public class StaticValueHttpField extends HttpField
public class StaticTableHttpField extends HttpField
{
private final Object _value;
public StaticValueHttpField(HttpHeader header,String name, String valueString, Object value)
{
super(header,name,valueString);
if (value==null)
throw new IllegalArgumentException();
_value=value;
}
public StaticValueHttpField(HttpHeader header,String valueString, Object value)
public StaticTableHttpField(HttpHeader header,String valueString, Object value)
{
super(header,header.asString(),valueString);
if (value==null)
@ -43,7 +35,7 @@ public class StaticValueHttpField extends HttpField
_value=value;
}
public StaticValueHttpField(String name, String valueString, Object value)
public StaticTableHttpField(String name, String valueString, Object value)
{
super(name,valueString);
if (value==null)