HTTP/3におけるDATAGRAMの送信と、CAPSULEフレームについて

2022/03/31 最新動向も踏まえ、記事を新しく書き直しました
HTTP DatagramsとCapsuleプロトコルについて - ASnoKaze blog


QUICで再送を必要としないアプリケーションデータを送信するのに、DATAGRAMフレームが利用できます。このDATAGRAMフレームで送ったアプリケーションデータは、パケットの順番が入れ替わったり、パケットロスが起こってもQUICレイヤでの回復は行われません。

HTTP/3を応用したプロトコルであるWebTransportやMASQUEプロトコルでにおいて、このQUIC DATAGRAMフレームを利用するための議論が行われています。

今回は、HTTP/3でQUIC DATAGRAMフレームを使うための仕様を読んでいこうかと思います
www.ietf.org

なお、WebTransportやMASQUEについては過去に書いた記事を御覧ください

Using QUIC Datagrams with HTTP/3

HTTP/3で、QUICのDATAGRAMフレームを使うにあたって、どのHTTPリクエストに紐づくDATAGRAMフレームなのか関連付ける必要があります。

もともとは、ストリームIDで該当のリクエストストリームと紐付ける方法が考えられていました。しかし、ストリームIDはhop-by-hopの値ですので、end-to-endでHTTPリクエストと紐付けられる仕組みに変更されました。こうすることでproxyといった中間装置がいてもend-to-endでDATAGRAMをHTTPリクエストと関連付けることができます。

Using QUIC Datagrams with HTTP/3」のdraft-01では、Context IDを新しく導入し、HTTPリクエストとDATAGRAMフレームを関連付けます。DATAGRAMフレームを使う前に、HTTP/3のCAPSULEフレームで、リクエストストリーム上で明示的にその関連付けを行います。

なお、Context IDは62bit空間をもち、クライアントから払い出す場合は偶数を、サーバから払い出す場合は奇数となります。

HTTP/3 CAPSULEフレーム

CAPSULEフレームは、HTTP/3レイヤの拡張フレームです。HTTPリクエストを送信したリクエストストリーム上で送信されます。

f:id:ASnoKaze:20210516002411p:plain

CAPSULEフレームには、3つのタイプが定義されています。

  • REGISTER_DATAGRAM_CONTEXT: HTTPリクエストとDATAGRAMフレームを関連付けるのに使用するContext IDを通知します。
  • CLOSE_DATAGRAM_CONTEXT: REGISTER_DATAGRAM_CONTEXTをキャンセルします
  • DATAGRAM: QUIC DATAGRAMフレームが使えない場合に、カプセル化してDatagram Payloadを送信します

なお、片方向からREGISTER_DATAGRAM_CONTEXTを送れば、双方向にDATAGRAMフレームが送信できます。

HTTP/3でDATAGRAMフレームを使うときのフォーマット

HTTP/3でQUIC DATAGRAMフレームを使う場合は下記のフォーマットとなります。

f:id:ASnoKaze:20210516003650p:plain

関連付けるストリームは、クライアントが開始した双方向ストリームであるリクエストストリームなので、4で割ってQuarter Stream IDとして記載します。Context IDはCAPSULEフレームで登録したIDを指定します。

なお、REGISTER_DATAGRAM_CONTEXTで登録されていないContext IDを受信したエンドポイントは、バッファしておいたREGISTER_DATAGRAM_CONTEXTが届くのを待つか、単純に破棄します。

仕様には、MASQUEとWebTrasnportの通信例が紹介されています。例えばWebTransportは次のとおりです。

f:id:ASnoKaze:20210516004537p:plain

リクエストストリーム上でREGISTER_DATAGRAM_CONTEXTタイプのCAPSULEフレームを送りContext IDを登録してます。そのご双方向にDATAGAMフレームが送れるようになります。

HTTP/2やHTTP/1.1の場合

HTTP/2やHTTP/1.1でもDatagram Payloadを送れるようにすることを検討しているようです。QUICの接続に失敗するケースで、MASQUEやWebTrasnport個々別にフォールバック先を定義する必要がなくなります。

具体的な方法は今後議論されていくでしょう。