Implement the QpackFieldPreEncoder allowing it to use static table references.
Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
This commit is contained in:
parent
c3d69b3e60
commit
c9dfded16a
|
@ -68,7 +68,6 @@ class EncodableEntry
|
|||
{
|
||||
byte allowIntermediary = 0x00; // TODO: this is 0x20 bit, when should this be set?
|
||||
byte staticBit = _referencedName.isStatic() ? (byte)0x10 : (byte)0x00;
|
||||
String value = (Objects.requireNonNull(_field).getValue() == null) ? "" : _field.getValue();
|
||||
|
||||
// Encode the prefix.
|
||||
buffer.put((byte)(0x40 | allowIntermediary | staticBit));
|
||||
|
@ -76,6 +75,7 @@ class EncodableEntry
|
|||
NBitInteger.encode(buffer, 4, relativeIndex);
|
||||
|
||||
// Encode the value.
|
||||
String value = getValue();
|
||||
if (_huffman)
|
||||
{
|
||||
buffer.put((byte)0x80);
|
||||
|
@ -92,8 +92,8 @@ class EncodableEntry
|
|||
else
|
||||
{
|
||||
byte allowIntermediary = 0x00; // TODO: this is 0x10 bit, when should this be set?
|
||||
String name = Objects.requireNonNull(_field).getName();
|
||||
String value = (_field.getValue() == null) ? "" : _field.getValue();
|
||||
String name = getName();
|
||||
String value = getValue();
|
||||
|
||||
// Encode the prefix code and the name.
|
||||
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()
|
||||
{
|
||||
if (_referencedEntry != null && !_referencedEntry.isStatic())
|
||||
|
|
|
@ -15,70 +15,61 @@ package org.eclipse.jetty.http3.qpack;
|
|||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jetty.http.HttpField;
|
||||
import org.eclipse.jetty.http.HttpFieldPreEncoder;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.HttpVersion;
|
||||
import org.eclipse.jetty.http3.qpack.table.Entry;
|
||||
import org.eclipse.jetty.http3.qpack.table.StaticTable;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
|
||||
/**
|
||||
* TODO: implement QpackEncoder with PreEncodedFields.
|
||||
*/
|
||||
public class QpackFieldPreEncoder implements HttpFieldPreEncoder
|
||||
{
|
||||
|
||||
@Override
|
||||
public HttpVersion getHttpVersion()
|
||||
{
|
||||
return HttpVersion.HTTP_2;
|
||||
return HttpVersion.HTTP_3;
|
||||
}
|
||||
|
||||
@Override
|
||||
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);
|
||||
|
||||
ByteBuffer buffer = BufferUtil.allocate(name.length() + value.length() + 10);
|
||||
BufferUtil.clearToFill(buffer);
|
||||
boolean huffman;
|
||||
int bits;
|
||||
|
||||
boolean huffman = !QpackEncoder.DO_NOT_HUFFMAN.contains(header);
|
||||
if (notIndexed)
|
||||
{
|
||||
// Non indexed field
|
||||
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;
|
||||
encodableEntry = new EncodableEntry(httpField, huffman);
|
||||
}
|
||||
else
|
||||
{
|
||||
// indexed
|
||||
buffer.put((byte)0x40);
|
||||
huffman = !QpackEncoder.DO_NOT_HUFFMAN.contains(header);
|
||||
bits = 6;
|
||||
Entry entry = staticTable.get(httpField);
|
||||
if (entry != null)
|
||||
{
|
||||
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);
|
||||
if (entry != null)
|
||||
NBitInteger.encode(buffer, bits, entry.getIndex());
|
||||
else
|
||||
{
|
||||
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);
|
||||
|
||||
// Use a base of zero as we only reference the static table.
|
||||
int base = 0;
|
||||
ByteBuffer buffer = BufferUtil.allocate(encodableEntry.getRequiredSize(base));
|
||||
BufferUtil.clearToFill(buffer);
|
||||
encodableEntry.encode(buffer, base);
|
||||
BufferUtil.flipToFlush(buffer, 0);
|
||||
return BufferUtil.toArray(buffer);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue