Draft: draft-ietf-masque-h3-datagram

Commentary: This PR represents the consensus of the 2021 MASQUE Design Team . . . cc 
 I think that this is right , but we should be more precise about what this means . That is , if the method is CONNECT and either : intermediary understands the : protocol selection , or request includes Capsule - Protocol Then the intermediary can forward DATAGRAM capsules as QUIC DATAGRAM frames or forward QUIC DATAGRAM frames as DATAGRAM capsules . Those conditions could be spelled out more clearly . 
 I agree . I 'll add this to the . Note that this was filed on the wrong repository , is the droid you 're looking for . 
 Oops . You should be able to move the issue . 
 Ah right , thanks ! I 've moved the issue . 
 With and , there is no longer a CLOSECONTEXTID Capsule , with its associated error codes . H3 Datagram still says that unknown capsule types must be ignored . This creates a dilemma : if I send a capsule like REGISTERFOOCONTEXT , acknowledged by a REGISTERFOOACK response , how do I know if it worked ? If the REGISTERFOOCONTEXT capsule is ignored , I will have to wait indefinitely for the ACK , or set a timeout (  ) . There are a few different ways to solve this , but I think the cleanest is the REGISTERDATAGRAMCONTEXT capsule type from the ( published ) H3 Datagram draft . CONNECT - IP and CONNECT - UDP can make that capsule type mandatory to implement , so we do n't need to worry about whether the other side supports it . This also highlights why we need a " Datagram Contexts " draft supporting CONNECT - UDP and CONNECT - IP . We need the " Datagram Format Types " concept , the CLOSEDATAGRAMCONTEXT capsule type , and all the other bits . We could paste all of this into CONNECT - UDP , but I do n't think we want to cross - reference it out of CONNECT - UDP every time we need to define a new extension or format . 
 From yesterday 's meeting I recall you were less interested in opening a new draft for Datagram Format Contexts . How do you think we should resolve this problem ? 
 My suggestion is that CONNECT - UDP and CONNECT - IP both define that they use a varint as the first field in the datagram body , which is an identifier that capsules can register , and then various extensions define their own formats . Each new capsule / datagram extension would define its own Datagram Payload format . I strongly feel that we should n't have a generic REGISTERDATAGRAMCONTEXT or CLOSEDATAGRAMCONTEXT , since then you just need another registry of types within that . The capsule registry itself is sufficient . Each extension can define for itself the capsules it needs . Not all extensions need the ability to ack or close , but some do . So , if your extension needs to be have ACKs and CLOSE , define that . If you do n't , do n't . You could have :    And for some other extension : REGISTERBARCONTEXT CLOSEBARCONTEXT And maybe for another , just a register : REGISTERXYZCONTEXT 
 OK , so I send you a REGISTERFOOCONTEXT and then I wait for ACKFOOCONTEXT to confirm . How long do I wait before concluding that you do n't support FOO , and dropped the capsule as unrecognized ? 
 You can use request headers that are expected to be echoed in responses to indicate if the other supports the extension at all . Alternatively , there could be a generic " I did n't understand your capsule type " error . I think that 's better than trying to generalize context - specific errors . 
 OK . I would prefer the second option , to avoid request bloat . That would require updating H3 Datagram with an UNKNOWN_TYPE capsule , containing a varint , emitted in response to any unrecognized capsule . This still does n't address the other registration failure modes we 've considered ( e.g. malformed request , context limit reached ) . I would prefer not to have to duplicate those concepts for every extension we define , but I can tolerate it if necessary . 
 HTTP headers are the best mechanism to establish support for extensions . I do n't think we need anything generic here , we could revisit that if we see multiple extensions duplicating work though . 
 I 've drawn up an example ( ) of how I think PING and TIMESTAMP extensions would work in this model ( no generic registration , support negotiated by headers ) . It can be done ! In my view , the lack of any generic signaling for context creation is going to be a major pain for implementors , resulting in a lot of duplicated ( or worse , almost - duplicated ) code . To streamline it , I 've left out all the detailed error codes for malformed or excessive registrations , which would also have to be duplicated for each extension . I think we 'll get a higher - quality standard if context lifetime management is defined and implemented once , well , instead of being redefined and reimplemented poorly for each extension . EDIT : Added the IANA registration instructions for the new HTTP headers required for each extension . Now it 's even longer ! 
 We 've been discussing this topic on the and on the , but rightly points out that this deserves its own issue . There is interest in deploying extensions to protocols that use HTTP Datagrams . Some of these extensions require the ability to send multiple types of HTTP datagrams associated with a single request stream . For example , an extension to CONNECT - UDP that allows measuring the HTTP Datagram MTU an extension to CONNECT - IP that allows compressing IP headers This means that when these extensions are in use , HTTP Datagrams carry an identifier that allows the receiver to know what kind of HTTP Datagram it 's receiving ( e.g. " is this a UDP payload or an MTU probe ? " or " is this a full IP packet or a compressed one ? " ) . One potential solution is to have CONNECT - UDP and CONNECT - IP require their HTTP Datagrams to always start with an identifier . This has the unfortunate downside of wasting a byte for requests that do not use extensions , and also precludes WebTransport from using extensions in the future . Alternatively , we could define an optional extension to HTTP Datagrams which has the advantage of not wasting bytes when not in use , and allows any protocol relying on HTTP Datagrams to use it if chooses to at any point in the future . This extension would be negotiated via an HTTP header . Let 's assume we are going with the model of an optional extension to HTTP Datagrams . Since this is optional , a client will not know whether it is supported by the server until it receives the response headers . " Zero - Latency Extensibility " is the ability for a client to send HTTP Datagrams ( both the " regular " datagram that 's the default one from the request , and the " extension " datagrams ) . Note that this does n't apply to the server because the server does n't send HTTP Datagrams until after it 's parsed the request headers . Let 's call the flight of frames and/or packets that go alongside the HTTP request headers the " first flight " . The requirement is for the client to be able to send both " regular " and " extension " HTTP datagrams with its first flight , and to have the server parse them as follows : if the server supports the extension , the server can correctly parse both " regular " and " extension " HTTP datagrams from the first flight ; if the server does n't support the extension , the server can correctly parse the " regular " datagrams and drop the " extension " ones . Intermediaries should n't have to know or care about this extension . All that intermediaries need to do is blindly convert between QUIC DATAGRAM frames and DATAGRAM capsules regardless of any extension being used . This puts one constraint on the solution : QUIC DATAGRAM frames and DATAGRAM capsules need to have the same semantics because they can get converted between one another by intermediaries . Solving this problem once the headers is exchanged is pretty straightforward : if both endpoints support the extension , then datagrams start with an identifier . Otherwise , they do n't contain the identifier . Getting this to work before the response headers are received is slightly more tricky : it requires having a way to distinguish between datagrams sent before the headers were received and ones sent after . The simplest way to distinguish them is to define two capsules and use the capsule type to tell us which is which . The datagram context extension works as follows : it is negotiated by adding a header to both request and response , and when both endpoints support it , it adds a context ID varint at the start of the HTTP Datagram Payload field . Now , in order to achieve zero - latency extensibility , the client needs to be able to send datagrams before receiving the server headers in such a way that the server can correctly parse them ( if you add the context ID and the server does n't support the extension , you do n't want the server to parse the context ID as part of the payload ) . So here 's my idea for how to accomplish that . The extension says the following : clients that support the extension are not allowed to send QUIC DATAGRAM frames nor DATAGRAM capsule before they 've received the server headers the extension defines a new RELIABLEDATAGRAMEXT capsule that can be sent before and after receiving server headersthe extension does not change the semantics of the RELIABLEDATAGRAM capsule , that still does not contain a Context IDwhen both endpoints support the extension ( after receiving headers ) the extension changes the semantics of both the QUIC DATAGRAM frame and DATAGRAM capsule to include a Context ID at the start : if the client wishes to use zero - latency extensibility , it can send RELIABLEDATAGRAM and RELIABLEDATAGRAMEXT before receiving the server headers . Both of these will be parsed correctly by servers , whether or not the server supports the extension . All of this relies on the fact that there is one bit that differentiates the DATAGRAM capsule from the RELIABLEDATAGRAM capsule ( the bit is in the capsule type ) , so that the extension can give the two capsules different semantics in a way that is backwards compatible . I 'm realizing that calling this RELIABLEDATAGRAM tied zero - latency extensibility to . This would work just as well if we renamed RELIABLEDATAGRAM to EARLYDATAGRAM or UNEXTENDED_DATAGRAM . 
 I do n't view it as waste . I view it as the ( extremely low ) cost of simple and performant 0 - RTT extensibility . When you make mechanisms complex , the may solve problems on paper , but no one will use them -- see HTTP/2 Priorities . Is there a more concrete argument for how this byte will cause performance problems for users of unextended CONNECT - UDP or CONNECT - IP ? If WebTransport might ever want to change the layout of H3 Datagrams , it should add an identifier now . 
 Yeah , I 'm with  on this . This design is considerably more complex and forces clients into using reliable , ordered transfer for ~1RTT if they want to use extensibility . Spending the byte or so on a type discriminator is far simpler . For WebTransport , I doubt we 'll need this . We hand off responsibility for the content of datagrams to applications . And then there is always the possibility of a WebTransport version 2 . ( Here , I am forced to acknowledge that protocol negotiation with extended CONNECT is likely a complete disaster , but now we 're far enough into speculative territory that I 'm OK with that risk . ) 
 Separately , That presumes that the negotiation of extensions that modify the payload of datagrams occurs atomically . If the extension is not negotiated atomically and uses capsules that are sent after the request , then a server might process a request and send DATAGRAM frames ignorant of the potential for extensions to be used . That creates an ambiguity at the client . The client can not know if the server has not understood the extension ( so that the datagram does n't include a context / type / usage field ) or whether it is using the extension ( so that it does ) when it receives the first DATAGRAM frame , which is likely to arrive before any negotiation signals . That means that the server also has to follow the pattern of sending datagrams as part of the stream , with the various markings you have , unless you bind the processing of extensions into the HTTP request header fields . There 's no mention of how these extensions are negotiated here , so I assume that you are planning to use HTTP header fields in order to get this . My thought would be that it is easier to do that sort of negotiation with capsules , which is what previous versions of the draft did . That this comes with this constraint on how extensions are negotiated or used makes it less appealing . 
 sorry for being unclear . Whether or not contexts are in use ( by which I mean " does the payload start with a context ID varint ? " ) is negotiated via an HTTP header . That occurs atomically . Subsequently , capsules are used to assign semantics to a given context . There 's no ambiguity on the receiver there , because if you receive a datagram for context 4 and you have n't received or understood what context 4 means you can just drop that datagram . 
 I agree that it 's much simpler to just always have the context ID be present for protocol that want to be able to tag different datagrams . This means there 's no complexity about when unreliable datagrams are allowed to be sent , or dealing with headers to try to guess how to interpret payloads . It 's much more deterministic and will be less prone to implementation bugs . 
 Since both  and Tommy specifically mentioned " Context ID " , I 'll point out that the identifier could be the context ID as currently specified in the drafts , but alternate designs are possible . 
 registered . Endpoints MUST NOT close a Context ID that has already been closed . If an endpoint receives a CLOSEDATAGRAMCONTEXT capsule that violates one or more of these requirements , the endpoint MUST abruptly terminate the corresponding stream with a stream error of type H3GENERALPROTOCOLERROR . I think this text should acknowledge that both sides may close a context at the same time and that a CLOSEDATAGRAM_CONTEXT may be received for a already closed context . This is just a nit , but I think worth mentioning . 
 field in order to associate the QUIC DATAGRAM frame with a stream and context within that stream . If an endpoint receives a QUIC DATAGRAM frame whose payload is too short to allow parsing the Quarter Stream ID field , the endpoint MUST treat it as an HTTP/3 connection error of type H3GENERALPROTOCOLERROR . If an endpoint receives a QUIC DATAGRAM frame whose payload is long enough to allow parsing the Quarter Stream ID field but too short to allow parsing the Context ID field , the endpoint MUST abruptly terminate the corresponding stream with a stream error of type H3GENERALPROTOCOLERROR . This tests talks about paring of Context ID on an endpoint , but  ID is optional . The text should acknowledge that better . 
 The generic definition of Capsule includes the field that is the length of all remaining fields , which depends on the type . We state that the length can be zero . However , many of the capsule types we define can not be zero - length : REGISTERDATAGRAM - at least 1 byte REGISTERDATAGRAM_CONTEXT - at least 2 bytes       bytes We could be more prescriptive of these capsules . Such as explicitly marking the minimal length in the figures , or noting it in the prose . We might also recommend that receivers of these capsules reject capsules that are clearly too short 
 How about we do something similar to : 
 Is it also a connection error / FRAME_ERROR if the stream containing capsules ends in the middle of a capsule ? 
 Capsules are end - to - end so if the stream is aborted mid - capsule by an endpoint , there 's not much an intermediary can do , and it should n't impact other streams on the same connection . Our implementation will reset a stream if it receives a FIN mid - capsule . 
 Since capsules are above the layer of H2 and H3 , closing a connection seems quite extreme . I would treat these a bit like truncated HTTP content . Terminating the data stream seems like a decent recommendation , 
 If an endpoint aborts a stream mid - capsule , it should do so with a RST and not a FIN , right ? The text in H3 ( right below your linked text ) talks about truncation on graceful completion . Also , is the recommendation from the original issue ( malformed frames ) also be a stream or a connection error ? It seems like we should be applying the same logic to the two cases , right ? 
 Capsules are n't frames . We should expect some implementations to allow applications to inject their own capsules , just like application can insert HTTP content today . There might be valid reasons to terminate a stream , such as the user losing interest in a tunnelled connection , an implementation that is taking opaque application data and sending it has no way to ensure it does n't send a truncated capsule . For these reasons , I think recommending a connection closure is too extreme ( endpoints can always do that if they really want to ) . Recommending a stream closure , with possibly a new error code , seems right . 
 The capsules that signal use of different datagram contexts ( or the absence thereof ) assume that there is a generic need for this form of identification . That has not been established . WebTransport certainly does n't need it . As this is an end - to - end signal anyway , it is also a protocol - specific signal . All uses of this framework are perfectly capable of doing their own signaling and negotiation . A one - size - fits - all mechanism is more likely a one - size - fits - few mechanism , but it still comes with costs that every user has to bear ( see ietf - wg - webtrans / draft - ietf - webtrans - http3 for instance ) . For instance , if CONNECT - UDP wanted to signal ECN and DSCP , that might be more efficiently achieved with a single byte ( 2 + 6 ) rather than a varint . If CONNECT - IP wanted different compression contexts , that might be suited to a varint , but why would this draft be in a position to decide that ? As there is no value in an intermediary looking at these context identifiers - I would argue negative utility in the RFC 8558 sense - these should be removed from the protocol . The only potential value I see in having some sort of signaling here is to explicitly signal the use of DATAGRAM frames associated with a stream . However , as we have agreed to send DATAGRAM frames without negotiation , that too seems like it wo n't be needed . 
 Deciding where to draw the line between having a feature live in the shared domain or an application - specific domain is always tricky . On one hand if you share every feature , each application has to do useless work . On the other if you do n't share you end up reinventing many similar yet different wheels . In this case it is n't obvious because we have two applications that need it and one that does n't . So we ca n't make a decision based on architectural fundamentals . The question here is therefore a pragmatic one : how do we trade off between WebTransport 's ease of implementation and CONNECT - IP 's extensibility ? For me , it comes down to negotiation . I proposed the design that 's currently in the drafts because it has one property I really like : zero - round - trip negotiation . In other words , the client is free to choose between using or not using contexts , and can immediately start sending using its preferred choice without waiting to see the server 's headers . I see it as the best of both worlds : WebTransport gets efficient wire encoding at a very small implementation cost , and CONNECT - IP gets an efficient compression mechanism . 
 I 'm not sure why this is presented as a dichotomy . The draft can provide a mechanism for contexts layered on top of a common capsule framing , and then CONNECT - IP can use both , while WebTransport can use datagrams+capsules directly ( the exact semantics depending on the specific method or value used ) . 
 my concern there is that if WebTransport decides to only use a subset of HTTP Datagrams , then when someone implements a WebTransport - compatible intermediary , they 're going to skip implementing contexts . If we decide that all applications can use contexts , it will ensure we have a healthy ecosystem of intermediaries that support any HTTP Datagram application . 
 Sure , just like they can decide to drop any request that has method , or whatever value you come up with . There will be inevitable friction to introducing any specific new use of datagrams , and I do n't think you can pay the entirety of that cost upfront . The intermediaries that are used by people who want to pass MASQUE traffic will implement contexts , and for the rest , this does n't really matter . 
 There 's a very big difference here : if we decide that all HTTP Datagram applications are the same to intermediaries , it takes less work for them to support all of them than it does to support only one . That 's what ensures that they all get supported . The risk is someone implementing half the protocol to save time , not someone going out of their way to disallow some options . 
 I 'm confused . How do you make them same to the intermediaries while making them different to the endpoints ? 
 By ensuring that intermediaries treat all opaque capsules the same , but having endpoints parse and react to each capsule according to its semantics . 
 But if the intermediaries treat all of the capsules the same , it does n't matter if datagram contexts are optional or not , since it would require parsing capsules to know that . 
 Related to this , we have This seems to be a bit of a backdoor requirement . An implementation that only cared to support no - context datagrams would not need the context ID allocation service . 
  happy with this as - is , but would also support the editorial changes being discussed on the email thread around how intermediaries handle datagrams . LGTM , thank you !
Note that use of the Capsule Protocol is not required to use HTTP
Datagrams.  If a new HTTP Method or Upgrade Token is only defined
over transports that support QUIC DATAGRAM frames, they might not
need a stream encoding.  Additionally, definitions of new HTTP
Methods or of new HTTP Upgrade Tokens can use HTTP Datagrams with
their own data stream protocol.  However, new HTTP Method or Upgrade
Tokens SHOULD use the Capsule Protocol unless they have a good reason
not to.
This indicates that the context was closed to save resources.  The
recipient SHOULD limit its future registration of resource-
intensive contexts.
Note that while datagram capsules are sent on a stream,
intermediaries can reencode HTTP Datagrams into QUIC DATAGRAM frames
over the next hop, and those could be dropped.  Because of this,
applications have to always consider HTTP Datagrams to be unreliable,
even if they were initially sent in a capsule.
Because new protocols or extensions may involve defining new capsule
types, intermediaries that wish to allow for future extensibility
SHOULD forward capsules unmodified.  One exception to this rule is
the DATAGRAM capsule; see datagram-capsule.  An intermediary can
identify the use of the capsule protocol either through the presence
of the Capsule-Protocol header field (hdr) or by understanding the
chosen HTTP Upgrade token.  An intermediary that identifies the use
of the capsule protocol MAY convert between DATAGRAM capsules and
QUIC DATAGRAM frames when forwarding.  Definitions of new Capsule
Types MAY specify optional custom intermediary processing.
Note that while DATAGRAM capsules that are sent on a stream are
reliably delivered in order, intermediaries can reencode DATAGRAM
capsules into QUIC DATAGRAM frames when forwarding messages, which
could result in loss or reordering.
frames to datagram capsules allows HTTP Datagrams to be arbitrarily
large without suffering any loss; this can misrepresent the true path
properties, defeating methods such a DPLPMTUD.
frames to DATAGRAM capsules allows HTTP Datagrams to be arbitrarily
large without suffering any loss; this can misrepresent the true path
properties, defeating methods such as DPLPMTUD.
The value of the Datagram Format Type field (see datagram-formats)
is a 62-bit integer.
The value of the Close Code field (see close-capsule) is a 62-bit
integer.