本セッションの登壇者
セッション動画
私からは「HTTPセマンティクスと新しいヘッダなど」ということで、HTTPの上のレイヤの部分の話をしようと思います。セマンティクスというキーワードが不慣れな方もいらっしゃるでしょうが、HTTP/3の話の前座としてなじみやすいところから話を始めていければと思います。そんなに難しい話をするつもりはないので、肩の力を抜いて聞いていただければうれしいです。
本日の内容ですが、議論中の内容を含むということと、HTTPの話がメインで、「ブラウザとかクラウドがそれをサポートするの?」というのはまた別の話と思っていて、こういう話題がディスカッションされていて、皆様がHTTPと接するときに「そういえばこういう機能があったな」と思い出していただければ幸いです。
HTTPセマンティクスとは
さっそくですが、HTTPセマンティクスってなんぞやというやつですね。よく図で出てくるプロトコルスタックの図で、HTTP1.1とか、HTTP/2とか、HTTP/3の上に乗ってるHTTPセマンティクス、まずはこの話をします。
HTTPセマンティクスは今、新しい仕様であるRFC 9110として公開されていますが、わかりやすく言うと「HTTPリクエストのGETとかPOSTの意味」とか、「ヘッダとはこういう意味だよ」とか、「レスポンスステータスコードというのはこういう意味を持ちますよ」という意味を定義したものですね。なので、HTTP1.1ではASCII文字列で送っていたけども、HTTP/2ではバイナリ形式で送るようになり、HTTP/3ではUDP上のフレームというフォーマットで送るようになりましたが、HTTPが持つメッセージはHTTPのバージョンによって変わりません。このように「HTTPセマンティクスに則って送信方法が違うだけで、メッセージの意味は変わりません」というのがHTTPセマンティクスで定義されていることです。下に記載しているのは、HTTP1.1でHTTPメッセージを表現した例ですが、見たことがある人がいれば「ああ、GETリクエストだね」とわかるので、そんな難しいことはないと思います。
RFC 9110で何が変わったかというと、大きくHTTPのメッセージの構造が変わったということはないのですが、一部、今まで問題になってたような細かいエッジケースとか、新しいバージョンが出てくるにあたって整理された部分とかがあります。個人的に気をつけたいと思っているところをいくつか紹介します。
RFC 9110の変更点 - 名称や非推奨を整理
名称の整理についてです。セマンティクス上のHTTPメッセージの構造について名称が整理されています。たとえば「ヘッダ」と皆さんが呼んでいるものは、正しくはフィードです。あと「ボディ」と呼んでいたものはコンテントと呼びます。
HTTP1.1でメッセージのフォーマット上は「ボディ」と呼ぶのですが、それをセマンティクスとして呼ぶときは「HTTPメッセージのコンテント」とか、ヘッダフィールド(変わらず皆さん”ヘッダ”と呼んでいますが…)と、実はHTTP1.1のころからボディを送った後に追加で「ヘッダを送る」という機能があったのですが、「それは”ヘッダ”じゃないよね、”ヘッダ”という呼び方おかしいよね」という議論もあって、トレーラーフィールドと呼ぶように名称が整理されています。でも「フィールド」と呼んでも伝わらないので、ヘッダとかボディとか呼んでしまうことはありますし、僕のスライドでも(伝わらないので)そういう名称を使っていたりもします。なので、HTTP2や3でメッセージを送るときのワイヤ上のメッセージフォーマットを定義していて、それとは別にメッセージのセマンティクスという概念があるということを押さえておくと、この後の話も聞きやすいかと思います。
個人的にRFC 9110で大きく変わったと思っているのは、「418 I’m a tea pot」というJoke RFCがあって、おもしろいからみんなこぞって使っているのですが、HTTP上はunusedという形で定義されるようになりました。Joke RFCで418を使ってるのはあくまでHyper Text Coffee Pot Control Protocolであり、HTTPの番号じゃないということを明らかにするというか、仕様上クリアにするというのがしれっと入ってておもしろいなと思っています。
ここも曖昧性が残ってた部分がクリアになっているところで、GETやHEADなどのContent Bodyが非推奨になりました。実装上どう処理されるか保証されていないので「あんまり使わないでね」という形に決められています。ここは、後で追加のディスカッションがあるので紹介したいと思います。
これもややマニアックなんですが、Rangeを指定したPUTリクエストができるようになりました。Amazon S3などのストレージサービスにアップロードする際に途中で切れても途中からアップロードし直したりとか、クライアント側の処理として一部分、アップロードしたいファイルを分割してRangeでアップロードするケースが世の中にあるらしくて、それを仕様上で許容するというようなディスカッションがあったりしました。
その他、ステータスコードの100番系を「interim responses (non-final response)」、それ以外は「final response」と呼ぶという話や、HTTP/2やHTTP/3のバージョンはマイナー番号を持たないという話もあります。世の中には「HTTP2.0」のように表記されている記事もあって、たしかにそう呼ばれていた時代もありますが、仕様上はマイナーバージョン番号を持たないことになっています。ただしどうしても付けたい場合は、docフォーマット上でドットがあることを前提としているので「.0」を記述するならよい、と許容されています。
QUERYメソッド、再開用トークン、Cookieの改良を検討中
ここからが新しい話で、最近新しい提案書でQUERYメソッドというものが提案されています。先ほど述べたように、GETリクエストにBodyを付けることは非推奨になっていて、実装上も保障されていないので、POSTを使えばいいのですが、冪等(べきとう)的なリクエストをBody付きで送りたいという欲求が世の中にはありがちで、それをどうしようかという話題がIETFでずっと議論されています。
とはいえ、やっぱり既存のセマンティクスを変更するのは相互接続する上で安全性が保証できないので、新しくメソッドを作りましょうということで、QUERYメソッドが提案されました。キャッシュできる、Bodyが付いたリクエストが送れるようになります。これはまだ議論の段階です。
次のテーマとして、アップロード中に切断しても途中から再開できるような仕組みが欲しいという議論がされていて、Resumable Uploads Protocolという仕様が提案されています。アップロード中に再開用トークンを生成して、それを持って再開するとアップロードの途中からやり直すことができるようになりますという仕組みを今、仕様上策定中です。
以下は別のイベントでの発表資料のコピペですが、中身がちょっと難しいので、ここでは説明は割愛します。
あとはCookie関連ですね。これも話がけっこう出ていて、RFC 6265でCookieの仕様が標準化されているのですが、それを改訂しようという作業が進められています。基本的には不明瞭だった点の改修や、推奨事項の追加です。max-ageをこれぐらいに抑えたほうがいいとか、domain属性でドット(.)は禁止というかrejectするようにしましょうとか、長ったらしい属性は文字数上の上限を決めましょう、といったところの追加が挙げられます。
機能面の追加としては、すでにブラウザで実装が進んでるところではあるのですが、Cookie Name Prefixesという、Cookieを共有しているWebサイトから属性を上書きされないようにするために、「__secure-SID」と付けたCookieはsecure属性が付いて、secure属性を無効にできないことを強制します。Cookieの共有範囲を同じサイトに限定するSameSite属性の追加も、わりと使われています。あとは、secure属性を非セキュアなサイトから上書きするのを禁止するというのがあって、たとえば「中間攻撃者がhttp://から始まるサイトを踏ませて、そこからsecure属性を無効にするとCookieが盗聴できる」みたいなケースを潰すためにそのような機能が入っています。あとはここ1年ぐらいの新しいディスカッションとして、CHIPS (Cookies Having Independent Partitioned State specification)というのが最近ITUで新しく提案されていて、1秒で説明すると「トラッキングできないサードパーティCookieの仕組みを作ろう」というGoogleからの提案です。すでにChromeでは実験的な実装が進んでいたりもします。
POSTリクエストエラー処理用とアクセス頻度制御用の新ヘッダ
では、新しいヘッダをいくつか紹介します。まずはIdempotency-Keyヘッダです。背景として、クライアントはPOSTリクエスト中にタイムアウトが発生したときに、サーバで処理される前にタイムアウトしたのか、それともサーバが処理した後にレスポンスを返そうとしたけどタイムアウトしたのかというのを区別できないんですね。なので、それを自動でリトライするか、クライアント実装が自動リトライしていいかというと、けっこう難しいところがあるので、それをわかるようにしましょうということです。たとえば「POSTリクエストを冪等に処理できるようにしましょう」というのがIdempotency-Keyヘッダです。要は、POSTリクエストに一意の識別子を付けて送りましょう、サーバ側はそれを見て、一度処理したリクエストなのか、初めてのリクエストなのかを判断して、副作用がないようにそのPOSTリクエストを処理しましょう…というような仕様の標準化です。PayPalの提案で、PayPal自身、似たような仕組みを持っているようです。
あとは、Rate-Limitヘッダです。これはレスポンスヘッダでアクセス頻度の制限情報を通知する仕組みです。レスポンスのボディに「お前アクセスしすぎるよ」みたいな情報が返ってきたりするんですけど、それをヘッダとしてちゃんと標準化しよう、みたいな仕組みですね。「自分たちのサイトは1分間にこれぐらいアクセスを許容していて、今あなたはこれぐらいリクエストして残りこれぐらいリクエストできます、その制限が解除されるまで何秒間猶予があります」といったヘッダを通知する仕組みを標準化する動きが進んでいます。
ほかにもすでにRFCになっている話がけっこうあって、今日のセッションの内容に近いところだと、RFC 9220の「HTTP/3上でWebSocketを話す」などの標準化が進められていたりします。
では、これで終わります。ありがとうございました。