ブラウザでIPマルチキャストを受信するMulticastReceiver API

2021最新動向について別記事を書きました
asnokaze.hatenablog.com


目次

WICGやIETFにおいて、ブラウザでIPマルチキャストのパケットを受信できるようにする「MulticastReceiver API」(Multicast Receive API) の議論があるようです。

Akamaiの人らによって提案が行われています。その中で「人気コンテンツの大規模配信に対応していく」ことがモチベーションとしてあげられています。

この提案では、いかの事をゴールとしています

  • 1対多のマルチキャストをsubscribeする方法を提供する (送信はスコープ外)
  • 多くのユースケースで使用できるAPIを提供する。
  • トラフィック(パケット)を暗号的に認証する (改変されてないことがわかるようにする)
  • ネットワークの安全性を確保する。大量のトラフィックからネットワークを守る

IPマルチキャスト

ユニキャスト通信では、同じデータがクライアントの数だけルータ上を通ることになります。
f:id:ASnoKaze:20191124200553p:plain

マルチキャストでは、ルータ上でコピーされ必要なクライアント(リスナー)に届けられます。
f:id:ASnoKaze:20191124200635p:plain

各リスナーはSource と Groupを指定してsubscribeします。

MulticastReceiver API

MulticastReceiver Explainer」に例があります。
JavaScriptからsource、group、portを指定してsubscribeします。メタデータを提供するdormsサーバ(後述)を指定します。うけとったパケットはprocessPacketsで処理を行えます。

var mrc = new MulticastReceiverConfig();
mrc.source = '198.51.100.10';
mrc.group = '232.10.10.1';
mrc.port = 5001;
mrc.dorms = 'dorms.example.com';

var mr = new MulticastReceiver(mrc);
// process any packets received
mr.onmessage = function(evt) { processPackets(evt.data); }

// monitor other events, but do nothing with them.
mr.onjoin = function(evt) { console.log('multicast receiver joined'); }
mr.onleave = function(evt) { console.log('multicast receiver left'); }
(略)

mr.join();

プロトコル

Multicast to the Browserを実現するためのプロトコルIETFのMulticast Backbone Deployment (mboned) WGで議論されています。mboned WGは、グローバルインターネット、ドメイン間でマルチキャストルーティングプロトコルと、そのデプロイ、運用について議論をしているWGになります。

現在、ブラウザへのIPマルチキャストに関して、AkamaiのJake Holland氏らによって下記の3つの文書が提案されています。 これら3つを組み合わせてブラウザへの配信を実現させます。

DORMSはsource-specific multicast (SSM)に関する拡張可能なメタデータをディスカバリ・取得する方法を定義します。
AMBIはブラウザが受信したデータの整合性を検証し、パケットロスを監視する方法を定義します。
CBACCはブラウザがネットワークキャパシティ上限を超えないようにする方法を定義します。

ブラウザがゲートキーパーになる場合は図のようになります (経路上の装置がゲートキーパーになる場合もある(資料参照))
f:id:ASnoKaze:20191124204622p:plain
(IETF106 Mbonedの資料より(URL))

雑感

資料ではマルチキャストQUICにも触れているが、上位プロトコルに関しては今の所具体的なところは書かれていない (実験できるようにするのが大事とのこと)。
asnokaze.hatenablog.com

IPマルチキャスト難しい。

HTTP/3と新しいプライオリティ制御方式について

目次

関連記事

HTTP/3については以前書いたとおりです
asnokaze.hatenablog.com

追記 (2019/11/21)

https://tools.ietf.org/html/draft-kazuho-httpbis-priority-04」draft-04で、以下のようにurgencyとincremental頭文字で表現されるようになりました

   priority = u=4, i=?1

SETTINGSパラメータもSETTINGS_DEPRECATE_HTTP2_PRIORITIESを使うように変更されました

背景

HTTP/2から複数のHTTPリクエストが一つのコネクション上で並列的に送信されるようになりました。それにともない、クライアント側からリクエストの優先度(プライオリティ)をサーバに通知する仕組みが導入されました。

Webページをレンダリングを開始するのに必要なリソース(HTML, CSSなど)の優先度を高く設定したりできます。

現在標準化が進められているHTTP/3でも、最初はHTTP/2と同様、リクエストの依存関係(dependency)と重さ(weight)で優先度を管理する方式(ツリー方式)が検討されていました。

しかし、議論が進むに連れこのツリー方式の優先度制御は複雑であり、あまり実装されていないことがわかりました。(Interimの資料)

HTTP/3では新しい優先度制御方式も議論されましたが、一旦HTTP/3の仕様からは優先度制御の仕組みは外され、優先度制御はオプショナルな機能とする方向となりました。

実際、HTTP/3の仕様からはすでに優先度制御の機能は削除されています。
github.com

またHTTP/2でも優先度制御を行わないで、拡張仕様の優先度制御方式をネゴシエーションする仕組みを検討することになりました。

優先度制御の仕様は、別途デザインチームを結成しそこで議論されることになりました。

ここらへんの議論は、kazuhoさんの記事に書かれているとおりです。
blog.kazuhooku.com

プライオリティの仕様の方向性

HTTP WGのメーリングリストに投げられている通り(URL)、先日行われたQUIC WGの中間会議においてデザインチームのリーダであるIan Sweet氏より、Fastlyのkazuhoさんが提案している「Extensible Prioritization Scheme for HTTP」をベースとして進めていくことがアナウンスされています。

Extensible Prioritization Scheme for HTTP

この仕様では、プロトコルバージョンに依存しない、リクエストここ別に絶対値で示される優先度をもつエンドツーエンドの優先度制御方式を定義しています。

具体的には以下のものが定義されています

  • Priorityヘッダ(リクエスト・レスポンスで使用される)
  • 優先度。urgency (優先度の絶対値)、プログレッシブ
  • ネゴシエーションの仕組み
  • 優先度を更新するフレーム(HTTP/2, HTTP/3の拡張フレーム)
Priorityヘッダ

priorityは下記のような形式です。フォーマットは「Structured Headers」で定義されたDictionary形式です。

   priority = urgency=3, progressive=?1

このヘッダを用いてクライアントはこのHTTPリクエストの優先度をサーバに通知します。

一方で、サーバはレスポンスヘッダにpriorityを指定することで、そのレスポンスがどれくらいの優先度で返されていることを示せます。これによって特に、そのHTTPリクエスト・レスポンスを扱っているProxyに対して、優先度を知らせることができます。

urgency と progressive

priorityヘッダは、urgencyとprogressiveというパラメータを持ちます。

urgencyは-1から6までの値をとります。値が小さいほど優先度が高いです。サーバは優先度が高いものから送信していきます。

  • prerequisite (-1)
  • default (0)
  • supplementary (1~5)
  • background (6)

それぞれ意味次のとおりです。

prerequisite: urgencyがdefaultやprerequisiteのレスポンスを止めます。ブラウザのレンダリングをブロックするようなCSSのリクエストなどに使用されます。

default: 他のリクエストをブロックしません。例えば新しいページに遷移したときにしようされます。

supplementary: この複数要求されたリソースの名から、必須ではないりそーすにつけられます。1~5の値によって優先度がしめされます(クライアントはサーバが上書きして使えるように1,5は使うべきではありません)

background: 他のリクエストに影響が出ないように後回しにできるリクエストに使用される。

ネゴシエーションの仕組み

HTTP/2およびHTTP/2で使用する優先度制御方式をネゴシエーションする方法もこの仕様で定義されています。

SETTINGS_PRIORITIESパラメータを用いてネゴシエーションします。値は次のとおりです

  • 1. H2_TREE: HTTP/2の優先度ツリー方式 (HTTP/3では使用できない)
  • 2. URGENCY: この仕様

また、urgencyとは別にprogressiveを指定できます。progressiveはそのリソースが逐次処理可能なリソースか示します(例えばprogressive jpegなど)。progressiveブーリアンであり0か1をとり、同じurgencyでprogressiveなレスポンスがあった場合は帯域を等分して使います。

優先度の更新

通信中に優先度を更新する場合もあります(例えば、ブラウザのタブを切り替えたり)。そのときに使用する拡張フレームも定義されています。

HTTP/2とHTTP/3両方にPRIORITY_UPDATEフレームを新しく定義しますが、それぞれフォーマットは異なります。HTTP/2ではストリームIDを指定します。HTTP/3ではストリームIDもしくはプッシュIDをしてします。新しい優先度はASCIIでヘッダと同じように指定します。

H2の場合
f:id:ASnoKaze:20191107015351p:plain

H3の場合
f:id:ASnoKaze:20191107015417p:plain

キャッシュ情報を示す、Cache-Status レスポンスヘッダ

リクエストに対してx-cacheレスポンスヘッダでキャッシュにhitしたか示すCDNベンダーもあります。

しかし、このx-cacheヘッダは各ベンダー独自のもので標準化されていませんでした。

そこでCache-Statusというヘッダをちゃんと定義する「The Cache-Status HTTP Response Header」という仕様がFastlyのMark Nottingham氏から出ています。

以前まではcacheヘッダという名前でしたが、draft 01ではCache-Statusヘッダと改称されました。それにあわせてヘッダ値もリファクタされています。

前の仕様は以前書いた通りです。
asnokaze.hatenablog.com

Cache-Statusヘッダ

Cache-Statusは以下のようになります。「Structured Headers for HTTP」の定義に従ってリスト構造を持ちます。

Cache-Status: ExampleCache; fwd=res-stale; fwd-res=notmod

まず、このCache-Statusヘッダをつけたサーバの識別子(CDN名)が付きます。そのあとに、キャッシュに関する情報がつきます。(複数CDNを経由する場合は、そのつど追記されていきます。)

続くパラメータは以下の通りです。

fwd パラメータ

fwdパラメータは、リクエストがフォワードされた理由を示します。

  • none: リクエストはフォワードされてません (キャッシュにhitし、それが使用されました)
  • bypass: リクエストなんの処理もしないように設定されています
  • uri-miss: リクエストのURIにマッチするキャッシュがありません
  • vary-miss: リクエストのURIにマッチしましたが、ヘッダに基づいてマッチするキャッシュがありませんでした
  • miss: キャッシュにhitしませんでした (uri-missとvary-missを区別なく使用できる)
  • res-stale: キャッシュにマッチするものがありましたが、すでに有効ではなくなっていました
  • req-stale: キャッシュはありましたが、リクエストのCache-Controlリクエストディレクティブに基づいて、使用できませんでした
fwd-res

fwd-resパラメータは、リクエストを転送して受け取ったレスポンスの結果を示します。

  • full: 完全なレスポンス (304, 206以外)
  • partial: 206 Partial Response
  • notmod: 304 Not Modified
fwd-stored

fwd-storedパラメータは、リクエストをフォワードした際にそのレスポンスを保存したかを示します。

res-fresh

res-freshパラメータはレスポンスの残りのFreshness(有効時間)を秒で示します。

Cache-Status: ExampleCache; res-fresh=376
cache-fresh

cache-freshパラメータは、持ってたキャッシュを返した際に、その残りのFreshness(有効時間)を秒で示します。

collapse-hit

キャッシュサーバが同じHTTPリクエストを同時に複数受信した場合は、そのうち1つだけを転送し、受け取ったレスポンスを複数リクエストに対して返す実装もあります。

collapse-hitは、ほかのHTTPリクエストと束ねられたかをしめします。

collapse-wait

collapse-waitパラメータは、ほかのHTTPリクエストに束ねられた場合の待ち時間をミリ秒で示します

Cache-Status: ExampleCache; fwd=uri-miss;
              collapse-hit=?0; collapse-wait=240

複数のCDNを利用する場合

先述の通り、複数のCDNを通る場合はそのつど追記されます。

Cache-Status: "CDN Company Here"; res-fresh=545,
              OriginCache; cache-fresh=1100; collapse-hit=?1

「Binary Structured HTTP Headers」について

Fastlyの「Binary Structured HTTP Headers」という提案仕様がでています。

目次

概要

HTTPヘッダはテキストで表現されます。特に値に関して数値、日付やブーリアン値もテキストで表現されます。また、Accept-Encodingのようにリスト構造を持つヘッダ値もあります。

本来バイナリで表現できるデータ形式や構造をテキストで表現するのは、データ量が増えるほかパースコストがかかります。

そこで、Structured Headersの定義に基づいて、HTTPヘッダ値を直接バイナリで表現できるようにするのが「Binary Structured HTTP Headers」です。この仕様では、バイナリのヘッダを送るBINHEADERSフレームと、HPACKに追加でBinary Literal Representationを定義します。

エンドポイントがこの仕様に対応していることを示すSETTINGS_BINARY_STRUCTURED_HEADERSパラメータも定義されます。

Structured Headersについては以前書いたとおり(少々内容は古くなっており、データ型の種類が異なっています)
asnokaze.hatenablog.com

BINHEADERSフレーム

BINHEADERSフレームは、次の一点を除きHEADERSフレームと同じフィールドを持ちます。HEADERSフレームとの違いは、ヘッダ圧縮(HPACK)でテキストを表現するのに使用されるString Literal Representationの代わりにBinary Literal Representationを使用することです。

ただし、Binary Literal Representationはヘッダ値でのみ使用されます。

Binary Literal Representation

Binary Literal Representationはデータ構造が示す部分と、値のデータ型を示す部分からなります。まずは、データ構造を示す部分から説明してきます。(ヘッダ構造を示すtypeと、データ型を示すtypeはそれぞれ別の種類であることに注意してください)

Binary Literal Representationは以下のフィールドを持ちます
f:id:ASnoKaze:20191102224210p:plain

ヘッダの構造を表す4つのTypeがあります

  • Lists (type=0x1)
  • Dictionaries (type=0x2)
  • Items (type=0x3)
  • String Literals (type=0x4)

(Inner Lists, Parametersは説明を省略)

Lists

Listsとは下記のような ’,’ で区切られているようなヘッダ値です。Binary Literal RepresentationではInner ListsやItemを複数書くことで表現されます。

Example-StrListHeader: "foo", "bar", "It was the best of times."
Dictionaries

Dictionariesとは下記のような、key=valueの構造を複数持つヘッダ値です。

   Example-DictHeader: en="Applepie", da=*w4ZibGV0w6ZydGU=*

Binary Literal Representationでは下記のように、Keyの長さ、Keyの文字列、値(Binary Structure Types)からなります。
f:id:ASnoKaze:20191102225721p:plain

Items

整数、実数、base64値、ブーリアンなどを示す単体の値です。それぞれごとにdata typeを持つので、それを見ることでどのデータ型なのか識別できます。

f:id:ASnoKaze:20191102230315p:plain

String Literals

これはバイナリではなく、単純な文字列表現です。バイナリ表現が使用できない場合に使用されます。HPACKで定義されるString Literal Representationsと同じものです。

Item Payload Types

具体的なItemのバイナリ表現方法です。

Itemには下記の種類があります。それぞれごとにバイナリフォーマットが定義されています。

  • Integers (type=0x3)
  • Floats (type=0x4)
  • Strings (type=0x5)
  • Tokens (type=0x6)
  • Byte Sequences (type=0x7)
  • Booleans (type=0x8)

(説明を省略したInner Lists, Parametersがそれぞれtype=1, 2です)

例えばInteger(整数)は下記のバイナリフォーマとを持ちます。
Sは正負、Xはパディング、その後に長さと値が入ります。
f:id:ASnoKaze:20191102232742p:plain

Booleansであれば以下のように短く表現できます。
f:id:ASnoKaze:20191102231737p:plain

Aliased Fields

この仕様ではいくつかのヘッダにおいて、Binary Structured HTTP Headersを使えるようにエイリアスというものを定義しています。

Dataヘッダは以下のとおりです。そのままではBinary表現は使用できません

Date: Sun, 06 Nov 1994 08:49:37 GMT

DataヘッダのエイリアスであるSH-Dateでは、Unixタイムを使用して以下のようにIntegerのバイナリ表現を使用できます。

SH-Date: 784072177

どのようなエイリアスが定義されているかは仕様を御覧ください。

NginxでHTTP/3が動いた (Cloudflareパッチ)

2020/060/01 追記
nginx公式版が提供されました。こちらを御覧ください
asnokaze.hatenablog.com


NginxをHTTP/3対応させるパッチがCloudflareから提供されました (CloudflareのHTTP/3ライブラリ Quicheを利用しています。現状ではHTTP/3ドラフト23版の対応になります)
github.com

基本的に、書いてるとおりにやればビルドできるのですが、無事HTTP/3しゃべるところまで確認できました

ビルド

rustインストールしておく

$ curl https://sh.rustup.rs -sSf | sh
$ source $HOME/.cargo/env

書いてあるとおり

$ curl -O https://nginx.org/download/nginx-1.16.1.tar.gz
$ tar xzvf nginx-1.16.1.tar.gz

$ git clone --recursive https://github.com/cloudflare/quiche

$ cd nginx-1.16.1
$ patch -p01 < ../quiche/extras/nginx/nginx-1.16.patch

$ ./configure                              \ # ./configureで実行した
       --prefix=$PWD                           \
       --with-http_ssl_module                  \
       --with-http_v2_module                   \
       --with-http_v3_module                   \
       --with-openssl=../quiche/deps/boringssl \
       --with-quiche=../quiche
$ make

nginx.conf の編集

nginx-1.16.1$ vim ./conf/nginx.conf  #下記を追記

    server {
        listen       4433 quic;
        server_name  localhost;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;

        ssl_certificate      /path/to/server.crt;
        ssl_certificate_key  /path/to/server.key;

        location / {
            root   html;
            index  index.html index.htm;
        }
    }

起動

nginx-1.16.1$ sudo ./objs/nginx 

接続してみる

quicheのサンプルクライアントで接続する (draft-23バージョンでネゴシエーションします)

quiche$ cargo build --examples
quiche$ target/debug/examples/http3-client https://127.0.0.1:4433/index.html --no-verify   |head -n3
<!DOCTYPE html>
<html>
<head>

ちゃんとHTTP/3でアクセスログにも着てる

nginx-1.16.1$ tail ./logs/access.log 
127.0.0.1 - - [16/Oct/2019:18:21:43 +0900] "GET /index.html HTTP/3" 200 612 "-" "quiche"
127.0.0.1 - - [16/Oct/2019:18:21:45 +0900] "GET /index.html HTTP/3" 200 612 "-" "quiche"
127.0.0.1 - - [16/Oct/2019:18:22:19 +0900] "GET /index.html HTTP/3" 200 612 "-" "quiche"

パケットキャプチャもこの通り
f:id:ASnoKaze:20191016190623p:plain

WebTransport over QUIC について

2020/03/11 追記
関連記事を書きました


目次

blink-devメーリングリストで、「Intent to Implement: QuicTransport」として、ChromeでのWebTransport over QUICの実装の機運が高まっている。

というか、GoogleのQUIC, HTTP/3実装ライブラリであるQUICHEにはすでにQuicTransportに関するコードが既にコミットされ始めている(URL)

WebTransportは、トランスポートプロトコルとしてHTTP/3やQUICを利用する双方向のメッセージプロトコルです。APIに関してはW3C側で、プロトコルとしてはIETFで議論が始まっています。仕様は以下の通り

来月行われるIETF106では、WebTransport WGを結成するためのBoFが提案されている。そのなかでも「Chromium is currently implementing a client Google QUIC library will support both client and server」と、クライアント・サーバともに実装している旨が書かれている。

仕様としては使用できるトランスポーはいくつかあるが、まずはover QUICから取り掛かるようだ

WebTransport over QUIC

一部本記事と重複するが、WebTransportの概要については下記の記事を参照
asnokaze.hatenablog.com

Googleさんが、WebTransport over QUICをまず進めていくようなので、WebTransport over QUICについて簡単に書く。なお、draftは著者様のgithub上ではすでに加筆されており、次のdraft-01で入る予定の機能についても触れる。

WebTransport over QUICは、WebTransportの特性のうち下記をサポート

  • Stream independence: Always supported
  • Partial reliability: Always supported
  • Pooling support: Not supported
  • Connection mobility: Implementation-dependent

また、QuicTransportでの0-RTTサポートは、QUICおよびTLS 1.3と同様にオプションです。

Stream independence

QUICレイヤのストリーム(単方向・双方向)を利用して、ヘッドオブラインブロッキングのない通信(パケットロスが発生しても他のストリームをブロックしない)となる。TCPとは異なり、アプリケーションはOSレイヤでのロスしたパケットの回復を待つことはなく、パケットから処理が可能となる。

Partial reliability

また、DATAGRAMフレームを利用し、パケットロスしたデータを回復しないことも選択できる。
asnokaze.hatenablog.com

Pooling support

WebTransport over QUICでは一つのQUICコネクションを利用してしまうので、同じ相手と通信していてもQUICコネクションを一つに束ねることはできない。その観点では、輻輳制御コントローラを共有するWebTransport over HTTP/3の方がメリットがあります。

Connection mobility

QUICはコネクションマイグレーションという機能がありますが、実装依存です。

asnokaze.hatenablog.com

URI Scheme

WebTransport over QUICでは、quic-transport用のURIが新しく定義されています。

通常のURL同様以下のような構造を持ちます。

quic-transport://host:port/path

クライアントは上記のURLに対して接続を開始します。host名はSNIとして送信され、pathは後述のClient Indicationを用いてサーバに伝えられます。

接続の開始

WebTransport over QUICでは、draft-00ではALPNとして"wq"を使っていましたが、draft-01からは、individual draft版を示す "wq-vvv-01"を使用します。クロスプロトコル攻撃もなくなります。

サーバからのTLS Finishedのメッセージが受信されると、WebTransport over QUICのコネクションが確立されます。

Client Indication

draft-01からClient Indicationという仕組みが導入される予定です。

これは、下記Issueでも述べられている通りに、どのWebページ(オリジン)によって開始されたWebTransport over QUICなのか識別できるようにするためのものです。
github.com

https://example.comからwq.example.com:4433に対して接続を開始した場合、接続を開始したオリジンとしてhttps://example.com:443がWebTransport over QUICサーバに通知されます。こすることで第三者のWebページにWebTransport over QUICサーバを勝手に利用されるということはなくなります。

Client Indication自体は、クライアントからサーバに対してメタ的な情報を通知する汎用的な仕組みです。クライアントは、コネクションが確立した直後に、ストリームID:2 (単方向ストリーム)で接続を開始したオリジンを通知するClient Indicationメッセージを投げます。サーバはこのメッセージが来るまで待ち状態となります(正確にはストリームID:2がクローズするまで待ち状態)。

Client Indicationメッセージは下記のフォーマットになります。可変長Valueを持つ、Key-Value型のメッセージ形式です。
f:id:ASnoKaze:20191010013538p:plain

このうち、Keyとして0x0000を持つのがOrigin通知用のClient Indicationで、valueとしてオリジンが入ります。Keyが0x0001のものはPathを送信するのに使用されます。

対応していないKey番号を持つClient Indicationは無視されます。

データのやり取り

コネクションが確立され、Client Indicationが完了したあと、各ストリーム上でクライアントとサーバでやりとりが開始されます。

Fallback

余談ですが、WebTransport over QUICのプロトコル自体にはコネクションの確立に失敗しても、WebTransport over TCPへのフォールバックの機能はありません。WebTransportのフレームワークが、WebSocketベースのポリフィルが提供されるらしいので、アプリケーションがそちらに切り替えを行う形になるのかとおもいます。

ChromeのHTTP/3(ドラフト版)対応

追記(2019/12/24)
最新版ですと、h3-23ではなくh3-24が必要ですー

「The latest Chrome Canary supports h3-24 instead of h3-23」
https://groups.google.com/a/chromium.org/forum/#!topic/proto-quic/trZsbXM_2CM


Chrome CanaryがHTTP/3のドラフト版に対応していたので、簡単に見てみる
(登場するバージョンについての説明は、後述する。)

動作確認

デフォルトでは喋ってくれない。chrome canaryの起動オプションに下記を追加する。

--enable-quic --quic-version=h3-23

(起動コマンドがわからない場合は、chrome://version/ を開くと確認できる)

HTTP/3 draft-23に対応しているページを開きます。
https:///quic.aiortc.org:4433

ページは正しく表示され、デベロッパーツール上はhttp/2+quic/99と表示されますが、HTTP/3 draft-23で通信は行われています。
f:id:ASnoKaze:20190921230316p:plain

Wireshark で、QUICトランスポートのバージョンを見てみるとちゃんとIETF QUICのバージョンを示す 0xFF00000017 (draft-23) で通信していることを確認できます。
f:id:ASnoKaze:20190921230528p:plain

バージョンについては、順に説明していく。

gQUIC, iQUICのバージョン

もともと、"QUIC"はGoogleが考案・実装していたプロトコルですが、標準化するに当たりIETFに持ち込まれました。そして、IETFではQUICはトランスポートプロトコルとして設計され、その上にHTTP/3がのっかる形となりました。(Google QUICはHTTPレイヤも含むプロトコルでした)

この過程で、もともとのGoogle QUICとIETF QUICは別物となり、それぞれ互換性の無いプロトコルとなりました。Google版のQUICをgQUIC, IETF版のQUICをiQUICと呼び分けることもあります。

もちろん、HTTP/3ではiQUICを前提にしているため、HTTP/3に対応するためにはiQUICに対応する必要があります。

Chromeでは標準仕様であるiQUICへの移行を段階的に進めており、HTTP/3 draft-23 が実験的に喋れる状況となっています。

識別子とalt-svc

iQUIC

HTTP/3では、サーバがHTTP/3に対応している旨、alt-svcレスポンスヘッダを用いて通知します。

下記例では、HTTP/3の仕様 draft-23バージョンを 4433ポートで提供していることを示しています。このレスポンスヘッダを受け取ったクライアントは、自身がそのバージョンに対応していれば、そこに繋がきに行きます。

alt-svc: h3-23=":4433"; ma=3600

IETF版、QUICではHTTP/3の識別子として、 h3- という形で通知を行います。もし、RFCとして正式なものが公開されれば、はなくなり、h3という識別子を用いることになります。
(ここでは、HTTP/3のバージョンにのみ言及しており、トランスポートとしてのQUICについては別途コネクション時にネゴシエーションされる点に注意。QUICトランスポートのハンドシェイクでは draft版は 0xff0000 を使用します。)

gQUIC

gQUICでも同様にalt-svcを使用しますが、バージョン体系が異なっています

Googleのサーバは下記のようなalt-svcを返します。gQUICは、HTTPレイヤも含むプロトコルですので識別子としてquicを使用しています。vという値を用いて、対応バージョンとして、46,43,39に対応していることを示しています。

alt-svc: quic=":443"; ma=2592000; v="46,43,39"

識別子も、バージョン体系もiQUICとgQUICは異なっています。

先述の通り、gQUICはiQUICへの移行を目指しております。GoogleのQUICライブラリに、その様子が伺えます
https://quiche.googlesource.com/quiche/+/refs/heads/master/quic/core/quic_versions.h

  QUIC_VERSION_46 = 46,  // Use IETF draft-17 header format with demultiplexing bit.
  QUIC_VERSION_47 = 47,  // Allow variable-length QUIC connection IDs.
  QUIC_VERSION_48 = 48,  // Use CRYPTO frames for the handshake.
  QUIC_VERSION_99 = 99,  // Dumping ground for IETF QUIC changes which are not yet ready for production.

gQUICでも暗号経路を確立するために暗号ハンドシェイクを行いますが、iQUICと同様のTLS1.3を用いたハンドシェイクの場合は、iQUICのバージョン同様 0xff0000を使うことがわかります(そうでない場合は、QUIC 99となる。)
https://quiche.googlesource.com/quiche.git/+/c8d9e40cd42e73b643e36300c807865b2ec8787d/quic/core/quic_versions.cc#115

    case QUIC_VERSION_99:
      if (parsed_version.handshake_protocol == PROTOCOL_TLS1_3) {
        return MakeVersionLabel(0xff, 0x00, 0x00, kQuicIetfDraftVersion);
      }
      return MakeVersionLabel(proto, '0', '9', '9');

ということで、実装的にはIETF QUIC版も対応していそうということがわかります。