Draft: draft-ietf-quic-http

Commentary: As discussed in Tokyo , varints all the things . This led to a few ancillary changes along the way : I stole transport 's frame type IANA rules and used it for our three new varint registries . ( This was alluded to in discussion in Tokyo . ) Unidirectional stream types are now a fixed sequence starting from 0x00 , rather than scattered code points that " just happen " to have ASCII values . ( This was explicitly requested in discussion in Tokyo . ) It 's impractical to enumerate and have IANA reserve the grease values for a much larger space ; therefore , I shifted the requirement to saying that IANA MUST NOT allocate those code points to anyone . ( This also avoids IANA having a publicly - visible list of the grease codepoints , which is a nice perk . ) The is less effective greasing , as it falls entirely in the private use range . I changed everything to use the formulation , which has the side benefit of being easy to produce and less obvious to identify on first glance . ( However , only two of these values fall in the standards - assigned region . ) If any of these ancillary changes are controversial , I 'm happy to split them out into separate issues for discussion , but they make these changes fit more naturally . 
 Checking the , it seems we have a clash on 0x8 due to RFC 8441 - WebSocket over HTTP/2 . I think its reasonable that someone might write a WebSocket over HTTP/3 extension and reusing the code point would be nice . Can we move NUMPLACEHOLDERS to 0x9 and leave 0x8 open ? Originally posted by in 
 Not a new issue but : RFC 7540 has a column for . I think it makes sense that HTTP/3 does similar . Originally posted by in 
  streams are special , compared to other unidirectional streams , because they requires some some additional preface (  ID ) before allowing frames . Reading through section 3.2 again . It seems like a reader could be mislead by the combination of figure 1 and 2 . The usual convention across QUIC and HTTP/3 specs is to define a frame header , then later section define the frame body . The  stream shown in figure 2 duplicates the stream header field , and I think it could be misread as saying there are two stream headers . Do others think this is a problem ? We could fix the diagram or remove it completely . Or something else entirely . 
 I 'm not sold on this being a problem , but let 's see what others think . 
 Closing , since no one else has weighed in . 
 Continuing on from , I realized that the spontaneous push example might be something better supported by a unidirectional stream . And here , the same arguments about uncoordinated , spontaneous use apply . 
 That 's how my h3 extension worked , reserving 0xTBD . This would have the effect of changing the current stream type greasing rules , which we always had some concern over because of the small space . If this change is to be made , we might want to consider if ASCII codes values currently defined are still appropriate . Also , if this is a supported change I 'd encourage it to be done sooner rather than later . 
 I 'll support this if the current stream types in HTTP/3 and QPACK get values of 63 or smaller , making the encodable in a single byte . 
 Yes , that would be the only sensible plan , as it was with QUIC frame types . These are important enough to spec at the beginning , so we take prime positions . I would also recommend the same registration rules : to 0x3f = Standards Action or IESG Review , to 0x3fff = Specification Required , all other values = Private Use . 
 I also support this ( with changing existing stream types to be < = 63 ) . I 'd also make it a MUST encode as smallest possible encoding . 
 Discussed in Tokyo ; despite some unhappiness , we will do this . 
 I 'm not against the idea of this . The observation I made during the discussion is that uni streams are a critical part of a H3 session . Failure to read the uni stream type successfully , when it is a control stream , will be a killer : reading a single byte is more resistant to failure . I think we should put some energy into the H3 interop to try and ensure that implementations are resilient to varint stream type failures . I wonder if this can be done as a test vector , or by some other interop test design . 
 One idea for testing is to use a set of grease streams . On connection open the opposite endpoint sends partial varints at various encoding lengths ( e.g. write one byte , delay , write another byte , etc ) . the receiving endpoint should either wait for a complete varint and then proceed ( i.e. a resilient endpoint ) , or it will explode in varint parse failure ( a fragile one ) . 
 I plan to send unidirectional stream types in non - minimal varint encodings . Vive la liberté . 
 Great opportunity for network - oriented fuzzer 
  ? I 'm talking a live stack . 
 Me too . To elaborate my thoughts , some of the test methods presented at EPIQ , like quic tracker , can easily write bytes - on - wire tests that exercise such handling and edge cases 
 Reusing the language from the transport frame might make this easier , though we might decide not to worry about enforcing the minimum - sized encoding for HTTP . I 'm not advocating for this in particular , but we seem to have a bunch of issues on our plate around the basic frame formats . See also , which proposes this for settings types . And , which proposes reordering of the frame . Considering these issues together might be a good idea . 
 As stated in , I do not think that we should make this change . Our experience from HTTP/2 tells us that it 's unlikely that we would run out of the 8 - bit number space , and therefore requiring every stack to decode type using varint seems like an unnecessary complexity . Note that the endpoints would be required to decode the varint even if we decide to enforce minimum - sized encoding . This is because H3 allows use of frame IDs without negotiation . 
 I 'm in favor of varint with the min - size requirement . The ability to perform experiments without coordination is worth the addition of a 5 - line inline function . 
 what do you mean by without coordination ? 
 The idea is that there is a lot of space in the 8 - byte version , and so if you just pick a random code point in that space , the chance of collision is vanishingly small . This means people can do experiments without having some registry or other mechanism to prevent people choosing the same code point . 
 That 's what I figured ; but it 's not zero . ( Note that you only get 62 , not 64 , bits . ) 
 No random selection mechanism ever has a 0 chance of collision , but we routinely build systems that rely on not having collisions in these circumstances . 
 How do we decide how the varint 62 - bits are used ? I recall this being a discussion topic that led to the invariants saying the space is used however the endpoints decide . Would H3 frames need to coordinate with SETTINGS or just assume varint encodes 1 - byte updwards ? 
 That 's a good point . It would be bad to have to support small values encoded using the full eight bytes . 
 I 'm generally in favor of this , because it adds consistency and I believe it will make experimentation easier without explicit approval of the HTTP WG . Thanks for filing a separate issue . 
 IMO , the endpoints willing to do experiments should spend their 5 - line worth of coding effort to negotiate the experiment , rather than asking every implementation to accept the complexity . As suggested in the last paragraph of HTTP/3 section 7 , endpoints that are willing to do an experiment can exchange their own SETTINGS value to confirm that the peer supports the experiment , then use any of the unused 8 - bit frame types for the experiment . The benefits of the approach are : does not introduce the need to deal with varint types less network overhead in experiments ( due to being able to use 8 - bit types ) less chance of the experiment becoming a de - facto standard The last argument is based on the fact that the experiments use negotiation . The fear of doing experiments is that sometimes the code point used for the experiment gets ossified ; you can not decide when to stop sending the extensions . Negotiating the use is one way to mitigate the problem , because with negotiation you can observe if the extension is actually used by the peer . 
 One thing that SETTINGS does n't support is the use of new frame types prior to receiving SETTINGS . For instance , if I wanted to push out an origin policy in 0.5RTT on a regular connection ( using the context - free push that and talked about ) , I could maybe do that with a new frame type . Both h2 and h3 allow unannounced use of new frame types , so this would work fine . If the space is 8 - bit , then I ca n't experiment with that spontaneously and without coordination . I 'm leaning toward the varint on that basis . The larger encodings will push things off the fast path , but I think that 's OK . 
 While I agree to the fact that it is impossible with the 8 - bit design to send new frame types in 0 - RTT , I am not sure if I am convinced with the argument that it represents the necessity to have varint frame types . Consider the 0 - RTT context - free push case . We not only need to have new frame types but also need to change the semantics of push . The request headers of a context - push can not be sent in a way that a client ( that does not understand the extension ) can ignore . Therefore , to me it seems that any extension to be sent from the server in 0 - RTT needs to have a different unidirectional stream type . Therefore I think is the way to go , but that having varint frames types is not . 
 I do n't think that is true . If you assume that this is a QPACK - encoded header block , that would be true ( because it would create an expectation of acknowledgment ) , but you do n't need to use QPACK . That example , is - as you say - better on a unidirectional stream . And - with a small cost in head - of - line - can be done based on SETTINGS . But I ca n't say confidently that there is no use of 0.5 - RTT that would benefit from having relative ordering with other activity on the control stream . 
 The request headers of a context - push can not be sent in a way that a client ( that does not understand the extension ) can ignore . Maybe I should have pointed out that push streams start with a Push ID , however if a server has a usable  ID is not determined until it receives a  frame from the client . Does n't sending a push stream in 0.5 RTT violate that requirement ? 
 That 's not really relevant . If the intent is to enable pushing of stuff in 0.5RTT , then the design would n't necessarily use push IDs . It does n't need to associate the push with a request , so it does n't need them , it could just use a new stream type . But I think we 're well into the weeds here . Point is that there might be valid uses for sending extension frames before receiving SETTINGS . 
 The point is that how such a context - free push in 0.5 RTT would look like to a client that only implements H3 . H3 requires every push stream to carry a Push ID ( immediately following the stream type ) . Every non - negotiated extension including context - free push need to obey the requirements . Yeah . My point is that there would be not a single case for that , because my understanding is that a server can not start sending frames on an unidirectional stream due to the restriction I point out . 
 Sorry , I 'm being dense , obviously . Which restriction ? 
 No , I was imprecise in my last sentence . What I was trying to clarify is that it is a requirement of H3 that a server can not start sending frames on a push stream before it receives a  frame from the client , which arrives after SETTINGS . Therefore , any use of an extended frame on the push stream can be negotiated . Unidirectional streams other than the push stream are not restricted to the frame definition of H3 , so we have the room to do whatever we want , regardless of if we have varint frame types in H3 . The only case a server might want to send extended frames before seeing SETTINGS is when the client 's request arrives before the SETTINGS frame due to packet loss or out - of - order delivery ( I have n't considered this case before ; please forgive me if you assumed this case ) . But if we do care about such case ( i.e. using 0.5 RTT or SETTINGS being delivered later ) , I think we should revisit the discussion of if we should use Transport Parameters for sending H3 settings . We would have the following benefit by exchanging H3 settings using   , : QPACK dynamic table can always be used ; there is no need to operate in restricted mode until receiving SETTINGS from the peer Use of 0.5 - RTT push ( or any other extension ) can be negotiated . That avoids wasting the bandwidth by sending extensions that the client does not understand . 
 I agree with that exchanging H3 settings in transport parameters has appealing benefits , there is however the downside that client transport parameters are not encrypted , and this could therefore be used for fingerprinting . That said we may be somewhat off topic , as this issue is about 8 - bit vs varint for h3 frame types . Without going into the details discussed in this thread , there seems to be interest in allowing uncoordinated extensions , and varints allow those at a very small implementation cost . 
 I am not sure if we need to care about the downside , considering the fact that we are sending other parameters ( including the transport - level transport parameters ) in clear . If we do care , we should try protecting all of them . Yeah my point was that people interested in doing private experiments can always negotiate the use of the extensions for all the cases the WG decided to care about , and therefore that there is not a benefit in having varint frame types , especially assuming that sending private experimental extensions to the wild without coordination is likely to be just waste of bandwidth ( or if the experiment succeeds and many softwares start supporting it , we would be forced to standardize using the experimental codepoint ) . 
 I do n't feel strongly either way . You can always request a code point assignment from IANA without publishing an RFC , and experience suggests we 're unlikely to run out of code points . ( If we do , we revive the EXTENDED frame that contains a sub - type field and a payload defined by the sub - type . ) However , there is value in being able to do some initial tests without registering a codepoint . This can be done , as  suggests , either by advertising a setting or by allowing super - high codepoints for private use . I suspect the technical merits of either will ultimately prove irrelevant and this will wash whichever direction " varint all the things " goes . 
 I think it 's worth noting that the side effect of having varint h3 frame types means that we would need to redesign ( or abandon ) the HTTPMALFORMEDFRAME error code . It relies on the frame types always being 8 - bit . 
 Discussed in Tokyo ; moderate support and minimal opposition . We will do this . HTTPMALFORMEDFRAME will need to change . Two proposals : reflect the frame type if < 255 , and 255 indicates " other . " reflect the low byte of the frame type ; collisions should be relatively rare . 
 If we varint all the things , how likely is it that malformed frames occur ? Many frames carry just a varint payload , so malformed seems mostly to be that frame length ( i.e. payload length ) mismatches the sum of received payload parts . 
 That was one of the core points of , FYI . 
 Currently we are using values which would be fit in one byte , so it would save a tiny bit of space , and given that you already have to parse the varint for the value anyway , it would n't make things harder , and would give flexibility for experimental extensions and the like . 
 Good question , using varints SGTM . 
 Dupe of ? 
 +1 to making the change , because IIUC this is the only place in H3 where we use a fixed - size multi - byte integer encoding . We can have a consistent design pattern just by changing this . 
 In Tokyo , agreed to do this . 
 With minimal encoding . 
 No , the conclusion was to not require minimal encoding for anything . There is a performance argument for QUIC frames because they are used very frequently , but even that has been challenged . The minimal encoding is only a miniscule amount more efficient , and it 's more annoying to create . 
 It makes it slower to parse than JSON 
 My previous comments are addressed by the " non zero values of N " fix .
Paragraph (version A):
Unidirectional streams, in either direction, are used for a range of
purposes.  The purpose is indicated by a stream type, which is sent
as a single byte header at the start of the stream.  The format and
structure of data that follows this header is determined by the
stream type.
Paragraph (version B):
Unidirectional streams, in either direction, are used for a range of
purposes.  The purpose is indicated by a stream type, which is sent
as a variable-length integer at the start of the stream.  The format
and structure of data that follows this integer is determined by the
stream type.
Paragraph (version A):
A control stream is indicated by a stream type of "0x43" (ASCII 'C').
Data on this stream consists of HTTP/3 frames, as defined in frames.
Paragraph (version B):
A control stream is indicated by a stream type of "0x00".  Data on
this stream consists of HTTP/3 frames, as defined in frames.
Paragraph (version A):
A push stream is indicated by a stream type of "0x50" (ASCII 'P'),
followed by the Push ID of the promise that it fulfills, encoded as a
variable-length integer.  The remaining data on this stream consists
of HTTP/3 frames, as defined in frames, and fulfills a promised
server push.  Server push and Push IDs are described in server-push.
Paragraph (version B):
A push stream is indicated by a stream type of "0x01", followed by
the Push ID of the promise that it fulfills, encoded as a variable-
length integer.  The remaining data on this stream consists of HTTP/3
frames, as defined in frames, and fulfills a promised server push.
Server push and Push IDs are described in server-push.
Paragraph (version A):
Stream types of the format "0x1f * N" are reserved to exercise the
requirement that unknown types be ignored.  These streams have no
semantic meaning, and can be sent when application-layer padding is
desired.  They MAY also be sent on connections where no request data
is currently being transferred.  Endpoints MUST NOT consider these
streams to have any meaning upon receipt.
Paragraph (version B):
Stream types of the format "0x1f * N + 0x21" for integer values of N
are reserved to exercise the requirement that unknown types be
ignored.  These streams have no semantics, and can be sent when
application-layer padding is desired.  They MAY also be sent on
connections where no data is currently being transferred.  Endpoints
MUST NOT consider these streams to have any meaning upon receipt.
Paragraph (version A):
An 8-bit type for the frame.
Paragraph (version A):
A variable-length integer that describes the length of the Frame
Payload.  This length does not include the Type field.
Paragraph (version B):
A variable-length integer that identifies the frame type.
Paragraph (version A):
The payload of a SETTINGS frame consists of zero or more parameters,
each consisting of an unsigned 16-bit setting identifier and a value
which uses the QUIC variable-length integer encoding.
Paragraph (version B):
The payload of a SETTINGS frame consists of zero or more parameters.
Each parameter consists of a setting identifier and a value, both
encoded as QUIC variable-length integers.
Paragraph (version A):
Setting identifiers of the format "0x?a?a" are reserved to exercise
the requirement that unknown identifiers be ignored.  Such settings
have no defined meaning.  Endpoints SHOULD include at least one such
setting in their SETTINGS frame.  Endpoints MUST NOT consider such
settings to have any meaning upon receipt.
Paragraph (version B):
Setting identifiers of the format "0x1f * N + 0x21" for integer
values of N are reserved to exercise the requirement that unknown
identifiers be ignored.  Such settings have no defined meaning.
Endpoints SHOULD include at least one such setting in their SETTINGS
frame.  Endpoints MUST NOT consider such settings to have any meaning
upon receipt.
Paragraph (version A):
Frame types of the format "0xb + (0x1f * N)" are reserved to exercise
the requirement that unknown types be ignored (extensions).  These
frames have no semantic value, and can be sent when application-layer
padding is desired.  They MAY also be sent on connections where no
request data is currently being transferred.  Endpoints MUST NOT
consider these frames to have any meaning upon receipt.
Paragraph (version B):
Frame types of the format "0x1f * N + 0x21" for integer values of N
are reserved to exercise the requirement that unknown types be
ignored (extensions).  These frames have no semantics, and can be
sent when application-layer padding is desired.  They MAY also be
sent on connections where no data is currently being transferred.
Endpoints MUST NOT consider these frames to have any meaning upon
receipt.
Paragraph (version A):
An error in a specific frame type.  The frame type is included as
the last byte of the error code.  For example, an error in a
MAX_PUSH_ID frame would be indicated with the code (0x10D).
Paragraph (version B):
An error in a specific frame type.  If the frame type is "0xfe" or
less, the type is included as the last byte of the error code.
For example, an error in a MAX_PUSH_ID frame would be indicated
with the code (0x10D).  The last byte "0xff" is used to indicate
any frame type greater than "0xfe".
Paragraph (version A):
This document establishes a registry for HTTP/3 frame type codes.
The "HTTP/3 Frame Type" registry manages an 8-bit space.  The "HTTP/3
Frame Type" registry operates under either of the "IETF Review" or
"IESG Approval" policies RFC8126 for values from 0x00 up to and
including 0xef, with values from 0xf0 up to and including 0xff being
reserved for Experimental Use.
Paragraph (version A):
While this registry is separate from the "HTTP/2 Frame Type" registry
defined in RFC7540, it is preferable that the assignments parallel
each other.  If an entry is present in only one registry, every
effort SHOULD be made to avoid assigning the corresponding value to
an unrelated operation.
Paragraph (version A):
The 8-bit code assigned to the frame type.
Paragraph (version B):
While this registry is separate from the "HTTP/2 Frame Type" registry
defined in RFC7540, it is preferable that the assignments parallel
each other where the code spaces overlap.  If an entry is present in
only one registry, every effort SHOULD be made to avoid assigning the
corresponding value to an unrelated operation.
Paragraph (version A):
This document establishes a registry for HTTP/3 settings.  The
"HTTP/3 Settings" registry manages a 16-bit space.  The "HTTP/3
Settings" registry operates under the "Expert Review" policy RFC8126
for values in the range from 0x0000 to 0xefff, with values between
and 0xf000 and 0xffff being reserved for Experimental Use.  The
designated experts are the same as those for the "HTTP/2 Settings"
registry defined in RFC7540.
Paragraph (version B):
This document establishes a registry for HTTP/3 settings.  The
"HTTP/3 Settings" registry governs a 62-bit space.  This space is
split into three spaces that are governed by different policies.
Values between "0x00" and "0x3f" (in hexadecimal) are assigned via
the Standards Action or IESG Review policies RFC8126.  Values from
"0x40" to "0x3fff" operate on the Specification Required policy
RFC8126.  All other values are assigned to Private Use RFC8126.  The
designated experts are the same as those for the "HTTP/2 Settings"
registry defined in RFC7540.
Paragraph (version A):
The 16-bit code assigned to the setting.
Paragraph (version A):
This document establishes a registry for HTTP/3 unidirectional stream
types.  The "HTTP/3 Stream Type" registry manages an 8-bit space.
The "HTTP/3 Stream Type" registry operates under either of the "IETF
Review" or "IESG Approval" policies RFC8126 for values from 0x00 up
to and including 0xef, with values from 0xf0 up to and including 0xff
being reserved for Experimental Use.
Paragraph (version A):
The 8-bit code assigned to the stream type.