Draft: draft-ietf-quic-http

Commentary: As discussed on Slack , currently the text makes no mention of the case where the PUSHPROMISE arrives behind ( some of ) the data on the push stream itself . However , it does mention this situation for the DUPLICATEPUSH frame . This proposed change recommends buffering pushed data for an unknown  and using flow control to prevent this from being a problem . I am unsure if more text is needed ( e.g. , what happens if the  is never resolved ( which would mean a misbehaving server ) ) , but I think the proposed change should suffice . This is also related to issue . Thanks to for his help . 
 LGTM . Non - normative language seems to be the best form of guidance here 
 the push i d that links a push stream to a push promise is now an unframed varint that comes right after the stream preface . this is right now the only unframed data ( except made for the unidirectional stream prefaces ) in the specs and I am proposing to make that a frame as well for consistency and to simplify implementation and allow code reuse . motivation : the specs already define frames that only carry a single varint ( mostly push related )  push i d duplicate push cancel push and goaway ! here instead we decided to leave it unframed just because we can since it is at the beginning of the stream cost : two extra bytes per push stream the text will need to specify that on a push stream this new frame (  ? ) MUST be the first one , otherwise it is a protocol error . I am happy to put up a PR , in case we reach consensus 
 The varint type and length of a frame is also unframed . So you are asking to trade one unframed varint for two . Is your assertion that this is unique and difficult code to write , or that the unframed content is somehow difficult to manage ? 
 This seems to be going back to some of the early discussion we had on a thread I ca n't find . I 'm not against discussing things again because we have more experience . However , I do n't see a compelling reason for the change . My implementation needs to parse unframed data because of the stream header and for QPACK streams . I think this change might make my implementation more complex . Reading multiple varints requires more work : more checks to see if the stream has enough data , more checks to ensure only 1 frame sent at a specific time ( this is the same as SETTINGS ) 
 those are in the frame header -- so they are part of the frame . I am not sure what your point is here then . Here I am assuming that an implementation has generic code to parse frames , and that parsing anything that is not part of a frame requires special handling . While this is implementation specific and there can definitely be counter examples , from an abstraction and consistency point of view I see no reason for doing it the way we are doing it now . ( If we discount the unidirectional stream preface ) I believe there should be two type of streams : framed ( control , request , and push streams ) and unframed ( QPACK , and potentially extension streams ) . The push stream right now is a hybrid , that only becomes a framed stream after receiving that first PUSH_ID . If I am recalling correctly when we discussed potentially having DATA frames with zero - length to transition to unframed data , it was also considered a bit unusual . Here I am arguing that we are sort of doing the reverse here where we have an unframed stream that then transitions to framed . I think this generates complexity . And really the benefit we get is saving two bytes and one frame type . I do vaguely remember that discussion and not ' wasting ' frame types may have been one of the arguments when we made that decision , but that is not a problem now that we have a 62bit space for frame types . 
 I do n't care about the cost , I care about things like having to deal with  ( or whatever ) frames in places other than the start of a push stream . And I do n't believe that it is difficult to take the special - case code for pulling a varint off a partially - available stream and use that for push ID . We 've not had too much trouble with that so far in our implementation . 
 it is definitely not difficult , but it is a special case and as any special case forces an increased complexity in the possible codepaths , even if not that big in this case . I am making my argument for the sake of consistency mostly , and for the fact that I believe it would also help to better define error handling . With the current text , if I receive something bogus on a push stream ( after the preface ) I 'll have to keep the stream around ( because the push stream may come out of order ) waiting for a PUSH_PROMISE with that ID that may never come . So I believe that framing could help error handling as well . I do not have super strong feelings about this proposal but at the same time I 'd like us to try and recall what the motivations are for the current text and for making this special since it was a while back and personally I ca n't recall what they were . 
 This sounds like the case is looking at . I 'd argue this is a good reason for the current design , frame processing should only take place once the PUSHPROMISE is received . But I 'd like to understand how framing could help avoid errors . 
 I was not trying to solve the same problem as here , but I was mentioning the fact that I believe framing would slightly help in a subset of cases . Take a server with a buggy push implementation , rather than a malicious one . Something that does n't send the PUSHID at all . On the client you 'll start seeing a flow of data and you ca n't do anything better than parsing the first few bytes of that as a PUSHID , and basically see random IDs . With Framing , if a server forgets to send the  , it is clear at the receiver that it is a protocol error . That being said there are many other classes of bugs that may trigger the same behavior even with frames , so this is minor . now , that seems like an implementation dependent claim :) as says ( and I like it ) a client should buffer any data after receiving the PUSH_ID and before it has a PUSH PROMISE for it . and that is sufficient . no mention of frames there . 
 Right now in draft 19 we have : varint - stream type varint - push ID varint - frame type ( HEADERS ) . The assertion then is , if step 2 gets skipped by the sender , the receiver will parse the HEADERS frame type as a varint expecting it to be the push ID ( value 0x1 , with no restriction on min or  encoding ) . It will then parse the HEADERS frame length as a varint expecting it to be the HEADERS frame type ( length is unlikely to be 1 ) . Does n't the client just blow up at that point ? 
 It was just an example . And as I said I do n't feel strongly about the error handling nit . But if you must , yes if you assume headers is the first frame after the pushid then yes you would read 0x1 which is conveniently a server initiated bidirectional stream which is not allowed anyway , so you could reject it immediately . But I find this just fortuitous . For example , one could make a counter argument : why are we framing SETTINGS at all given that it is the first message on the control stream ? We also defined it quite clearly in this table what to do with it [ Certain frames can only occur as the first frame of a particular stream type ; these are indicated in Table 1 with a ( 1 ) . ] Do you think there is zero value in doing that for the PUSHID as well ? I personally think there is some value . Anyway , I think we are diverting this the wrong route . All I am looking for here is a good explanation for why it is defined like it is now , and I am failing to find it . As far as the implementation goes it makes little difference , and I guess it is more of a consistency problem for me . That naked varint on the wire triggers my OCD :) So instead of going back and forth like this , perhaps can shed some light on the good reasons why it is this way . 
 +1 to levelling up , I 'll take acknowledge my guilt here . But before I move on : If your at the stage of parsing QUIC STREAM frame payload , you should already know exactly what the stream ID is . Some historic points I remember : In Paris MT presented some ideas for unidirecitonal streams - This relates to issue and PR Push and control streams were identified then . And we were happy with reserving specific stream IDs for certain things . All non - reserved streams were server push streams . Subsequent data on the stream only makes logical sense to handle if you know what push it relates to , so those bytes go first . Roll forward some , QPACK design requires additional streams so those get reserved to . Around  , the topic of unidirectional stream types comes up . Without types , we make uncoordinated unidirecitonal stream extensions quite a difficult thing . So add more bytes at the start of stream and remove reservations . The SETTINGS frame can contain a set of parameters , indeed it SHOULD contain at least one GREASE setting . A single SETTINGS frame that describes the length of all parameters is quite useful , you know when the peer has finished sending all of them . I do n't see as much value for PUSHPROMISE because you 're just framing a single integer that describes its own length already . 
 oh gosh yeah , I confused PUSHID with a stream i d. scratch that completely 
 One can imagine a scenario where we 'd want to place something before the SETTINGS frame on the control stream . On the other hand , it 's less likely we 'd ever want anything other than the Push ID to begin the push stream . 
 Discussed in London ; no . 
 Seems like a good editorial improvement .
Paragraph (version A):
When a server later fulfills a promise, the server push response is
conveyed on a push stream (see push-streams).  The push stream
identifies the Push ID of the promise that it fulfills, then contains
a response to the promised request using the same format described
for responses in request-response.  Due to reordering, data on a push
stream can arrive before the corresponding PUSH_PROMISE, in which
case both the associated client request and the pushed request
headers are unknown.  Clients which receive a new push stream with an
as-yet-unknown Push ID can buffer the stream data in expectation of
the matching PUSH_PROMISE.  A client can use stream flow control (see
section 4.1 of QUIC-TRANSPORT) to limit the amount of data a server
may commit to the pushed stream.
Paragraph (version B):
When a server later fulfills a promise, the server push response is
conveyed on a push stream (see push-streams).  The push stream
identifies the Push ID of the promise that it fulfills, then contains
a response to the promised request using the same format described
for responses in request-response.  Due to reordering, data on a push
stream can arrive before the corresponding PUSH_PROMISE, in which
case both the associated client request and the pushed request
headers are unknown.  Clients that receive a new push stream with an
as-yet-unknown Push ID can buffer the stream data in expectation of
the matching PUSH_PROMISE.  A client can use stream flow control (see
section 4.1 of QUIC-TRANSPORT) to limit the amount of data a server
may commit to the pushed stream.