Draft: draft-ietf-quic-qpack

Commentary: This PR is more controversial than I first anticipated . It is intended to address . QPACK uses the term instruction extensively section 4 goes into great detail about all the different types . However , the instructions have been presented in terms of what streams they appear on . Which makes things a little unclear , and verbose , sometimes . I think it also conflates the idea of the true QPACK unframed encoder and decoder streams , with header block messages ( sets of instructions ) . So this change explicitly creates the terms encoder instruction , decoder instruction and header block instruction . It also removes a lot of the reference to request and push streams . I 'm not 100 % happy with the net outcome of these changes but posting the PR for feedback . 
 Did the section hierarchy get messed up a little in a recent refactor ? The concept of QPACK instructions are first introduced in section 2 , along with encoder and decoder streams . There is no forward reference to the later definitions . The real problem I have is with section 4.2 . It contains a bulleted list that is almost identical to section 2 , but subtly different . The text following this list is also ambiguous The previous list referred to request streams and push streams . These are obviously out of scope but it could get mistaken . I think we 've discussed elsewhere that implementations could decide not to use dynamic compression , and so the encoder and decoder streams are not necessary . I think this sentence could be made clearer by saying something like " if the dynamic table is being used , each endpoint MUST create exactly one pair of encoder and decoder streams . " Perhaps simplify to " receipt of additional streams which claim to be an encoder or decoder stream MUST be treated as a connection error of HTTPWRONGSTREAMCOUNT . Perhaps " The closure of encoder or decoder streams , at any point , MUST be treated as a connection error of type HTTPCLOSEDCRITICALSTREAM . " No it does n't :) While I am here , Section 4.5 is titled " Request and Push Streams " but it just talks about instructions to include in frames . I 'm left with a feeling that there is a misplaced focus on streams rather than instructions . This could be inverted to state instructions , with a comment on where they are allowed to appear , summarised in a nice table somewhere in the document . 
 The big editorial refactor intentionally reordered the sections : the goal was to describe concepts first and specific instructions second . Regarding whether the encoder / decoder streams are required , there 's a separate ( design ) issue open ( ) . Given that the instruction spaces are unique per stream type , and no instruction is allowed on more than one stream , I think it makes sense to keep the instructions organized by the stream on which they are used . I can clean up the ambiguous references to unidirectional streams to make it clear that we 're talking about the QPACK control streams . I 'll give it another read through with your comments in mind and see what further improvements we can make . 
 I 'm happy to come up with a PR containing some proposals . I think we have some diversity in perspective . Coming from a HTTP/3 - first position with a background in HTTP/2 , my currency is the header block . I 've been told it can be sent in HEADERS and PUSHPROMISE , I do n't need to be told how those frames are sent ( i.e. what streams ) . As someone unfamiliar with the specification , the instructions do n't leap out . There is not one section in the TOC that mentions the term instruction _ . From my limited appreciation , I 'd class the instructions as a primitive of header compression . But I accept that these are perhaps the QPACK data model , with primitives akin to built - in types . It still has n't leapt out to me if the encoder and decoder stream exchange clear header blocks , or just a stream of instructions . 
 Maybe it would simplify the document to refer to encoder stream , decoder stream and header blocks in that case ? True , much like frames are primitives in transport and HTTP . Both documents were reorganized as concepts first and wire - specifics following . Perhaps instructions as a concept are n't explained early enough ? I 'd prefer to keep the wire instructions after concepts . See 4.3 and 4.4 
 Discussed off list . I 'll prepare some PRs that we can discuss . 
 : have a look at my attached editorial PR . I think I 've addressed a lot of the concerns here that were n't addressed previously : I eliminated as many references as I could to request / push streams and instead refer to header blocks . There 's nothing preventing an extension from carrying header blocks in other kinds of frames and streams for example . I got rid of the bulleted list awkwardness that was regurgitating the same text from the overview section . 
 Thanks  for the delay , I 'll take a look in the next couple of days . If you do n't here from me assume its ok . I plan to do an end - to - end read at some point 
 After the most recent editorial revision , I 've done my best to address this .
Paragraph (version A):
As in HPACK, the decoder processes header blocks and emits the
corresponding header lists.  It also processes dynamic table
modifications from instructions on the encoder stream.
Paragraph (version B):
As in HPACK, the decoder processes header blocks and emits the
corresponding header lists.  It also processes dynamic table
modifications from encoder instructions received on the encoder
stream.
Paragraph (version A):
When the decoder encounters an invalid static table index on a
request stream or push stream it MUST treat this as a stream error of
type "HTTP_QPACK_DECOMPRESSION_FAILED".  If this index is received on
the encoder stream, this MUST be treated as a connection error of
type "HTTP_QPACK_ENCODER_STREAM_ERROR".
Paragraph (version A):
The dynamic table consists of a list of header fields maintained in
first-in, first-out order.  The dynamic table is initially empty.
Entries are added by instructions on the encoder stream (see encoder-
stream).
Paragraph (version B):
When the decoder encounters an invalid static table index in a header
block instruction it MUST treat this as a stream error of type
"HTTP_QPACK_DECOMPRESSION_FAILED".  If this index is received on the
encoder stream, this MUST be treated as a connection error of type
"HTTP_QPACK_ENCODER_STREAM_ERROR".
Paragraph (version B):
The dynamic table consists of a list of header fields maintained in
first-in, first-out order.  Each HTTP/3 endpoint holds a dynamic
table that is initially empty.  Entries are added by encoder
instructions received on the encoder stream (see encoder-
instructions).
Paragraph (version A):
When the maximum table capacity is 0, the encoder MUST NOT insert
entries into the dynamic table, and MUST NOT send any instructions on
the encoder stream.
Paragraph (version B):
When the maximum table capacity is 0, the encoder MUST NOT insert
entries into the dynamic table, and MUST NOT send any encoder
instructions on the encoder stream.
Paragraph (version A):
On the encoder stream, a relative index of "0" always refers to the
most recently inserted value in the dynamic table.  Note that this
means the entry referenced by a given relative index will change
while interpreting instructions on the encoder stream.
Paragraph (version A):
Unlike on the encoder stream, relative indices on push and request
streams are relative to the Base at the beginning of the header block
(see header-prefix).  This ensures that references are stable even if
the dynamic table is updated while decoding a header block.
Paragraph (version B):
In encoder instructions, a relative index of "0" always refers to the
most recently inserted value in the dynamic table.  Note that this
means the entry referenced by a given relative index will change
while interpreting instructions on the encoder stream.
Paragraph (version B):
Unlike encoder instructions, relative indices in header block
instructions are relative to the Base at the beginning of the header
block (see header-prefix).  This ensures that references are stable
even if the dynamic table is updated while decoding a header block.
Paragraph (version A):
A header block on the request stream can reference entries added
after the entry identified by the Base.  This allows an encoder to
process a header block in a single pass and include references to
entries added while processing this (or other) header blocks.  Newly
added entries are referenced using Post-Base instructions.  Indices
for Post-Base instructions increase in the same direction as absolute
indices, with the zero value being the first entry inserted after the
Base.
Paragraph (version A):
If the decoder encounters a reference on a request or push stream to
a dynamic table entry which has already been evicted or which has an
absolute index greater than or equal to the declared Required Insert
Count (see header-prefix), it MUST treat this as a stream error of
type "HTTP_QPACK_DECOMPRESSION_FAILED".
Paragraph (version A):
If the decoder encounters a reference on the encoder stream to a
dynamic table entry which has already been dropped, it MUST treat
this as a connection error of type "HTTP_QPACK_ENCODER_STREAM_ERROR".
Paragraph (version B):
A header block can reference entries added after the entry identified
by the Base.  This allows an encoder to process a header block in a
single pass and include references to entries added while processing
this (or other) header blocks.  Newly added entries are referenced
using Post-Base instructions.  Indices for Post-Base instructions
increase in the same direction as absolute indices, with the zero
value being the first entry inserted after the Base.
Paragraph (version B):
If the decoder encounters a reference in a header block instruction
to a dynamic table entry which has already been evicted or which has
an absolute index greater than or equal to the declared Required
Insert Count (see header-prefix), it MUST treat this as a stream
error of type "HTTP_QPACK_DECOMPRESSION_FAILED".
Paragraph (version B):
If the decoder encounters a reference in an encoder instruction to a
dynamic table entry which has already been dropped, it MUST treat
this as a connection error of type "HTTP_QPACK_ENCODER_STREAM_ERROR".
Paragraph (version A):
The encoder stream is a unidirectional stream of type "0x02" which
carries table updates from encoder to decoder.
Paragraph (version A):
The decoder stream is a unidirectional stream of type "0x03" which
carries acknowledgements of table modifications and header
processing from decoder to encoder.
Paragraph (version A):
Finally, the contents of HEADERS and PUSH_PROMISE frames on
request streams and push streams reference the QPACK table state.
Paragraph (version A):
There MUST be exactly one of each unidirectional stream type in each
direction.  Receipt of a second instance of either stream type MUST
be treated as a connection error of HTTP_WRONG_STREAM_COUNT.  These
streams MUST NOT be closed.  Closure of either unidirectional stream
MUST be treated as a connection error of type
HTTP_CLOSED_CRITICAL_STREAM.
Paragraph (version A):
This section describes the instructions which are possible on each
stream type.
Paragraph (version B):
There are three separate QPACK instruction spaces.  Encoder
instructions (encoder-instructions) carry table updates, decoder
instructions (decoder-instructions) carry acknowledgments of table
modifications and header processing, and header block instructions
(header-block-instructions) convey an encoded representation of a
header list by referring to the QPACK table state.
Paragraph (version B):
Encoder and decoder instructions appear on the unidirectional stream
types described in this section.  Header block instructions are
contained in HEADERS and PUSH_PROMISE frames, which are conveyed on
request or push streams as described in HTTP3.
Paragraph (version B):
An encoder stream is a unidirectional stream of type "0x02".  It
carries an unframed sequence of encoder instructions from encoder
to decoder.
Paragraph (version B):
A decoder stream is a unidirectional stream of type "0x03".  It
carries an unframed sequence of decoder instructions from decoder
to encoder.
Paragraph (version B):
HTTP/3 endpoints contain a QPACK encoder and decoder.  Each endpoint
MUST initiate a single encoder stream and decoder stream.  Receipt of
a second instance of either stream type be MUST treated as a
connection error of type HTTP_WRONG_STREAM_COUNT.  These streams MUST
NOT be closed.  Closure of either unidirectional stream type MUST be
treated as a connection error of type HTTP_CLOSED_CRITICAL_STREAM.
Paragraph (version A):
The contents of the encoder stream are an unframed sequence of the
following instructions.
Paragraph (version B):
This section specifies the following encoder instructions.
Paragraph (version A):
The decoder stream carries information used to ensure consistency of
the dynamic table.  Information is sent from the decoder to the
encoder; that is, the server informs the client about the processing
of the client's header blocks and table updates, and the client
informs the server about the processing of the server's header blocks
and table updates.
Paragraph (version A):
The contents of the decoder stream are an unframed sequence of the
following instructions.
Paragraph (version B):
Decoder instructions provide information used to ensure consistency
of the dynamic table.  They are sent from the decoder to the encoder
on a decoder stream; that is, the server informs the client about the
processing of the client's header blocks and table updates, and the
client informs the server about the processing of the server's header
blocks and table updates.
Paragraph (version B):
This section specifies the following decoder instructions.
Paragraph (version A):
After processing a header block whose declared Required Insert Count
is not zero, the decoder emits a Header Acknowledgement instruction
on the decoder stream.  The instruction begins with the '1' one-bit
pattern and includes the request stream's stream ID, encoded as a
7-bit prefix integer.  It is used by the peer's encoder to know when
it is safe to evict an entry, and possibly update the Known Received
Count.
Paragraph (version A):
The same Stream ID can be identified multiple times, as multiple
header blocks can be sent on a single stream in the case of
intermediate responses, trailers, and pushed requests.  Since header
frames on each stream are received and processed in order, this gives
the encoder precise feedback on which header blocks within a stream
have been fully processed.
Paragraph (version B):
After processing a header block whose declared Required Insert Count
is not zero, the decoder emits a Header Acknowledgement instruction
on the decoder stream.  The instruction begins with the '1' one-bit
pattern and includes the header block's associated stream ID, encoded
as a 7-bit prefix integer.  It is used by the peer's encoder to know
when it is safe to evict an entry, and possibly update the Known
Received Count.
Paragraph (version B):
The same Stream ID can be identified multiple times, as multiple
header blocks can be sent on a single stream in the case of
intermediate responses, trailers, and pushed requests.  Since HEADERS
and PUSH_PROMISE frames on each stream are received and processed in
order, this gives the encoder precise feedback on which header blocks
within a stream have been fully processed.
Paragraph (version A):
HEADERS and PUSH_PROMISE frames on request and push streams reference
the dynamic table in a particular state without modifying it.  Frames
on these streams emit the headers for an HTTP request or response.
Paragraph (version B):
HTTP/3 endpoints convert header lists to headers blocks and exchange
them inside HEADERS and PUSH_PROMISE frames.  A decoder interprets
header block instructions in order to construct a header list.  These
instructions reference the static table, or dynamic table in a
particular state without modifying it.
Paragraph (version B):
This section specifies the following header block instructions.
Paragraph (version A):
The decoder failed to interpret an instruction on a request or
push stream and is not able to continue decoding that header
block.
Paragraph (version A):
The decoder failed to interpret an instruction on the encoder
stream.
Paragraph (version A):
The encoder failed to interpret an instruction on the decoder
stream.
Paragraph (version B):
The decoder failed to interpret a header block instruction and is
not able to continue decoding that header block.
Paragraph (version B):
The decoder failed to interpret an encoder instruction received on
the encoder stream.
Paragraph (version B):
The encoder failed to interpret a decoder instruction received on
the decoder stream.
Paragraph (version A):
This document creates two new settings in the "HTTP/3 Settings"
registry established in HTTP3.
Paragraph (version A):
This document creates two new settings in the "HTTP/3 Stream Type"
registry established in HTTP3.
Paragraph (version A):
This document establishes the following new error codes in the
"HTTP/3 Error Code" registry established in HTTP3.
Paragraph (version B):
This document specifies two settings.  The entries in the following
table are registered in the "HTTP/3 Settings" registry established in
HTTP3.
Paragraph (version B):
This document specifies two stream types.  The entries in the
following table are registered in the "HTTP/3 Stream Type" registry
established in HTTP3.
Paragraph (version B):
This document specifies three error codes.  The entries in the
following table are registered in the "HTTP/3 Error Code" registry
established in HTTP3.