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 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())
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue