読者です 読者をやめる 読者になる 読者になる

HTTP/2 Connection Prefaceの理由と経緯

HTTP/2 Connection Prefaceとは

HTTP/2では通信の最初に「コネクションプリフェイス(Connection Preface)」というメッセージを送信します。
クライアント側は「クライアントコネクションプリフェイス」と呼ばれる以下のメッセージを送信します。

0x505249202a20485454502f322e300d0a0d0a534d0d0a0d0a
(文字列表現: "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n")

理由

なぜこの文字列なのか一見して分かりづらいですが、理由としてはHTTP/2クライアントが間違えてHTTP/1.1サーバと接続しようとした際に素早く切断されるようにするためである。HTTP/1.1では改行文字(\r\n)を終端文字としているため、それを待ち続けてしまうサーバ実装があったとしてもこのメッセージを送信することで(無効なリクエストとして)素早く切断される。


ここで改めてHTTPリクエストのリクエストラインのフォーマットを確認しておきましょう。
(http://tools.ietf.org/html/rfc7230#section-3.1.1)

  request-line   = method SP request-target SP HTTP-version CRLF
  method         = token
  HTTP-version  = HTTP-name "/" DIGIT "." DIGIT
  HTTP-name     = %x48.54.54.50 ; "HTTP", case-sensitive

このフォーマットを見ると、コネクションプリフェイスの「PRI * HTTP/2.0\r\n」部分は実はHTTP/1.1での定義として正しくパース出来る事が確認できます。("."を想定している実装もあるため、2.0になってるものと思います)


変遷・経緯

理由には概ね納得できますが、やはりこの文字列になる経緯などが気になります。
当初のhttp2 draft-01には、まだコネクションプリフェイスは登場しません。


(2013年のhttpbis interim 東京での議論でMagicの話が出て(議事録)、このコミットにてMagicという単語が出現しています)


メーリングリストで議論が始まったのが、2013年2月ゴロの「HTTP/2.0 Magic」が始まりです。


この議論の中で幾つかの文字列が提案されていますが、HTTPbis WGのChairであるMark Nottingham氏による統計データが示されました(Re: HTTP/2.0 Magic)


調査によると、760,000のWebサーバに提案された文字列を送信しコネクションがCloseする割合が確認されました。

文字列 Close Conn_Err Timeout
「FOO\n\n」 641481 85855 35148
「FOO\r\n\r\n」 1602 303 33243
「FOO * HTTP/2.0\r\n\r\n」 30082 396 4670
「FOO * HTTP/2.0\r\nConnection: close\r\n\r\n」 30310 337 4501
「FOO * HTTP/2.0\r\nContent-Length: 0\r\n\r\n」 30072 369 4707
「FOO * HTTP/2.0\r\n\r\nBAR * HTTP/2.0\r\n\r\n」 31212 306 3630
「FOO * HTTP/2.0\n\nBAR * HTTP/2.0\n\n」 27101 312 7735
「FOO * HTTP/2.0\r\n\r\nBAR\r\n\r\n」 31132 427 3589
「FOO\r\n\r\nBAR\r\n\r\n」 1042 86 11766
「\xff * HTTP/2.0\r\n\r\n\xff\r\n\r\n」 30271 342 4535
「FOO * HTTP/2.0\r\n\r\nBAR\r\n\r\n」 31132 427 3589


(当初は0x535044590d0a0d0aだった模様)
この調査を受けて、HTTP2 draft02で"Session Header"として「"FOO * HTTP/2.0\r\n\r\nBAR\r\n\r\n"」を送るという部分が追加されている。


その後draft03でSessionという単語をConnectionに統一したため、"Connection HEADER"になり「"FOO * HTTP/2.0\r\n\r\nBA\r\n\r\n"」と、1byte減り24byteとして定義されました。(https://github.com/http2/http2-spec/issues/101)


さらにdraft04で、現在の形である「"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"」となる。変更コミットを見てみると「Exercising editorial discretion regarding magic」


draft11にてようやく名称が「クライアントコネクションプリフェイス」となる。変更となったコミットを見てみると...「Connection header -> connection preface (to avoid considerable confusion)」と書かれているので、紛らわしいという理由のようだ。

PRIとSM

記録としてPRIとSMの理由を見つけることは出来なかったが...
当時PRISMが世間をにぎわしてたことは記憶に新しい(PRISM and HTTP/2.0)