Implement the QpackFieldPreEncoder allowing it to use static table references.

Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
This commit is contained in:
Lachlan Roberts 2021-03-05 19:44:06 +11:00 committed by Simone Bordet
parent c3d69b3e60
commit c9dfded16a
2 changed files with 70 additions and 43 deletions

View File

@ -68,7 +68,6 @@ class EncodableEntry
{ {
byte allowIntermediary = 0x00; // TODO: this is 0x20 bit, when should this be set? byte allowIntermediary = 0x00; // TODO: this is 0x20 bit, when should this be set?
byte staticBit = _referencedName.isStatic() ? (byte)0x10 : (byte)0x00; byte staticBit = _referencedName.isStatic() ? (byte)0x10 : (byte)0x00;
String value = (Objects.requireNonNull(_field).getValue() == null) ? "" : _field.getValue();
// Encode the prefix. // Encode the prefix.
buffer.put((byte)(0x40 | allowIntermediary | staticBit)); buffer.put((byte)(0x40 | allowIntermediary | staticBit));
@ -76,6 +75,7 @@ class EncodableEntry
NBitInteger.encode(buffer, 4, relativeIndex); NBitInteger.encode(buffer, 4, relativeIndex);
// Encode the value. // Encode the value.
String value = getValue();
if (_huffman) if (_huffman)
{ {
buffer.put((byte)0x80); buffer.put((byte)0x80);
@ -92,8 +92,8 @@ class EncodableEntry
else else
{ {
byte allowIntermediary = 0x00; // TODO: this is 0x10 bit, when should this be set? byte allowIntermediary = 0x00; // TODO: this is 0x10 bit, when should this be set?
String name = Objects.requireNonNull(_field).getName(); String name = getName();
String value = (_field.getValue() == null) ? "" : _field.getValue(); String value = getValue();
// Encode the prefix code and the name. // Encode the prefix code and the name.
if (_huffman) if (_huffman)
@ -118,6 +118,42 @@ class EncodableEntry
} }
} }
public int getRequiredSize(int base)
{
if (_referencedEntry != null)
{
int relativeIndex = _referencedEntry.getIndex() - base;
return 1 + NBitInteger.octectsNeeded(6, relativeIndex);
}
else if (_referencedName != null)
{
String value = getValue();
int relativeIndex = _referencedName.getIndex() - base;
int valueLength = _huffman ? Huffman.octetsNeeded(value) : value.length();
return 1 + NBitInteger.octectsNeeded(4, relativeIndex) + 1 + NBitInteger.octectsNeeded(7, valueLength) + valueLength;
}
else
{
String name = getName();
String value = getValue();
int nameLength = _huffman ? Huffman.octetsNeeded(name) : name.length();
int valueLength = _huffman ? Huffman.octetsNeeded(value) : value.length();
return 2 + NBitInteger.octectsNeeded(3, nameLength) + nameLength + NBitInteger.octectsNeeded(7, valueLength) + valueLength;
}
}
private String getName()
{
String name = Objects.requireNonNull(_field).getName();
return (name == null) ? "" : name;
}
private String getValue()
{
String value = Objects.requireNonNull(_field).getValue();
return (value == null) ? "" : value;
}
public int getRequiredInsertCount() public int getRequiredInsertCount()
{ {
if (_referencedEntry != null && !_referencedEntry.isStatic()) if (_referencedEntry != null && !_referencedEntry.isStatic())

View File

@ -15,70 +15,61 @@ package org.eclipse.jetty.http3.qpack;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpFieldPreEncoder; import org.eclipse.jetty.http.HttpFieldPreEncoder;
import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.http3.qpack.table.Entry; import org.eclipse.jetty.http3.qpack.table.Entry;
import org.eclipse.jetty.http3.qpack.table.StaticTable;
import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.BufferUtil;
/**
* TODO: implement QpackEncoder with PreEncodedFields.
*/
public class QpackFieldPreEncoder implements HttpFieldPreEncoder public class QpackFieldPreEncoder implements HttpFieldPreEncoder
{ {
@Override @Override
public HttpVersion getHttpVersion() public HttpVersion getHttpVersion()
{ {
return HttpVersion.HTTP_2; return HttpVersion.HTTP_3;
} }
@Override @Override
public byte[] getEncodedField(HttpHeader header, String name, String value) public byte[] getEncodedField(HttpHeader header, String name, String value)
{ {
StaticTable staticTable = QpackContext.getStaticTable();
HttpField httpField = new HttpField(header, name, value);
EncodableEntry encodableEntry;
boolean notIndexed = QpackEncoder.DO_NOT_INDEX.contains(header); boolean notIndexed = QpackEncoder.DO_NOT_INDEX.contains(header);
boolean huffman = !QpackEncoder.DO_NOT_HUFFMAN.contains(header);
ByteBuffer buffer = BufferUtil.allocate(name.length() + value.length() + 10);
BufferUtil.clearToFill(buffer);
boolean huffman;
int bits;
if (notIndexed) if (notIndexed)
{ {
// Non indexed field encodableEntry = new EncodableEntry(httpField, huffman);
boolean neverIndex = QpackEncoder.NEVER_INDEX.contains(header);
huffman = !QpackEncoder.DO_NOT_HUFFMAN.contains(header);
buffer.put(neverIndex ? (byte)0x10 : (byte)0x00);
bits = 4;
}
else if (header == HttpHeader.CONTENT_LENGTH && value.length() > 1)
{
// Non indexed content length for 2 digits or more
buffer.put((byte)0x00);
huffman = true;
bits = 4;
} }
else else
{ {
// indexed Entry entry = staticTable.get(httpField);
buffer.put((byte)0x40); if (entry != null)
huffman = !QpackEncoder.DO_NOT_HUFFMAN.contains(header); {
bits = 6; encodableEntry = new EncodableEntry(entry);
}
else
{
Entry nameEntry = staticTable.get(name);
if (nameEntry != null)
{
encodableEntry = new EncodableEntry(nameEntry, httpField, huffman);
}
else
{
encodableEntry = new EncodableEntry(httpField, huffman);
}
}
} }
Entry entry = QpackContext.getStaticTable().get(header); // Use a base of zero as we only reference the static table.
if (entry != null) int base = 0;
NBitInteger.encode(buffer, bits, entry.getIndex()); ByteBuffer buffer = BufferUtil.allocate(encodableEntry.getRequiredSize(base));
else BufferUtil.clearToFill(buffer);
{ encodableEntry.encode(buffer, base);
buffer.put((byte)0x80);
NBitInteger.encode(buffer, 7, Huffman.octetsNeededLC(name));
Huffman.encodeLC(buffer, name);
}
// TODO: I think we can only encode referencing the static table or with literal representations.
// QpackEncoder.encodeValue(buffer, huffman, value);
BufferUtil.flipToFlush(buffer, 0); BufferUtil.flipToFlush(buffer, 0);
return BufferUtil.toArray(buffer); return BufferUtil.toArray(buffer);
} }