header table mostly functional
This commit is contained in:
parent
1da95c974d
commit
58ed30e710
|
@ -29,6 +29,7 @@ public class Field extends HttpField
|
||||||
{
|
{
|
||||||
// final ByteBuffer _nameLiteral;
|
// final ByteBuffer _nameLiteral;
|
||||||
// final ByteBuffer _nameHuffman;
|
// final ByteBuffer _nameHuffman;
|
||||||
|
private final NameKey _nameKey=new NameKey();
|
||||||
|
|
||||||
public Field(String name,String value)
|
public Field(String name,String value)
|
||||||
{
|
{
|
||||||
|
@ -66,8 +67,27 @@ public class Field extends HttpField
|
||||||
_nameHuffman.position(_nameHuffman.limit());
|
_nameHuffman.position(_nameHuffman.limit());
|
||||||
BufferUtil.flipToFlush(_nameHuffman,0);
|
BufferUtil.flipToFlush(_nameHuffman,0);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public NameKey getNameKey()
|
||||||
|
{
|
||||||
|
return _nameKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class NameKey
|
||||||
|
{
|
||||||
|
|
||||||
|
public Field getField()
|
||||||
|
{
|
||||||
|
return Field.this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return getName();
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,91 +0,0 @@
|
||||||
//
|
|
||||||
// ========================================================================
|
|
||||||
// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
// All rights reserved. This program and the accompanying materials
|
|
||||||
// are made available under the terms of the Eclipse Public License v1.0
|
|
||||||
// and Apache License v2.0 which accompanies this distribution.
|
|
||||||
//
|
|
||||||
// The Eclipse Public License is available at
|
|
||||||
// http://www.eclipse.org/legal/epl-v10.html
|
|
||||||
//
|
|
||||||
// The Apache License v2.0 is available at
|
|
||||||
// http://www.opensource.org/licenses/apache2.0.php
|
|
||||||
//
|
|
||||||
// You may elect to redistribute this code under either of these licenses.
|
|
||||||
// ========================================================================
|
|
||||||
//
|
|
||||||
|
|
||||||
package org.eclipse.jetty.hpack;
|
|
||||||
|
|
||||||
public class HeaderTable
|
|
||||||
{
|
|
||||||
|
|
||||||
private static final String[][] STATIC_TABLE =
|
|
||||||
{
|
|
||||||
{null,null},
|
|
||||||
/* 1 */ {":authority" ,""},
|
|
||||||
/* 2 */ {":method" ,"GET"},
|
|
||||||
/* 3 */ {":method" ,"POST"},
|
|
||||||
/* 4 */ {":path" ,"/"},
|
|
||||||
/* 5 */ {":path" ,"/index.html"},
|
|
||||||
/* 6 */ {":scheme" ,"http"},
|
|
||||||
/* 7 */ {":scheme" ,"https"},
|
|
||||||
/* 8 */ {":status" ,"200"},
|
|
||||||
/* 9 */ {":status" ,"204"},
|
|
||||||
/* 10 */ {":status" ,"206"},
|
|
||||||
/* 11 */ {":status" ,"304"},
|
|
||||||
/* 12 */ {":status" ,"400"},
|
|
||||||
/* 13 */ {":status" ,"404"},
|
|
||||||
/* 14 */ {":status" ,"500"},
|
|
||||||
/* 15 */ {"accept-charset" ,""},
|
|
||||||
/* 16 */ {"accept-encoding" ,""},
|
|
||||||
/* 17 */ {"accept-language" ,""},
|
|
||||||
/* 18 */ {"accept-ranges" ,""},
|
|
||||||
/* 19 */ {"accept" ,""},
|
|
||||||
/* 20 */ {"access-control-allow-origin" ,""},
|
|
||||||
/* 21 */ {"age" ,""},
|
|
||||||
/* 22 */ {"allow" ,""},
|
|
||||||
/* 23 */ {"authorization" ,""},
|
|
||||||
/* 24 */ {"cache-control" ,""},
|
|
||||||
/* 25 */ {"content-disposition" ,""},
|
|
||||||
/* 26 */ {"content-encoding" ,""},
|
|
||||||
/* 27 */ {"content-language" ,""},
|
|
||||||
/* 28 */ {"content-length" ,""},
|
|
||||||
/* 29 */ {"content-location" ,""},
|
|
||||||
/* 30 */ {"content-range" ,""},
|
|
||||||
/* 31 */ {"content-type" ,""},
|
|
||||||
/* 32 */ {"cookie" ,""},
|
|
||||||
/* 33 */ {"date" ,""},
|
|
||||||
/* 34 */ {"etag" ,""},
|
|
||||||
/* 35 */ {"expect" ,""},
|
|
||||||
/* 36 */ {"expires" ,""},
|
|
||||||
/* 37 */ {"from" ,""},
|
|
||||||
/* 38 */ {"host" ,""},
|
|
||||||
/* 39 */ {"if-match" ,""},
|
|
||||||
/* 40 */ {"if-modified-since" ,""},
|
|
||||||
/* 41 */ {"if-none-match" ,""},
|
|
||||||
/* 42 */ {"if-range" ,""},
|
|
||||||
/* 43 */ {"if-unmodified-since" ,""},
|
|
||||||
/* 44 */ {"last-modified" ,""},
|
|
||||||
/* 45 */ {"link" ,""},
|
|
||||||
/* 46 */ {"location" ,""},
|
|
||||||
/* 47 */ {"max-forwards" ,""},
|
|
||||||
/* 48 */ {"proxy-authenticate" ,""},
|
|
||||||
/* 49 */ {"proxy-authorization" ,""},
|
|
||||||
/* 50 */ {"range" ,""},
|
|
||||||
/* 51 */ {"referer" ,""},
|
|
||||||
/* 52 */ {"refresh" ,""},
|
|
||||||
/* 53 */ {"retry-after" ,""},
|
|
||||||
/* 54 */ {"server" ,""},
|
|
||||||
/* 55 */ {"set-cookie" ,""},
|
|
||||||
/* 56 */ {"strict-transport-security" ,""},
|
|
||||||
/* 57 */ {"transfer-encoding" ,""},
|
|
||||||
/* 58 */ {"user-agent" ,""},
|
|
||||||
/* 59 */ {"vary" ,""},
|
|
||||||
/* 60 */ {"via" ,""},
|
|
||||||
/* 61 */ {"www-authenticate" ,""},
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,324 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// All rights reserved. This program and the accompanying materials
|
||||||
|
// are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
// and Apache License v2.0 which accompanies this distribution.
|
||||||
|
//
|
||||||
|
// The Eclipse Public License is available at
|
||||||
|
// http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
//
|
||||||
|
// The Apache License v2.0 is available at
|
||||||
|
// http://www.opensource.org/licenses/apache2.0.php
|
||||||
|
//
|
||||||
|
// You may elect to redistribute this code under either of these licenses.
|
||||||
|
// ========================================================================
|
||||||
|
//
|
||||||
|
|
||||||
|
package org.eclipse.jetty.hpack;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.hpack.Field.NameKey;
|
||||||
|
import org.eclipse.jetty.http.HttpField;
|
||||||
|
import org.eclipse.jetty.util.ArrayQueue;
|
||||||
|
import org.eclipse.jetty.util.ArrayTrie;
|
||||||
|
import org.eclipse.jetty.util.StringUtil;
|
||||||
|
import org.eclipse.jetty.util.Trie;
|
||||||
|
|
||||||
|
public class HpackContext
|
||||||
|
{
|
||||||
|
private static final String[][] STATIC_TABLE =
|
||||||
|
{
|
||||||
|
{null,null},
|
||||||
|
/* 1 */ {":authority" ,null},
|
||||||
|
/* 2 */ {":method" ,"GET"},
|
||||||
|
/* 3 */ {":method" ,"POST"},
|
||||||
|
/* 4 */ {":path" ,"/"},
|
||||||
|
/* 5 */ {":path" ,"/index.html"},
|
||||||
|
/* 6 */ {":scheme" ,"http"},
|
||||||
|
/* 7 */ {":scheme" ,"https"},
|
||||||
|
/* 8 */ {":status" ,"200"},
|
||||||
|
/* 9 */ {":status" ,"204"},
|
||||||
|
/* 10 */ {":status" ,"206"},
|
||||||
|
/* 11 */ {":status" ,"304"},
|
||||||
|
/* 12 */ {":status" ,"400"},
|
||||||
|
/* 13 */ {":status" ,"404"},
|
||||||
|
/* 14 */ {":status" ,"500"},
|
||||||
|
/* 15 */ {"accept-charset" ,null},
|
||||||
|
/* 16 */ {"accept-encoding" ,null},
|
||||||
|
/* 17 */ {"accept-language" ,null},
|
||||||
|
/* 18 */ {"accept-ranges" ,null},
|
||||||
|
/* 19 */ {"accept" ,null},
|
||||||
|
/* 20 */ {"access-control-allow-origin" ,null},
|
||||||
|
/* 21 */ {"age" ,null},
|
||||||
|
/* 22 */ {"allow" ,null},
|
||||||
|
/* 23 */ {"authorization" ,null},
|
||||||
|
/* 24 */ {"cache-control" ,null},
|
||||||
|
/* 25 */ {"content-disposition" ,null},
|
||||||
|
/* 26 */ {"content-encoding" ,null},
|
||||||
|
/* 27 */ {"content-language" ,null},
|
||||||
|
/* 28 */ {"content-length" ,null},
|
||||||
|
/* 29 */ {"content-location" ,null},
|
||||||
|
/* 30 */ {"content-range" ,null},
|
||||||
|
/* 31 */ {"content-type" ,null},
|
||||||
|
/* 32 */ {"cookie" ,null},
|
||||||
|
/* 33 */ {"date" ,null},
|
||||||
|
/* 34 */ {"etag" ,null},
|
||||||
|
/* 35 */ {"expect" ,null},
|
||||||
|
/* 36 */ {"expires" ,null},
|
||||||
|
/* 37 */ {"from" ,null},
|
||||||
|
/* 38 */ {"host" ,null},
|
||||||
|
/* 39 */ {"if-match" ,null},
|
||||||
|
/* 40 */ {"if-modified-since" ,null},
|
||||||
|
/* 41 */ {"if-none-match" ,null},
|
||||||
|
/* 42 */ {"if-range" ,null},
|
||||||
|
/* 43 */ {"if-unmodified-since" ,null},
|
||||||
|
/* 44 */ {"last-modified" ,null},
|
||||||
|
/* 45 */ {"link" ,null},
|
||||||
|
/* 46 */ {"location" ,null},
|
||||||
|
/* 47 */ {"max-forwards" ,null},
|
||||||
|
/* 48 */ {"proxy-authenticate" ,null},
|
||||||
|
/* 49 */ {"proxy-authorization" ,null},
|
||||||
|
/* 50 */ {"range" ,null},
|
||||||
|
/* 51 */ {"referer" ,null},
|
||||||
|
/* 52 */ {"refresh" ,null},
|
||||||
|
/* 53 */ {"retry-after" ,null},
|
||||||
|
/* 54 */ {"server" ,null},
|
||||||
|
/* 55 */ {"set-cookie" ,null},
|
||||||
|
/* 56 */ {"strict-transport-security" ,null},
|
||||||
|
/* 57 */ {"transfer-encoding" ,null},
|
||||||
|
/* 58 */ {"user-agent" ,null},
|
||||||
|
/* 59 */ {"vary" ,null},
|
||||||
|
/* 60 */ {"via" ,null},
|
||||||
|
/* 61 */ {"www-authenticate" ,null},
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
private static final Map<HttpField,Entry> __staticFieldMap = new HashMap<>();
|
||||||
|
private static final Trie<Entry> __staticNameMap = new ArrayTrie<>(24);
|
||||||
|
|
||||||
|
private static final Entry[] __staticTable=new Entry[STATIC_TABLE.length];
|
||||||
|
static
|
||||||
|
{
|
||||||
|
Set<String> added = new HashSet<>();
|
||||||
|
for (int i=1;i<STATIC_TABLE.length;i++)
|
||||||
|
{
|
||||||
|
Entry entry=new Entry(i,STATIC_TABLE[i][0],STATIC_TABLE[i][1],true);
|
||||||
|
__staticTable[i]=entry;
|
||||||
|
if (entry._field.getValue()!=null)
|
||||||
|
__staticFieldMap.put(entry._field,entry);
|
||||||
|
if (!added.contains(entry._field.getName()))
|
||||||
|
{
|
||||||
|
added.add(entry._field.getName());
|
||||||
|
__staticNameMap.put(entry._field.getName(),entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int _maxHeaderTableSize;
|
||||||
|
private int _headerTableSize;
|
||||||
|
private final Entry _refSet=new Entry(true);
|
||||||
|
private final ArrayQueue<Entry> _headerTable;
|
||||||
|
private final Map<HttpField,Entry> _fieldMap = new HashMap<>();
|
||||||
|
private final Map<String,Entry> _nameMap = new HashMap<>();
|
||||||
|
|
||||||
|
|
||||||
|
HpackContext(int maxHeaderTableSize)
|
||||||
|
{
|
||||||
|
_maxHeaderTableSize=maxHeaderTableSize;
|
||||||
|
int guesstimateEntries = 10+maxHeaderTableSize/(32+10+10);
|
||||||
|
_headerTable=new HeaderTable(guesstimateEntries,guesstimateEntries+10);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Entry get(HttpField field)
|
||||||
|
{
|
||||||
|
System.err.println(field);
|
||||||
|
System.err.println(_fieldMap);
|
||||||
|
System.err.println(__staticFieldMap);
|
||||||
|
Entry entry = _fieldMap.get(field);
|
||||||
|
if (entry==null)
|
||||||
|
entry=__staticFieldMap.get(field);
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Entry getNameEntry(String name)
|
||||||
|
{
|
||||||
|
Entry entry = __staticNameMap.get(name);
|
||||||
|
if (entry!=null)
|
||||||
|
return entry;
|
||||||
|
return _nameMap.get(StringUtil.asciiToLowerCase(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Entry add(HttpField field)
|
||||||
|
{
|
||||||
|
int i=_headerTable.getNextIndexUnsafe();
|
||||||
|
Entry entry=new Entry(i,field,false);
|
||||||
|
int size = entry.getSize();
|
||||||
|
if (size>_maxHeaderTableSize)
|
||||||
|
return null;
|
||||||
|
_headerTableSize+=size;
|
||||||
|
_headerTable.addUnsafe(entry);
|
||||||
|
_fieldMap.put(field,entry);
|
||||||
|
_nameMap.put(StringUtil.asciiToLowerCase(field.getName()),entry);
|
||||||
|
|
||||||
|
evict();
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void evict()
|
||||||
|
{
|
||||||
|
while (_headerTableSize>_maxHeaderTableSize)
|
||||||
|
{
|
||||||
|
Entry entry = _headerTable.pollUnsafe();
|
||||||
|
_headerTableSize-=entry.getSize();
|
||||||
|
entry.removeFromRefSet();
|
||||||
|
_fieldMap.remove(entry.getHttpField());
|
||||||
|
String lc=StringUtil.asciiToLowerCase(entry.getHttpField().getName());
|
||||||
|
if (entry==_nameMap.get(lc))
|
||||||
|
_nameMap.remove(lc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
private class HeaderTable extends ArrayQueue<HpackContext.Entry>
|
||||||
|
{
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/**
|
||||||
|
* @param initCapacity
|
||||||
|
* @param growBy
|
||||||
|
*/
|
||||||
|
private HeaderTable(int initCapacity, int growBy)
|
||||||
|
{
|
||||||
|
super(initCapacity,growBy);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/**
|
||||||
|
* @see org.eclipse.jetty.util.ArrayQueue#growUnsafe()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void growUnsafe(int newCapacity)
|
||||||
|
{
|
||||||
|
// Relay on super.growUnsafe to pack all entries 0 to _nextSlot
|
||||||
|
super.growUnsafe(newCapacity);
|
||||||
|
for (int i=0;i<_nextSlot;i++)
|
||||||
|
((Entry)_elements[i])._index=i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/**
|
||||||
|
* @see org.eclipse.jetty.util.ArrayQueue#enqueue(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean enqueue(Entry e)
|
||||||
|
{
|
||||||
|
return super.enqueue(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/**
|
||||||
|
* @see org.eclipse.jetty.util.ArrayQueue#dequeue()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Entry dequeue()
|
||||||
|
{
|
||||||
|
return super.dequeue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
public static class Entry
|
||||||
|
{
|
||||||
|
int _index;
|
||||||
|
final boolean _static;
|
||||||
|
final HttpField _field;
|
||||||
|
Entry _refSetNext=this;
|
||||||
|
Entry _refSetPrev=this;
|
||||||
|
boolean _refSetUsed;
|
||||||
|
|
||||||
|
Entry(boolean isStatic)
|
||||||
|
{
|
||||||
|
_static=isStatic;
|
||||||
|
_index=0;
|
||||||
|
_field=null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Entry(int index,String name, String value, boolean isStatic)
|
||||||
|
{
|
||||||
|
_static=isStatic;
|
||||||
|
_index=index;
|
||||||
|
_field=new HttpField(name,value);
|
||||||
|
}
|
||||||
|
|
||||||
|
Entry(int index, HttpField field, boolean isStatic)
|
||||||
|
{
|
||||||
|
_static=isStatic;
|
||||||
|
_index=index;
|
||||||
|
_field=field;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addToRefSet(HpackContext ctx)
|
||||||
|
{
|
||||||
|
_refSetNext=ctx._refSet;
|
||||||
|
_refSetPrev=ctx._refSet._refSetPrev;
|
||||||
|
ctx._refSet._refSetPrev._refSetNext=this;
|
||||||
|
ctx._refSet._refSetPrev=this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeFromRefSet()
|
||||||
|
{
|
||||||
|
if (_refSetNext!=this)
|
||||||
|
{
|
||||||
|
_refSetNext._refSetPrev=_refSetPrev;
|
||||||
|
_refSetPrev._refSetNext=_refSetNext;
|
||||||
|
_refSetNext=this;
|
||||||
|
_refSetPrev=this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSize()
|
||||||
|
{
|
||||||
|
return 32+_field.getName().length()+_field.getValue().length();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public HttpField getHttpField()
|
||||||
|
{
|
||||||
|
return _field;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean isStatic()
|
||||||
|
{
|
||||||
|
return _static;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return String.format("{%s,%d,%s,%x}",_static?"S":"D",_index,_field,hashCode());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,120 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// All rights reserved. This program and the accompanying materials
|
||||||
|
// are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
// and Apache License v2.0 which accompanies this distribution.
|
||||||
|
//
|
||||||
|
// The Eclipse Public License is available at
|
||||||
|
// http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
//
|
||||||
|
// The Apache License v2.0 is available at
|
||||||
|
// http://www.opensource.org/licenses/apache2.0.php
|
||||||
|
//
|
||||||
|
// You may elect to redistribute this code under either of these licenses.
|
||||||
|
// ========================================================================
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
package org.eclipse.jetty.hpack;
|
||||||
|
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.hpack.HpackContext.Entry;
|
||||||
|
import org.eclipse.jetty.http.HttpField;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public class HpackContextTest
|
||||||
|
{
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStaticName()
|
||||||
|
{
|
||||||
|
HpackContext ctx = new HpackContext(4096);
|
||||||
|
Entry entry=ctx.getNameEntry(":method");
|
||||||
|
assertEquals(":method",entry.getHttpField().getName());
|
||||||
|
Assert.assertTrue(entry.isStatic());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEmptyAdd()
|
||||||
|
{
|
||||||
|
HpackContext ctx = new HpackContext(0);
|
||||||
|
HttpField field = new HttpField("foo","bar");
|
||||||
|
Assert.assertNull(ctx.add(field));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTooBigAdd()
|
||||||
|
{
|
||||||
|
HpackContext ctx = new HpackContext(37);
|
||||||
|
HttpField field = new HttpField("foo","bar");
|
||||||
|
Assert.assertNull(ctx.add(field));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testJustRight()
|
||||||
|
{
|
||||||
|
HpackContext ctx = new HpackContext(38);
|
||||||
|
HttpField field = new HttpField("foo","bar");
|
||||||
|
Assert.assertNotNull(ctx.add(field));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEvictOne()
|
||||||
|
{
|
||||||
|
HpackContext ctx = new HpackContext(38);
|
||||||
|
HttpField field0 = new HttpField("foo","bar");
|
||||||
|
|
||||||
|
assertEquals(field0,ctx.add(field0).getHttpField());
|
||||||
|
assertEquals(field0,ctx.getNameEntry("foo").getHttpField());
|
||||||
|
|
||||||
|
HttpField field1 = new HttpField("xxx","yyy");
|
||||||
|
assertEquals(field1,ctx.add(field1).getHttpField());
|
||||||
|
|
||||||
|
assertNull(ctx.get(field0));
|
||||||
|
assertNull(ctx.getNameEntry("foo"));
|
||||||
|
assertEquals(field1,ctx.get(field1).getHttpField());
|
||||||
|
assertEquals(field1,ctx.getNameEntry("xxx").getHttpField());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAddStatic()
|
||||||
|
{
|
||||||
|
HpackContext ctx = new HpackContext(4096);
|
||||||
|
|
||||||
|
// Look for the field. Should find static version.
|
||||||
|
HttpField methodGet = new HttpField(":method","GET");
|
||||||
|
assertEquals(methodGet,ctx.get(methodGet).getHttpField());
|
||||||
|
assertTrue(ctx.get(methodGet).isStatic());
|
||||||
|
|
||||||
|
// Add static version to header table
|
||||||
|
Entry e0=ctx.add(ctx.get(methodGet).getHttpField());
|
||||||
|
|
||||||
|
// Look again and should see dynamic version
|
||||||
|
assertEquals(methodGet,ctx.get(methodGet).getHttpField());
|
||||||
|
assertFalse(methodGet==ctx.get(methodGet).getHttpField());
|
||||||
|
assertFalse(ctx.get(methodGet).isStatic());
|
||||||
|
|
||||||
|
// Duplicates allows
|
||||||
|
Entry e1=ctx.add(ctx.get(methodGet).getHttpField());
|
||||||
|
|
||||||
|
// Look again and should see dynamic version
|
||||||
|
assertEquals(methodGet,ctx.get(methodGet).getHttpField());
|
||||||
|
assertFalse(methodGet==ctx.get(methodGet).getHttpField());
|
||||||
|
assertFalse(ctx.get(methodGet).isStatic());
|
||||||
|
assertFalse(e0==e1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -72,7 +72,7 @@ public class HttpField
|
||||||
return getName() + ": " + (v==null?"":v);
|
return getName() + ": " + (v==null?"":v);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSame(HttpField field)
|
public boolean isSameName(HttpField field)
|
||||||
{
|
{
|
||||||
if (field==null)
|
if (field==null)
|
||||||
return false;
|
return false;
|
||||||
|
@ -104,21 +104,27 @@ public class HttpField
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int nameHashCode()
|
||||||
|
{
|
||||||
|
int hash=13;
|
||||||
|
int len = _name.length();
|
||||||
|
for (int i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
char c = Character.toUpperCase(_name.charAt(i));
|
||||||
|
hash = 31 * hash + c;
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode()
|
public int hashCode()
|
||||||
{
|
{
|
||||||
if (_header==null)
|
if (_header==null)
|
||||||
{
|
return _value.hashCode() ^ nameHashCode();
|
||||||
int hash=13;
|
|
||||||
int len = _name.length();
|
|
||||||
for (int i = 0; i < len; i++)
|
|
||||||
{
|
|
||||||
char c = Character.toUpperCase(_name.charAt(i));
|
|
||||||
hash = 31 * hash + c;
|
|
||||||
}
|
|
||||||
return _value.hashCode() ^ hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _value.hashCode() ^ _header.hashCode();
|
return _value.hashCode() ^ _header.hashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -333,7 +333,7 @@ public class HttpFields implements Iterable<HttpField>
|
||||||
for (int i=_fields.size();i-->0;)
|
for (int i=_fields.size();i-->0;)
|
||||||
{
|
{
|
||||||
HttpField f=_fields.get(i);
|
HttpField f=_fields.get(i);
|
||||||
if (f.isSame(field))
|
if (f.isSameName(field))
|
||||||
{
|
{
|
||||||
if (put)
|
if (put)
|
||||||
_fields.remove(i);
|
_fields.remove(i);
|
||||||
|
|
|
@ -90,6 +90,15 @@ public class ArrayQueue<E> extends AbstractList<E> implements Queue<E>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/**
|
||||||
|
* @return the next index to be used
|
||||||
|
*/
|
||||||
|
public int getNextIndexUnsafe()
|
||||||
|
{
|
||||||
|
return _nextSlot;
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
@Override
|
@Override
|
||||||
public boolean add(E e)
|
public boolean add(E e)
|
||||||
|
@ -109,9 +118,9 @@ public class ArrayQueue<E> extends AbstractList<E> implements Queue<E>
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
private boolean enqueue(E e)
|
protected boolean enqueue(E e)
|
||||||
{
|
{
|
||||||
if (_size == _elements.length && !grow())
|
if (_size == _elements.length && !growUnsafe())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
_size++;
|
_size++;
|
||||||
|
@ -192,7 +201,7 @@ public class ArrayQueue<E> extends AbstractList<E> implements Queue<E>
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
private E dequeue()
|
protected E dequeue()
|
||||||
{
|
{
|
||||||
E e = at(_nextE);
|
E e = at(_nextE);
|
||||||
_elements[_nextE] = null;
|
_elements[_nextE] = null;
|
||||||
|
@ -339,7 +348,7 @@ public class ArrayQueue<E> extends AbstractList<E> implements Queue<E>
|
||||||
if (index < 0 || index > _size)
|
if (index < 0 || index > _size)
|
||||||
throw new IndexOutOfBoundsException("!(" + 0 + "<" + index + "<=" + _size + ")");
|
throw new IndexOutOfBoundsException("!(" + 0 + "<" + index + "<=" + _size + ")");
|
||||||
|
|
||||||
if (_size == _elements.length && !grow())
|
if (_size == _elements.length && !growUnsafe())
|
||||||
throw new IllegalStateException("Full");
|
throw new IllegalStateException("Full");
|
||||||
|
|
||||||
if (index == _size)
|
if (index == _size)
|
||||||
|
@ -384,25 +393,28 @@ public class ArrayQueue<E> extends AbstractList<E> implements Queue<E>
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
protected boolean grow()
|
protected void growUnsafe(int newCapacity)
|
||||||
{
|
{
|
||||||
synchronized (_lock)
|
Object[] elements = new Object[newCapacity];
|
||||||
{
|
|
||||||
if (_growCapacity <= 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Object[] elements = new Object[_elements.length + _growCapacity];
|
int split = _elements.length - _nextE;
|
||||||
|
if (split > 0)
|
||||||
|
System.arraycopy(_elements, _nextE, elements, 0, split);
|
||||||
|
if (_nextE != 0)
|
||||||
|
System.arraycopy(_elements, 0, elements, split, _nextSlot);
|
||||||
|
|
||||||
int split = _elements.length - _nextE;
|
_elements = elements;
|
||||||
if (split > 0)
|
_nextE = 0;
|
||||||
System.arraycopy(_elements, _nextE, elements, 0, split);
|
_nextSlot = _size;
|
||||||
if (_nextE != 0)
|
|
||||||
System.arraycopy(_elements, 0, elements, split, _nextSlot);
|
|
||||||
|
|
||||||
_elements = elements;
|
|
||||||
_nextE = 0;
|
|
||||||
_nextSlot = _size;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
protected boolean growUnsafe()
|
||||||
|
{
|
||||||
|
if (_growCapacity <= 0)
|
||||||
|
return false;
|
||||||
|
growUnsafe(_elements.length+_growCapacity);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue