From f39313b1d5187186706c08bb4d80d72389bee2ef Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Fri, 5 Feb 2021 18:48:54 +1100 Subject: [PATCH] Decouple the DynamicTable from the QpackContext. Signed-off-by: Lachlan Roberts --- .../src/main/java/module-info.java | 1 + .../jetty/http3/qpack/AuthorityHttpField.java | 1 + .../jetty/http3/qpack/QpackContext.java | 255 ++---------------- .../jetty/http3/qpack/QpackDecoder.java | 2 +- .../jetty/http3/qpack/QpackEncoder.java | 4 +- .../jetty/http3/qpack/table/DynamicTable.java | 157 +++++++++++ .../jetty/http3/qpack/table/Entry.java | 62 +++++ .../jetty/http3/qpack/table/StaticEntry.java | 56 ++++ .../http3/qpack/{ => table}/StaticTable.java | 33 +-- .../jetty/http3/qpack/QpackContextTest.java | 24 +- .../jetty/http3/qpack/QpackDecoderTest.java | 2 +- .../jetty/http3/qpack/QpackEncoderTest.java | 21 +- .../eclipse/jetty/http3/qpack/QpackTest.java | 17 +- 13 files changed, 351 insertions(+), 284 deletions(-) create mode 100644 jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/table/DynamicTable.java create mode 100644 jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/table/Entry.java create mode 100644 jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/table/StaticEntry.java rename jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/{ => table}/StaticTable.java (79%) diff --git a/jetty-http3/http3-qpack/src/main/java/module-info.java b/jetty-http3/http3-qpack/src/main/java/module-info.java index ff85d8fb4c9..41421a21ec1 100644 --- a/jetty-http3/http3-qpack/src/main/java/module-info.java +++ b/jetty-http3/http3-qpack/src/main/java/module-info.java @@ -17,6 +17,7 @@ import org.eclipse.jetty.http3.qpack.QpackFieldPreEncoder; module org.eclipse.jetty.http3.qpack { exports org.eclipse.jetty.http3.qpack; + exports org.eclipse.jetty.http3.qpack.table; requires transitive org.eclipse.jetty.http; requires org.slf4j; diff --git a/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/AuthorityHttpField.java b/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/AuthorityHttpField.java index ff257c5ebde..9d83368cbd8 100644 --- a/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/AuthorityHttpField.java +++ b/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/AuthorityHttpField.java @@ -15,6 +15,7 @@ package org.eclipse.jetty.http3.qpack; import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HttpHeader; +import org.eclipse.jetty.http3.qpack.table.StaticTable; /** * diff --git a/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/QpackContext.java b/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/QpackContext.java index d580b1bdb51..2a15bc3189f 100644 --- a/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/QpackContext.java +++ b/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/QpackContext.java @@ -13,13 +13,11 @@ package org.eclipse.jetty.http3.qpack; -import java.nio.ByteBuffer; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; - import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpHeader; +import org.eclipse.jetty.http3.qpack.table.DynamicTable; +import org.eclipse.jetty.http3.qpack.table.Entry; +import org.eclipse.jetty.http3.qpack.table.StaticTable; import org.eclipse.jetty.util.StringUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -36,35 +34,23 @@ public class QpackContext { public static final Logger LOG = LoggerFactory.getLogger(QpackContext.class); private static final StaticTable __staticTable = new StaticTable(); - private final DynamicTable _dynamicTable; - private int _maxDynamicTableSizeInBytes; - private int _dynamicTableSizeInBytes; - - private final Map _fieldMap = new HashMap<>(); - private final Map _nameMap = new HashMap<>(); - QpackContext(int maxDynamicTableSize) { - _maxDynamicTableSizeInBytes = maxDynamicTableSize; - int guesstimateEntries = 10 + maxDynamicTableSize / (32 + 10 + 10); - _dynamicTable = new DynamicTable(guesstimateEntries); + _dynamicTable = new DynamicTable(maxDynamicTableSize); if (LOG.isDebugEnabled()) LOG.debug(String.format("HdrTbl[%x] created max=%d", hashCode(), maxDynamicTableSize)); } public void resize(int newMaxDynamicTableSize) { - if (LOG.isDebugEnabled()) - LOG.debug(String.format("HdrTbl[%x] resized max=%d->%d", hashCode(), _maxDynamicTableSizeInBytes, newMaxDynamicTableSize)); - _maxDynamicTableSizeInBytes = newMaxDynamicTableSize; - _dynamicTable.evict(); + _dynamicTable.setCapacity(newMaxDynamicTableSize); } public Entry get(HttpField field) { - Entry entry = _fieldMap.get(field); + Entry entry = _dynamicTable.get(field); if (entry == null) entry = __staticTable.get(field); return entry; @@ -75,7 +61,7 @@ public class QpackContext Entry entry = __staticTable.get(name); if (entry != null) return entry; - return _nameMap.get(StringUtil.asciiToLowerCase(name)); + return _dynamicTable.get(StringUtil.asciiToLowerCase(name)); } public Entry get(int index) @@ -96,32 +82,15 @@ public class QpackContext public Entry add(HttpField field) { - Entry entry = new Entry(field); - int size = entry.getSize(); - if (size > _maxDynamicTableSizeInBytes) - { - if (LOG.isDebugEnabled()) - LOG.debug(String.format("HdrTbl[%x] !added size %d>%d", hashCode(), size, _maxDynamicTableSizeInBytes)); - _dynamicTable.evictAll(); - return null; - } - _dynamicTableSizeInBytes += size; - _dynamicTable.add(entry); - _fieldMap.put(field, entry); - _nameMap.put(field.getLowerCaseName(), entry); - - if (LOG.isDebugEnabled()) - LOG.debug(String.format("HdrTbl[%x] added %s", hashCode(), entry)); - _dynamicTable.evict(); - return entry; + return _dynamicTable.add(new Entry(field)); } /** * @return Current dynamic table size in entries */ - public int size() + public int getNumEntries() { - return _dynamicTable.size(); + return _dynamicTable.getNumEntries(); } /** @@ -129,7 +98,7 @@ public class QpackContext */ public int getDynamicTableSize() { - return _dynamicTableSizeInBytes; + return _dynamicTable.getSize(); } /** @@ -137,19 +106,25 @@ public class QpackContext */ public int getMaxDynamicTableSize() { - return _maxDynamicTableSizeInBytes; + return _dynamicTable.getMaxSize(); } + /** + * @return index of entry in COMBINED address space (QPACK has separate address spaces for dynamic and static tables). + */ public int index(Entry entry) { - if (entry._slot < 0) + if (entry.getIndex() < 0) return 0; if (entry.isStatic()) - return entry._slot; + return entry.getIndex(); return _dynamicTable.index(entry); } + /** + * @return index of entry in the static table or 0 if not in the table (I guess the entries start from 1 not 0 unlike QPACK). + */ public static int staticIndex(HttpHeader header) { if (header == null) @@ -157,194 +132,6 @@ public class QpackContext Entry entry = __staticTable.get(header.asString()); if (entry == null) return 0; - return entry._slot; - } - - @Override - public String toString() - { - return String.format("QpackContext@%x{entries=%d,size=%d,max=%d}", hashCode(), _dynamicTable.size(), _dynamicTableSizeInBytes, _maxDynamicTableSizeInBytes); - } - - private class DynamicTable - { - Entry[] _entries; - int _size; - int _offset; - int _growby; - - private DynamicTable(int initCapacity) - { - _entries = new Entry[initCapacity]; - _growby = initCapacity; - } - - public void add(Entry entry) - { - if (_size == _entries.length) - { - Entry[] entries = new Entry[_entries.length + _growby]; - for (int i = 0; i < _size; i++) - { - int slot = (_offset + i) % _entries.length; - entries[i] = _entries[slot]; - entries[i]._slot = i; - } - _entries = entries; - _offset = 0; - } - int slot = (_size++ + _offset) % _entries.length; - _entries[slot] = entry; - entry._slot = slot; - } - - public int index(Entry entry) - { - return StaticTable.STATIC_SIZE + _size - (entry._slot - _offset + _entries.length) % _entries.length; - } - - public Entry get(int index) - { - int d = index - StaticTable.STATIC_SIZE - 1; - if (d < 0 || d >= _size) - return null; - int slot = (_offset + _size - d - 1) % _entries.length; - return _entries[slot]; - } - - public int size() - { - return _size; - } - - private void evict() - { - while (_dynamicTableSizeInBytes > _maxDynamicTableSizeInBytes) - { - Entry entry = _entries[_offset]; - _entries[_offset] = null; - _offset = (_offset + 1) % _entries.length; - _size--; - if (LOG.isDebugEnabled()) - LOG.debug(String.format("HdrTbl[%x] evict %s", QpackContext.this.hashCode(), entry)); - _dynamicTableSizeInBytes -= entry.getSize(); - entry._slot = -1; - _fieldMap.remove(entry.getHttpField()); - String lc = entry.getHttpField().getLowerCaseName(); - if (entry == _nameMap.get(lc)) - _nameMap.remove(lc); - } - if (LOG.isDebugEnabled()) - LOG.debug(String.format("HdrTbl[%x] entries=%d, size=%d, max=%d", QpackContext.this.hashCode(), _dynamicTable.size(), _dynamicTableSizeInBytes, _maxDynamicTableSizeInBytes)); - } - - private void evictAll() - { - if (LOG.isDebugEnabled()) - LOG.debug(String.format("HdrTbl[%x] evictAll", QpackContext.this.hashCode())); - if (size() > 0) - { - _fieldMap.clear(); - _nameMap.clear(); - _offset = 0; - _size = 0; - _dynamicTableSizeInBytes = 0; - Arrays.fill(_entries, null); - } - } - } - - public static class Entry - { - final HttpField _field; - int _slot; // The index within it's array - - Entry() - { - _slot = -1; - _field = null; - } - - Entry(HttpField field) - { - _field = field; - } - - public int getSize() - { - String value = _field.getValue(); - return 32 + _field.getName().length() + (value == null ? 0 : value.length()); - } - - public HttpField getHttpField() - { - return _field; - } - - public boolean isStatic() - { - return false; - } - - public byte[] getStaticHuffmanValue() - { - return null; - } - - @Override - public String toString() - { - return String.format("{%s,%d,%s,%x}", isStatic() ? "S" : "D", _slot, _field, hashCode()); - } - } - - public static class StaticEntry extends Entry - { - private final byte[] _huffmanValue; - private final byte _encodedField; - - StaticEntry(int index, HttpField field) - { - super(field); - _slot = index; - String value = field.getValue(); - if (value != null && value.length() > 0) - { - int huffmanLen = Huffman.octetsNeeded(value); - if (huffmanLen < 0) - throw new IllegalStateException("bad value"); - int lenLen = NBitInteger.octectsNeeded(7, huffmanLen); - _huffmanValue = new byte[1 + lenLen + huffmanLen]; - ByteBuffer buffer = ByteBuffer.wrap(_huffmanValue); - - // Indicate Huffman - buffer.put((byte)0x80); - // Add huffman length - NBitInteger.encode(buffer, 7, huffmanLen); - // Encode value - Huffman.encode(buffer, value); - } - else - _huffmanValue = null; - - _encodedField = (byte)(0x80 | index); - } - - @Override - public boolean isStatic() - { - return true; - } - - @Override - public byte[] getStaticHuffmanValue() - { - return _huffmanValue; - } - - public byte getEncodedField() - { - return _encodedField; - } + return entry.getIndex(); } } diff --git a/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/QpackDecoder.java b/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/QpackDecoder.java index 6d9f5ec484e..2ed19b6a59a 100644 --- a/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/QpackDecoder.java +++ b/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/QpackDecoder.java @@ -19,7 +19,7 @@ import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpTokens; import org.eclipse.jetty.http.MetaData; -import org.eclipse.jetty.http3.qpack.QpackContext.Entry; +import org.eclipse.jetty.http3.qpack.table.Entry; import org.eclipse.jetty.util.BufferUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/QpackEncoder.java b/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/QpackEncoder.java index 4b07ac626d7..391eea5b7a0 100644 --- a/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/QpackEncoder.java +++ b/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/QpackEncoder.java @@ -29,8 +29,8 @@ import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http.PreEncodedHttpField; -import org.eclipse.jetty.http3.qpack.QpackContext.Entry; -import org.eclipse.jetty.http3.qpack.QpackContext.StaticEntry; +import org.eclipse.jetty.http3.qpack.table.Entry; +import org.eclipse.jetty.http3.qpack.table.StaticEntry; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.StringUtil; import org.slf4j.Logger; diff --git a/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/table/DynamicTable.java b/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/table/DynamicTable.java new file mode 100644 index 00000000000..a3818f69e5f --- /dev/null +++ b/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/table/DynamicTable.java @@ -0,0 +1,157 @@ +package org.eclipse.jetty.http3.qpack.table; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.jetty.http.HttpField; +import org.eclipse.jetty.http3.qpack.QpackContext; + +public class DynamicTable +{ + public static final int FIRST_INDEX = StaticTable.STATIC_SIZE + 1; + private int _maxDynamicTableSizeInBytes; + private int _dynamicTableSizeInBytes; + + private final Map _fieldMap = new HashMap<>(); + private final Map _nameMap = new HashMap<>(); + private final int _growby; + + private Entry[] _entries; + private int _numEntries; + private int _offset; + + public DynamicTable(int maxSize) + { + _maxDynamicTableSizeInBytes = maxSize; + int initCapacity = 10 + maxSize / (32 + 10 + 10); + _entries = new Entry[initCapacity]; + _growby = initCapacity; + } + + public Entry add(Entry entry) + { + int size = entry.getSize(); + if (size > _maxDynamicTableSizeInBytes) + { + if (QpackContext.LOG.isDebugEnabled()) + QpackContext.LOG.debug(String.format("HdrTbl[%x] !added size %d>%d", hashCode(), size, _maxDynamicTableSizeInBytes)); + evictAll(); + return null; + } + _dynamicTableSizeInBytes += size; + + if (_numEntries == _entries.length) + { + Entry[] entries = new Entry[_entries.length + _growby]; + for (int i = 0; i < _numEntries; i++) + { + int slot = (_offset + i) % _entries.length; + entries[i] = _entries[slot]; + entries[i].setIndex(i); + } + _entries = entries; + _offset = 0; + } + int slot = (_numEntries++ + _offset) % _entries.length; + _entries[slot] = entry; + entry.setIndex(slot); + + _fieldMap.put(entry.getHttpField(), entry); + _nameMap.put(entry.getHttpField().getLowerCaseName(), entry); + + if (QpackContext.LOG.isDebugEnabled()) + QpackContext.LOG.debug(String.format("HdrTbl[%x] added %s", hashCode(), entry)); + evict(); + return entry; + } + + public int index(Entry entry) + { + return StaticTable.STATIC_SIZE + _numEntries - (entry.getIndex() - _offset + _entries.length) % _entries.length; + } + + public Entry get(int index) + { + int d = index - StaticTable.STATIC_SIZE - 1; + if (d < 0 || d >= _numEntries) + return null; + int slot = (_offset + _numEntries - d - 1) % _entries.length; + return _entries[slot]; + } + + public Entry get(String name) + { + return _nameMap.get(name); + } + + public Entry get(HttpField field) + { + return _fieldMap.get(field); + } + + public int getSize() + { + return _dynamicTableSizeInBytes; + } + + public int getMaxSize() + { + return _maxDynamicTableSizeInBytes; + } + + public int getNumEntries() + { + return _numEntries; + } + + public void setCapacity(int capacity) + { + if (QpackContext.LOG.isDebugEnabled()) + QpackContext.LOG.debug(String.format("HdrTbl[%x] resized max=%d->%d", hashCode(), _maxDynamicTableSizeInBytes, capacity)); + _maxDynamicTableSizeInBytes = capacity; + evict(); + } + + private void evict() + { + while (_dynamicTableSizeInBytes > _maxDynamicTableSizeInBytes) + { + Entry entry = _entries[_offset]; + _entries[_offset] = null; + _offset = (_offset + 1) % _entries.length; + _numEntries--; + if (QpackContext.LOG.isDebugEnabled()) + QpackContext.LOG.debug(String.format("HdrTbl[%x] evict %s", hashCode(), entry)); + _dynamicTableSizeInBytes -= entry.getSize(); + entry.setIndex(-1); + _fieldMap.remove(entry.getHttpField()); + String lc = entry.getHttpField().getLowerCaseName(); + if (entry == _nameMap.get(lc)) + _nameMap.remove(lc); + } + if (QpackContext.LOG.isDebugEnabled()) + QpackContext.LOG.debug(String.format("HdrTbl[%x] entries=%d, size=%d, max=%d", hashCode(), getNumEntries(), _dynamicTableSizeInBytes, _maxDynamicTableSizeInBytes)); + } + + private void evictAll() + { + if (QpackContext.LOG.isDebugEnabled()) + QpackContext.LOG.debug(String.format("HdrTbl[%x] evictAll", hashCode())); + if (getNumEntries() > 0) + { + _fieldMap.clear(); + _nameMap.clear(); + _offset = 0; + _numEntries = 0; + _dynamicTableSizeInBytes = 0; + Arrays.fill(_entries, null); + } + } + + @Override + public String toString() + { + return String.format("%s@%x{entries=%d,size=%d,max=%d}", getClass().getSimpleName(), hashCode(), getNumEntries(), _dynamicTableSizeInBytes, _maxDynamicTableSizeInBytes); + } +} diff --git a/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/table/Entry.java b/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/table/Entry.java new file mode 100644 index 00000000000..0ee4043148d --- /dev/null +++ b/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/table/Entry.java @@ -0,0 +1,62 @@ +package org.eclipse.jetty.http3.qpack.table; + +import org.eclipse.jetty.http.HttpField; + +public class Entry +{ + final HttpField _field; + private int _slot; // The index within it's array + + public Entry() + { + this(-1, null); + } + + public Entry(HttpField field) + { + this(-1, field); + } + + public Entry(int index, HttpField field) + { + _field = field; + _slot = index; + } + + public int getSize() + { + String value = _field.getValue(); + return 32 + _field.getName().length() + (value == null ? 0 : value.length()); + } + + public void setIndex(int index) + { + _slot = index; + } + + public int getIndex() + { + return _slot; + } + + public HttpField getHttpField() + { + return _field; + } + + public boolean isStatic() + { + return false; + } + + public byte[] getStaticHuffmanValue() + { + return null; + } + + @Override + public String toString() + { + return String.format("{%s,%d,%s,%x}", isStatic() ? "S" : "D", _slot, _field, hashCode()); + } +} diff --git a/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/table/StaticEntry.java b/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/table/StaticEntry.java new file mode 100644 index 00000000000..767b56f782a --- /dev/null +++ b/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/table/StaticEntry.java @@ -0,0 +1,56 @@ +package org.eclipse.jetty.http3.qpack.table; + +import java.nio.ByteBuffer; + +import org.eclipse.jetty.http.HttpField; +import org.eclipse.jetty.http3.qpack.Huffman; +import org.eclipse.jetty.http3.qpack.NBitInteger; + +public class StaticEntry extends Entry +{ + private final byte[] _huffmanValue; + private final byte _encodedField; + + StaticEntry(int index, HttpField field) + { + super(index, field); + String value = field.getValue(); + if (value != null && value.length() > 0) + { + int huffmanLen = Huffman.octetsNeeded(value); + if (huffmanLen < 0) + throw new IllegalStateException("bad value"); + int lenLen = NBitInteger.octectsNeeded(7, huffmanLen); + _huffmanValue = new byte[1 + lenLen + huffmanLen]; + ByteBuffer buffer = ByteBuffer.wrap(_huffmanValue); + + // Indicate Huffman + buffer.put((byte)0x80); + // Add huffman length + NBitInteger.encode(buffer, 7, huffmanLen); + // Encode value + Huffman.encode(buffer, value); + } + else + _huffmanValue = null; + + _encodedField = (byte)(0x80 | index); + } + + @Override + public boolean isStatic() + { + return true; + } + + @Override + public byte[] getStaticHuffmanValue() + { + return _huffmanValue; + } + + public byte getEncodedField() + { + return _encodedField; + } +} diff --git a/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/StaticTable.java b/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/table/StaticTable.java similarity index 79% rename from jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/StaticTable.java rename to jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/table/StaticTable.java index 1f7ca39f816..67dddf5213f 100644 --- a/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/StaticTable.java +++ b/jetty-http3/http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/table/StaticTable.java @@ -1,4 +1,4 @@ -package org.eclipse.jetty.http3.qpack; +package org.eclipse.jetty.http3.qpack.table; import java.util.HashMap; import java.util.HashSet; @@ -9,6 +9,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.http3.qpack.StaticTableHttpField; import org.eclipse.jetty.util.Index; public class StaticTable @@ -82,18 +83,18 @@ public class StaticTable public static final int STATIC_SIZE = STATIC_TABLE.length - 1; - private final Map __staticFieldMap = new HashMap<>(); - private final Index __staticNameMap; - private final QpackContext.StaticEntry[] __staticTableByHeader = new QpackContext.StaticEntry[HttpHeader.values().length]; - private final QpackContext.StaticEntry[] __staticTable = new QpackContext.StaticEntry[STATIC_TABLE.length]; + private final Map __staticFieldMap = new HashMap<>(); + private final Index __staticNameMap; + private final StaticEntry[] __staticTableByHeader = new StaticEntry[HttpHeader.values().length]; + private final StaticEntry[] __staticTable = new StaticEntry[STATIC_TABLE.length]; public StaticTable() { - Index.Builder staticNameMapBuilder = new Index.Builder().caseSensitive(false); + Index.Builder staticNameMapBuilder = new Index.Builder().caseSensitive(false); Set added = new HashSet<>(); for (int i = 1; i < STATIC_TABLE.length; i++) { - QpackContext.StaticEntry entry = null; + StaticEntry entry = null; String name = STATIC_TABLE[i][0]; String value = STATIC_TABLE[i][1]; @@ -107,7 +108,7 @@ public class StaticTable HttpMethod method = HttpMethod.CACHE.get(value); if (method != null) - entry = new QpackContext.StaticEntry(i, new StaticTableHttpField(header, name, value, method)); + entry = new StaticEntry(i, new StaticTableHttpField(header, name, value, method)); break; } @@ -116,13 +117,13 @@ public class StaticTable HttpScheme scheme = HttpScheme.CACHE.get(value); if (scheme != null) - entry = new QpackContext.StaticEntry(i, new StaticTableHttpField(header, name, value, scheme)); + entry = new StaticEntry(i, new StaticTableHttpField(header, name, value, scheme)); break; } case C_STATUS: { - entry = new QpackContext.StaticEntry(i, new StaticTableHttpField(header, name, value, value)); + entry = new StaticEntry(i, new StaticTableHttpField(header, name, value, value)); break; } @@ -132,7 +133,7 @@ public class StaticTable } if (entry == null) - entry = new QpackContext.StaticEntry(i, header == null ? new HttpField(STATIC_TABLE[i][0], value) : new HttpField(header, name, value)); + entry = new StaticEntry(i, header == null ? new HttpField(STATIC_TABLE[i][0], value) : new HttpField(header, name, value)); __staticTable[i] = entry; @@ -149,30 +150,30 @@ public class StaticTable for (HttpHeader h : HttpHeader.values()) { - QpackContext.StaticEntry entry = __staticNameMap.get(h.asString()); + StaticEntry entry = __staticNameMap.get(h.asString()); if (entry != null) __staticTableByHeader[h.ordinal()] = entry; } } - public QpackContext.Entry get(HttpField field) + public Entry get(HttpField field) { return __staticFieldMap.get(field); } - public QpackContext.Entry get(String name) + public Entry get(String name) { return __staticNameMap.get(name); } - public QpackContext.Entry get(int index) + public Entry get(int index) { if (index >= __staticTable.length) return null; return __staticTable[index]; } - public QpackContext.Entry get(HttpHeader header) + public Entry get(HttpHeader header) { int index = header.ordinal(); if (index >= __staticTableByHeader.length) diff --git a/jetty-http3/http3-qpack/src/test/java/org/eclipse/jetty/http3/qpack/QpackContextTest.java b/jetty-http3/http3-qpack/src/test/java/org/eclipse/jetty/http3/qpack/QpackContextTest.java index de81e7b7ff7..9764c02fdab 100644 --- a/jetty-http3/http3-qpack/src/test/java/org/eclipse/jetty/http3/qpack/QpackContextTest.java +++ b/jetty-http3/http3-qpack/src/test/java/org/eclipse/jetty/http3/qpack/QpackContextTest.java @@ -16,7 +16,7 @@ package org.eclipse.jetty.http3.qpack; import java.nio.ByteBuffer; import org.eclipse.jetty.http.HttpField; -import org.eclipse.jetty.http3.qpack.QpackContext.Entry; +import org.eclipse.jetty.http3.qpack.table.Entry; import org.hamcrest.Matchers; import org.junit.jupiter.api.Test; @@ -197,7 +197,7 @@ public class QpackContextTest Entry[] entry = new Entry[100]; // Lookup the index of a static field - assertEquals(0, ctx.size()); + assertEquals(0, ctx.getNumEntries()); assertEquals(":authority", ctx.get(1).getHttpField().getName()); assertEquals(3, ctx.index(ctx.get(methodPost))); assertEquals(methodPost, ctx.get(3).getHttpField()); @@ -208,7 +208,7 @@ public class QpackContextTest entry[0] = ctx.add(field[0]); // Check new entry is 62 - assertEquals(1, ctx.size()); + assertEquals(1, ctx.getNumEntries()); assertEquals(62, ctx.index(entry[0])); assertEquals(entry[0], ctx.get(62)); @@ -217,7 +217,7 @@ public class QpackContextTest assertEquals(3, ctx.index(ctx.get(methodPost))); assertEquals(methodPost, ctx.get(3).getHttpField()); assertEquals("www-authenticate", ctx.get(61).getHttpField().getName()); - assertEquals(null, ctx.get(62 + ctx.size())); + assertEquals(null, ctx.get(62 + ctx.getNumEntries())); // Add 4 more entries for (int i = 1; i <= 4; i++) @@ -226,7 +226,7 @@ public class QpackContextTest } // Check newest entry is at 62 oldest at 66 - assertEquals(5, ctx.size()); + assertEquals(5, ctx.getNumEntries()); int index = 66; for (int i = 0; i <= 4; i++) { @@ -240,7 +240,7 @@ public class QpackContextTest assertEquals(3, ctx.index(ctx.get(methodPost))); assertEquals(methodPost, ctx.get(3).getHttpField()); assertEquals("www-authenticate", ctx.get(61).getHttpField().getName()); - assertEquals(null, ctx.get(62 + ctx.size())); + assertEquals(null, ctx.get(62 + ctx.getNumEntries())); // add 1 more entry and this should cause an eviction! entry[5] = ctx.add(field[5]); @@ -262,7 +262,7 @@ public class QpackContextTest assertEquals(3, ctx.index(ctx.get(methodPost))); assertEquals(methodPost, ctx.get(3).getHttpField()); assertEquals("www-authenticate", ctx.get(61).getHttpField().getName()); - assertEquals(null, ctx.get(62 + ctx.size())); + assertEquals(null, ctx.get(62 + ctx.getNumEntries())); // Add 4 more entries for (int i = 6; i <= 9; i++) @@ -328,7 +328,7 @@ public class QpackContextTest entry[i] = ctx.add(field[i]); } - assertEquals(5, ctx.size()); + assertEquals(5, ctx.getNumEntries()); // check indexes int index = 66; @@ -341,7 +341,7 @@ public class QpackContextTest // resize so that only 2 entries may be held ctx.resize(38 * 2); - assertEquals(2, ctx.size()); + assertEquals(2, ctx.getNumEntries()); // check indexes index = 63; @@ -354,7 +354,7 @@ public class QpackContextTest // resize so that 6.5 entries may be held ctx.resize(38 * 6 + 19); - assertEquals(2, ctx.size()); + assertEquals(2, ctx.getNumEntries()); // check indexes index = 63; @@ -371,7 +371,7 @@ public class QpackContextTest entry[i] = ctx.add(field[i]); } - assertEquals(6, ctx.size()); + assertEquals(6, ctx.getNumEntries()); // check indexes index = 67; @@ -384,7 +384,7 @@ public class QpackContextTest // resize so that only 100 entries may be held ctx.resize(38 * 100); - assertEquals(6, ctx.size()); + assertEquals(6, ctx.getNumEntries()); // check indexes index = 67; for (int i = 4; i <= 9; i++) diff --git a/jetty-http3/http3-qpack/src/test/java/org/eclipse/jetty/http3/qpack/QpackDecoderTest.java b/jetty-http3/http3-qpack/src/test/java/org/eclipse/jetty/http3/qpack/QpackDecoderTest.java index f3ae0b84a4b..df0bd5939f7 100644 --- a/jetty-http3/http3-qpack/src/test/java/org/eclipse/jetty/http3/qpack/QpackDecoderTest.java +++ b/jetty-http3/http3-qpack/src/test/java/org/eclipse/jetty/http3/qpack/QpackDecoderTest.java @@ -209,7 +209,7 @@ public class QpackDecoderTest assertThat(metaData.getFields().get(HttpHeader.HOST), is("localhost0")); assertThat(metaData.getFields().get(HttpHeader.COOKIE), is("abcdefghij")); assertThat(decoder.getQpackContext().getMaxDynamicTableSize(), is(50)); - assertThat(decoder.getQpackContext().size(), is(1)); + assertThat(decoder.getQpackContext().getNumEntries(), is(1)); } @Test diff --git a/jetty-http3/http3-qpack/src/test/java/org/eclipse/jetty/http3/qpack/QpackEncoderTest.java b/jetty-http3/http3-qpack/src/test/java/org/eclipse/jetty/http3/qpack/QpackEncoderTest.java index 87fd1288235..92bc0a9b1f7 100644 --- a/jetty-http3/http3-qpack/src/test/java/org/eclipse/jetty/http3/qpack/QpackEncoderTest.java +++ b/jetty-http3/http3-qpack/src/test/java/org/eclipse/jetty/http3/qpack/QpackEncoderTest.java @@ -20,6 +20,7 @@ import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; +import org.eclipse.jetty.http3.qpack.table.StaticTable; import org.eclipse.jetty.util.BufferUtil; import org.hamcrest.Matchers; import org.junit.jupiter.api.Test; @@ -67,7 +68,7 @@ public class QpackEncoderTest assertThat(buffer.remaining(), Matchers.greaterThan(0)); // All are in the dynamic table - assertEquals(4, encoder.getQpackContext().size()); + assertEquals(4, encoder.getQpackContext().getNumEntries()); // encode exact same fields again! BufferUtil.clearToFill(buffer); @@ -75,7 +76,7 @@ public class QpackEncoderTest BufferUtil.flipToFlush(buffer, 0); // All are in the dynamic table - assertEquals(4, encoder.getQpackContext().size()); + assertEquals(4, encoder.getQpackContext().getNumEntries()); // Add 4 more fields for (int i = 4; i <= 7; i++) @@ -92,7 +93,7 @@ public class QpackEncoderTest assertThat(buffer.remaining(), Matchers.greaterThan(0)); // max dynamic table size reached - assertEquals(5, encoder.getQpackContext().size()); + assertEquals(5, encoder.getQpackContext().getNumEntries()); // remove some fields for (int i = 0; i <= 7; i += 2) @@ -109,7 +110,7 @@ public class QpackEncoderTest assertThat(buffer.remaining(), Matchers.greaterThan(0)); // max dynamic table size reached - assertEquals(5, encoder.getQpackContext().size()); + assertEquals(5, encoder.getQpackContext().getNumEntries()); // remove another fields fields.remove(field[1].getName()); @@ -123,7 +124,7 @@ public class QpackEncoderTest assertThat(buffer.remaining(), Matchers.greaterThan(0)); // max dynamic table size reached - assertEquals(5, encoder.getQpackContext().size()); + assertEquals(5, encoder.getQpackContext().getNumEntries()); // re add the field @@ -138,7 +139,7 @@ public class QpackEncoderTest assertThat(buffer.remaining(), Matchers.greaterThan(0)); // max dynamic table size reached - assertEquals(5, encoder.getQpackContext().size()); + assertEquals(5, encoder.getQpackContext().getNumEntries()); } @Test @@ -207,7 +208,7 @@ public class QpackEncoderTest assertThat(buffer.remaining(), Matchers.greaterThan(0)); // empty dynamic table - assertEquals(0, encoder.getQpackContext().size()); + assertEquals(0, encoder.getQpackContext().getNumEntries()); // encode again BufferUtil.clearToFill(buffer); @@ -218,7 +219,7 @@ public class QpackEncoderTest assertThat(buffer.remaining(), Matchers.greaterThan(0)); // empty dynamic table - assertEquals(0, encoder.getQpackContext().size()); + assertEquals(0, encoder.getQpackContext().getNumEntries()); } @Test @@ -278,7 +279,7 @@ public class QpackEncoderTest // Only first and third fields are put in the table QpackContext context = encoder.getQpackContext(); - assertThat(context.size(), equalTo(2)); + assertThat(context.getNumEntries(), equalTo(2)); assertThat(context.get(StaticTable.STATIC_SIZE + 1).getHttpField().getName(), equalTo("host")); assertThat(context.get(StaticTable.STATIC_SIZE + 2).getHttpField().getName(), equalTo("user-agent")); assertThat(context.getDynamicTableSize(), equalTo( @@ -304,6 +305,6 @@ public class QpackEncoderTest QpackContext context = encoder.getQpackContext(); assertThat(context.getMaxDynamicTableSize(), Matchers.is(50)); - assertThat(context.size(), Matchers.is(1)); + assertThat(context.getNumEntries(), Matchers.is(1)); } } diff --git a/jetty-http3/http3-qpack/src/test/java/org/eclipse/jetty/http3/qpack/QpackTest.java b/jetty-http3/http3-qpack/src/test/java/org/eclipse/jetty/http3/qpack/QpackTest.java index 0d5d0fd400b..bd037b3fc75 100644 --- a/jetty-http3/http3-qpack/src/test/java/org/eclipse/jetty/http3/qpack/QpackTest.java +++ b/jetty-http3/http3-qpack/src/test/java/org/eclipse/jetty/http3/qpack/QpackTest.java @@ -24,6 +24,7 @@ import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http.MetaData.Response; import org.eclipse.jetty.http.PreEncodedHttpField; +import org.eclipse.jetty.http3.qpack.table.DynamicTable; import org.eclipse.jetty.util.BufferUtil; import org.junit.jupiter.api.Test; @@ -174,10 +175,10 @@ public class QpackTest BufferUtil.flipToFlush(buffer, 0); MetaData decoded0 = decoder.decode(buffer); - assertEquals(2, encoder.getQpackContext().size()); - assertEquals(2, decoder.getQpackContext().size()); - assertEquals(longEnoughToBeEvicted, encoder.getQpackContext().get(StaticTable.STATIC_TABLE.length + 1).getHttpField().getName()); - assertEquals("foo", encoder.getQpackContext().get(StaticTable.STATIC_TABLE.length).getHttpField().getName()); + assertEquals(2, encoder.getQpackContext().getNumEntries()); + assertEquals(2, decoder.getQpackContext().getNumEntries()); + assertEquals(longEnoughToBeEvicted, encoder.getQpackContext().get(DynamicTable.FIRST_INDEX + 1).getHttpField().getName()); + assertEquals("foo", encoder.getQpackContext().get(DynamicTable.FIRST_INDEX).getHttpField().getName()); assertMetaDataSame(original0, decoded0); @@ -192,10 +193,10 @@ public class QpackTest MetaData decoded1 = decoder.decode(buffer); assertMetaDataSame(original1, decoded1); - assertEquals(2, encoder.getQpackContext().size()); - assertEquals(2, decoder.getQpackContext().size()); - assertEquals("x", encoder.getQpackContext().get(StaticTable.STATIC_TABLE.length).getHttpField().getName()); - assertEquals("foo", encoder.getQpackContext().get(StaticTable.STATIC_TABLE.length + 1).getHttpField().getName()); + assertEquals(2, encoder.getQpackContext().getNumEntries()); + assertEquals(2, decoder.getQpackContext().getNumEntries()); + assertEquals("x", encoder.getQpackContext().get(DynamicTable.FIRST_INDEX).getHttpField().getName()); + assertEquals("foo", encoder.getQpackContext().get(DynamicTable.FIRST_INDEX + 1).getHttpField().getName()); } @Test