Package io.github.mahmoudimus.http3
Class QpackEncoder
java.lang.Object
io.github.mahmoudimus.http3.QpackEncoder
Encodes field sections with QPACK (RFC 9204). One encoder per connection, for the field sections
this endpoint sends. Not thread-safe: callers serialize access, and must send each section's
encoder-stream instructions (see
encoderStreamBytes()) no later than the section.
Two modes:
- Static only (
QpackEncoder(), or until the peer allows a dynamic table): fields are indexed in the static table or sent as literals. Sections never depend on the encoder stream (Required Insert Count 0), so they can never block. Always safe. - Dynamic (
QpackEncoder(long)with a non-zero limit, onceapplyPeerSettings(io.github.mahmoudimus.http3.Http3Settings)gives a non-zero SETTINGS_QPACK_MAX_TABLE_CAPACITY): the encoder sets the table capacity to the smaller of its limit and the peer's, inserts fields into the dynamic table with encoder-stream instructions (Set Dynamic Table Capacity, Insert With Name Reference, Insert With Literal Name, Duplicate) and references them. A section may reference entries the peer has not acknowledged yet, and so block, only while fewer than the peer's SETTINGS_QPACK_BLOCKED_STREAMS streams are blocked (or the stream already is); otherwise it uses only acknowledged entries and literals.
QpackEncoder qpack = new QpackEncoder(4096);
qpack.applyPeerSettings(peerSettings);
byte[] section = qpack.encode(streamId, fields);
encoderStream.write(qpack.encoderStreamBytes()); // first, or together with the section
requestStream.writeHeaders(section);
// Bytes from the peer's QPACK decoder stream:
qpack.onDecoderStream(bytes, 0, n);
The peer's decoder-stream instructions (Section Acknowledgment, Stream Cancellation, Insert Count Increment) release references and advance the Known Received Count. An entry is evicted only once its insertion has been acknowledged and no unacknowledged section references it (§2.1.1); when that does not leave room, the field is sent as a literal instead.
A field marked HeaderField.sensitive(), or (unless turned off) one named in
SENSITIVE_NAMES, is sent as a literal with the 'N' bit set and never enters the dynamic
table. Strings are Huffman-coded unless that would make them longer or setHuffman(boolean)
turns it off. Names are sent as given: lower-case them first.
-
Field Summary
FieldsModifier and TypeFieldDescriptionNames whose fields are sent never-indexed by default: they carry credentials. -
Constructor Summary
ConstructorsConstructorDescriptionA static-table-only encoder: it never uses the dynamic table, whatever the peer allows.QpackEncoder(long maxTableCapacity) An encoder that will use a dynamic table of up tomaxTableCapacityoctets (memory it is willing to spend), and no more than the peer's SETTINGS_QPACK_MAX_TABLE_CAPACITY. -
Method Summary
Modifier and TypeMethodDescriptionvoidApplies the QPACK settings and MAX_FIELD_SECTION_SIZE from the peer's SETTINGS.intThe number of streams with a section that the peer cannot decode until it receives more inserts.longduplicate(long absoluteIndex) Re-inserts an existing entry with a Duplicate instruction (§4.3.4), so that sections can reference a fresh copy while the old one becomes evictable.longThe current capacity of the dynamic table.dynamicTableEntry(long absoluteIndex) The dynamic table entry with this absolute index, or null if absent.intThe number of entries in the dynamic table.longThe current size of the dynamic table in octets (entries plus 32 each).byte[]encode(long streamId, List<HeaderField> fields) Encodes one field section for a HEADERS or PUSH_PROMISE frame on the given stream, queuing any encoder-stream instructions it needs.byte[]Takes the encoder-stream instructions produced so far; send them on the QPACK encoder stream before, or together with, the sections that depend on them.longInserts a field into the dynamic table without referencing it, for later sections (a speculative insert), choosing a name reference where one exists.longThe number of entries inserted so far (the Insert Count).longHow many inserts the peer's decoder has acknowledged (§2.1.4).longThe largest capacity the dynamic table may have: the smaller of our limit and the peer's.voidonDecoderStream(byte[] data) Processes bytes from the peer's QPACK decoder stream; seeonDecoderStream(byte[], int, int).voidonDecoderStream(byte[] data, int offset, int length) Processes bytes from the peer's QPACK decoder stream (§4.4), in any pieces: an instruction split between calls is completed by the next.intreferenceCount(long absoluteIndex) The number of unacknowledged field sections that reference this entry.voidsetCapacity(long capacity) Sets the dynamic table capacity, emitting a Set Dynamic Table Capacity instruction (§4.3.1).setHuffman(boolean huffman) Whether to Huffman-code strings that do not get longer for it (default true).setNeverIndexSensitiveNames(boolean neverIndexSensitiveNames) Whether to send fields named inSENSITIVE_NAMESnever-indexed (default true).voidsetPeerSettings(long maxTableCapacity, long maxBlockedStreams) Applies the peer's SETTINGS_QPACK_MAX_TABLE_CAPACITY and SETTINGS_QPACK_BLOCKED_STREAMS.
-
Field Details
-
SENSITIVE_NAMES
Names whose fields are sent never-indexed by default: they carry credentials.
-
-
Constructor Details
-
QpackEncoder
public QpackEncoder()A static-table-only encoder: it never uses the dynamic table, whatever the peer allows. -
QpackEncoder
public QpackEncoder(long maxTableCapacity) An encoder that will use a dynamic table of up tomaxTableCapacityoctets (memory it is willing to spend), and no more than the peer's SETTINGS_QPACK_MAX_TABLE_CAPACITY. UntilapplyPeerSettings(io.github.mahmoudimus.http3.Http3Settings)it works in static-only mode, which is valid with any peer.- Parameters:
maxTableCapacity- the largest dynamic table this encoder will use, in octets
-
-
Method Details
-
setHuffman
Whether to Huffman-code strings that do not get longer for it (default true).- Parameters:
huffman- whether to Huffman-code- Returns:
- this encoder
-
setNeverIndexSensitiveNames
Whether to send fields named inSENSITIVE_NAMESnever-indexed (default true).- Parameters:
neverIndexSensitiveNames- whether to- Returns:
- this encoder
-
applyPeerSettings
Applies the QPACK settings and MAX_FIELD_SECTION_SIZE from the peer's SETTINGS.- Parameters:
peer- the peer's settings
-
setPeerSettings
public void setPeerSettings(long maxTableCapacity, long maxBlockedStreams) Applies the peer's SETTINGS_QPACK_MAX_TABLE_CAPACITY and SETTINGS_QPACK_BLOCKED_STREAMS. HTTP/3 sends SETTINGS once, so call this once.- Parameters:
maxTableCapacity- the peer's SETTINGS_QPACK_MAX_TABLE_CAPACITYmaxBlockedStreams- the peer's SETTINGS_QPACK_BLOCKED_STREAMS
-
maxDynamicTableCapacity
public long maxDynamicTableCapacity()The largest capacity the dynamic table may have: the smaller of our limit and the peer's.- Returns:
- the capacity in octets
-
insertCount
public long insertCount()The number of entries inserted so far (the Insert Count).- Returns:
- the Insert Count
-
knownReceivedCount
public long knownReceivedCount()How many inserts the peer's decoder has acknowledged (§2.1.4).- Returns:
- the Known Received Count
-
dynamicTableSize
public long dynamicTableSize()The current size of the dynamic table in octets (entries plus 32 each).- Returns:
- the size in octets
-
dynamicTableCapacity
public long dynamicTableCapacity()The current capacity of the dynamic table.- Returns:
- the capacity in octets
-
dynamicTableLength
public int dynamicTableLength()The number of entries in the dynamic table.- Returns:
- the number of entries
-
dynamicTableEntry
The dynamic table entry with this absolute index, or null if absent.- Parameters:
absoluteIndex- the absolute index- Returns:
- the entry, or null
-
referenceCount
public int referenceCount(long absoluteIndex) The number of unacknowledged field sections that reference this entry.- Parameters:
absoluteIndex- the absolute index- Returns:
- the number of sections
-
blockedStreams
public int blockedStreams()The number of streams with a section that the peer cannot decode until it receives more inserts.- Returns:
- the number of streams
-
encoderStreamBytes
public byte[] encoderStreamBytes()Takes the encoder-stream instructions produced so far; send them on the QPACK encoder stream before, or together with, the sections that depend on them.- Returns:
- the bytes, possibly none
-
setCapacity
public void setCapacity(long capacity) Sets the dynamic table capacity, emitting a Set Dynamic Table Capacity instruction (§4.3.1). Without this call, the first section or insert sets it tomaxDynamicTableCapacity().- Parameters:
capacity- the new capacity in octets- Throws:
IllegalArgumentException- abovemaxDynamicTableCapacity()IllegalStateException- if shrinking would evict an entry that is not evictable
-
insert
Inserts a field into the dynamic table without referencing it, for later sections (a speculative insert), choosing a name reference where one exists.- Parameters:
name- the field namevalue- the field value- Returns:
- the new entry's absolute index, or -1 if it did not fit
-
duplicate
public long duplicate(long absoluteIndex) Re-inserts an existing entry with a Duplicate instruction (§4.3.4), so that sections can reference a fresh copy while the old one becomes evictable.- Parameters:
absoluteIndex- the entry to duplicate- Returns:
- the new entry's absolute index, or -1 if there was no room
- Throws:
IllegalArgumentException- if the entry is not in the table
-
encode
Encodes one field section for a HEADERS or PUSH_PROMISE frame on the given stream, queuing any encoder-stream instructions it needs.- Parameters:
streamId- the stream the section goes onfields- the fields- Returns:
- the encoded field section
- Throws:
IllegalArgumentException- if a name or value has a char above U+00FF (not an octet), or the section is larger than the peer's SETTINGS_MAX_FIELD_SECTION_SIZE; nothing has changed then
-
onDecoderStream
Processes bytes from the peer's QPACK decoder stream; seeonDecoderStream(byte[], int, int).- Parameters:
data- the bytes- Throws:
Http3Exception- a connection error QPACK_DECODER_STREAM_ERROR for an invalid instruction
-
onDecoderStream
Processes bytes from the peer's QPACK decoder stream (§4.4), in any pieces: an instruction split between calls is completed by the next.- Parameters:
data- the bytesoffset- where they start indatalength- how many- Throws:
Http3Exception- a connection error QPACK_DECODER_STREAM_ERROR for an acknowledgment of a section that was not sent, an Insert Count Increment of 0 or past the inserts sent, or an integer overflow
-