ブログ・ア・ラ・クレーム

技術的なメモとかライフログとか。

HTTP Alternative Services について

本稿は HTTP2 Advent Calendar 2014 20 日目の記事です。 本稿では HTTP/2 周辺のトピックでもやや地味な部類に入るであろう、 HTTP Alternative Services について簡単に触れていきます。

  • 2014-12-21 19:20 用語の修正

概要

HTTP Alternative Services とは、 HTTP で配信するリソースを他のプロトコル、ホスト、ポート番号でもサービス提供ができることを通知する仕組みです。 用途としては下記のようなものが想定されます。

  • メンテナンス等のためサーバをダウンさせる前に、他のサービス可能なサーバを提示する
  • 新しいプロトコルへの切り替えを提案する(HTTP/1.1 から HTTP/2 へ、など)
  • 日和見暗号(サーバ認証を行わず http スキームで暗号化通信する仕組み) の使用を提案する
  • SNI などをサポートするクライアントとそうでないクライアントを分離する
  • 他ホストにリクエストを振り分けて負荷分散する

HTTP Alternative Services は HTTP/2 とは分離された Internet-Draft になっており、 2014年12月現在、 5番目のドラフトが出ている 状態です。

HTTP Alternative Services メッセージの表現方法

HTTP Alternative Services ではサーバからクライアントへ代替が存在する旨のメッセージを通知することで使用することができます。 このメッセージでは最初にリクエストを受け取った OriginRFC6454 にあるようにスキーム、ホスト、ポートの組で識別する)を代替する Alternative service を通知するような内容になります。

例えば Origin が下記の通りだったとして、

 ("http", "www.example.com", "80")

Origin が下記のようなメッセージを送ることで、「new.example.com:81 に HTTP/2 で話すことで Origin と同様のリソースを受け取ることができる」ことを通知できます。

("h2", "new.example.com", "81")

このメッセージの表現方法について、現行のHTTP Alternative Services のドラフトでは下記2つの方法が提示されています。

  • Alt-Svc HTTP ヘッダフィールド を使用する
  • HTTP/2 において ALTSVC フレーム という拡張フレームを使用する

Alt-Svc HTTP ヘッダフィールド

Origin は、下記のようなフォーマットの Alt-Svc ヘッダを送ることで Alternative service の存在をクライアントに通知することができます。 ここでプロトコル名として提示するのは、 ALPNプロトコル識別子と同様のものになります。

Alt-Svc: h2="new.example.org:80"

Alt-Svc ヘッダの内容はキャッシュされます。デフォルトでは 24 時間後にフレッシュされますが、 Alt-Svc ヘッダの ma(max-age) パラメータによってキャッシュが失効されるまでの時間を指定することもできます。

# 1時間後に失効
Alt-Svc: h2=":443"; ma=3600

なお、クライアントは Alt-Svc を使って Alternative service にリクエストを投げる際は Alt-Used HTTP ヘッダフィールド を付加する必要があります。(MUST) これは Alternative service 切り替えのループが発生することを防ぐことと、サーバ側で負荷分散する際に Alt-Svc が使われたリクエストなのかどうかを識別することが目的です。

Alt-Svc を使って振られた Alternative service はリクエストをうまく捌けない際に 421 Misdirected Request HTTP ステータスコード を返します。 クライアントは 421 を受け取った際には Alt-Svc キャッシュから該当エントリを消す必要があります。(MUST)

ALTSVC フレーム

HTTP/2 で Alternative Services を使用する場合は、 ALTSVC フレームで Alt-Svc ヘッダと同内容のメッセージを表現します。 ALTSVC フレームは Optional なフレームタイプであり、 最新の HTTP/2 のドラフト では定義されておらず、これをサポートしていないクライアントはサーバから送られてきた ALTSVCフレームを無視しても問題ありません。 (ちなみに draft-11 から draft-13 の間は ALTSVC フレームタイプが HTTP/2 のドラフト内で定義されていたりしました)

HTTP Alternative Services の活用例

http スキームで暗号通信を行う 日和見暗号 でも HTTP Alternative Services を使用します。 Origin は日和見暗号が利用可能であればレスポンスに HTTP-TLS ヘッダを付与します。 クライアントはこれを ":443" の Alternative service として記憶することで、次回以降にユーザが http スキームでリクエストを投げる際に HTTP over TLS で通信可能な Alternative service を選択することができます。

f:id:syu_cream:20141220153046p:plain

HTTP/2 通信開始前は基本的に ALPN や HTTP Upgrade でクライアントとサーバの間でお互いに HTTP/2 を解釈可能だということを確認します。 HTTP Alternative Services を使って事前に HTTP/2 で通信可能な alternative services がいることを知っていれば、このようなプロトコルネゴシエーションをスキップして直ぐに HTTP/2 通信を開始することもできます。

f:id:syu_cream:20141220153103p:plain

  • 負荷分散する

alternative service として別ホストを指定することもできるため、 Origin が高負荷な場合は HTTP Alternative Services を使って別ホストにリクエストを振ることで負荷分散することも可能です。

f:id:syu_cream:20141220153112p:plain

これは個人の意見ですが、 HTTP Alternative Services を使って負荷分散するのは難しいのではと思っています。 まず Origin は Alternative services の負荷状況を把握しておく必要があると考えられます。でないと誤って高負荷な Alternative services にリクエストを振り続けてしまう可能性があります。 更に HTTP Alternative Services は Optional な機能のため、これで負荷をどの程度分散できるかはどの程度ブラウザが対応してくれるかに大きく依存します。

HTTP Alternative Services 周辺事情のこれまで

HTTP Alternative Services 周辺のこれまでのおおまかな流れをまとめてみました。

  • Alternate-Protocol ヘッダフィールド

Alternative Services の前身となるのは、 SPDYの仕様に含まれる Alternate-Protocol ヘッダフィールド であると思われます。 Alternate-Protocol ヘッダは、リクエストが指定ポートで他のプロトコルでも捌けることを通知するためのヘッダです。

  • Encryption for HTTP URIs Using Alternate Services

こちらの文書日和見暗号を実現するのに、 Alt-Svc ヘッダを使う提案がされています。

  • HTTP Alternate Services

こちらの文書 で、 Alternative Services が日和見暗号から分離されています。

  • HTTP/2 ALTSVC フレーム

http2 draft-11 で、 HTTP/2 で Alternative Services を使用するためのフレームタイプが定義されました。 しかしながら http2 draft-13 でこれは除去され、 HTTP Alternative Services draft-02 に分離されました。

GitHub の issues で議論された内容を元に、 HTTP Alternative Services draft-05 まで更新されています。

おわりに

HTTP Alternative Services の理解があまりなかったため、今回仕様と経緯を調査しまとめてみました。補足や誤り指摘等大歓迎です。何かありましたらコメント欄にでも書いて頂ければ幸いです。

ちなみに今回 HTTP Alternative Services に対応している実装が存在するのか気になって少々調べてみたのですが、少なくともコードベースでは Chromium, FireFox, nghttp2 には対応する実装がありそうでした。 どこまで機能するのかは未調査です。後ほど余裕があった際にでも調べます。

余談ですが, 現在の仕様では "HTTP2.0" ではなく "HTTP/2" もしくは "HTTP2" が正しい名称です.