この記事は?
 TISアドベントカレンダー9日目です。
 最近、同期との会話で「HTTP/3とか出たけど、そもそもHTTPのバージョンってそれぞれどう違うのよ?」みたいな会話になりました。その場では「わからん!」でみたいな感じで話は終わってしまったのですが。個人的には興味があったので、この機会にまとめてみたいなと思って書いてます。
書くこと、書かないこと
先に書いたと通り、この記事では、バージョンの違いや、バージョンが上がってきた経緯についてまとめるものです。それぞれ仕様やセマンティクスについて1つ1つ詳細に調べてまとめるた記事ではないです。具体的には以下のようなことを書きます。
- HTTPとは
 - HTTPのバージョンごとの違い
 
また、この記事はバージョンごとのすべての変更点を網羅するものではなく主要なものをまとめるものです。
想定される読者
 HTTPの基礎の基礎は知っていることを想定しています。
 具体的には書籍「HTTPの教科書」に書かれてることをなんとなく把握している(それぞれの内容に説明はできなくとも聞けばそういうのもあるなぁってわかる)レベルを想定してブログを書いています。
そもそもHTTPとは?
RFC7230では、HTTPは以下のように説明されます。
The Hypertext Transfer Protocol (HTTP) is a stateless application
level protocol for distributed, collaborative, hypertext information
systems.
「HTTPは分散的で共同的なハイパーテキスト情報システムのためのステートレスなアプリケーションレベルのプロトコルです。」
HTTPではWebクライアントとWebサーバがコミュニケーションを取るために以下のような仕様を定めています。
- 送信する手順
 - 送信するフォーマット
 
HTTPのバージョンについて
 HTTPは、最初は非常にシンプルなプロトコルでした。月日がながれ、バージョンが上がるごとに機能追加や通信速度改善に対する取り組みが行われています。また、HTTPは前方互換性が保たれるように策定されています。
 それぞれのバージョンアップの年月日を以下にまとめます。
| 年代 | バージョン | 
|---|---|
| 1990 | HTTP/0.9 | 
| 1996 | HTTP/1.0 | 
| 1997 | HTTP/1.1 | 
| 2015 | HTTP/2 | 
| 2018年 | HTTP/3 | 
HTTP0.9
そもそもHTTP/0.9というバージョンは存在しませんでした。HTTP/1.0より前という意味合いで、0.9と呼ばれるようになったみたいです。このバージョンで行えることは非常にシンプルで
URLで特定されるHTMLを取得する
ということだけです。
イメージとしては「ブラウザーからURLを叩いて、HTMLのドキュメントを取得し表示する」これだけです。双方向通信はもちろんのこと、情報の更新や、削除も行えません。
HTTP/1.0
HTTP/1.0ではMIMEのようにメタデータを追加したメッセージ形式を導入することで、プロトコルの改善を行っています。
HTTP/0.9からの変更点
- 送受信フォーマットにヘッダが追加された。
 - リクエスト、レスポンス時のバHTTPのバージョンが追加された。
 - リクエスト時にメソッド(GET、PUT、POST、DELETE等)が送信できるようになった。
 - レスポンス時にステータスコードが送られるようになった。
 
できるようになったこと
上記の変更から、様々なセマンティクスが定義され、HTTP/1.0ではHTTP/0.9に対して以下のようなことができるようになりました。
- 複数のドキュメントを送信可能になった。
 - HTML以外のデータ形式を送受信するための手段が提供された。
 - コンテンツの追加、削除、更新などが行えるようになった。
 - サーバーからのリダイレクトの要求が可能になった。
 
HTTP1.1
HTTP/1.1では前バージョンまでの曖昧な点をはっきりさせ、パフォーマンスの改善のための仕組みが取り込まれてます。
HTTP/1.0からの変更点
- 通信の高速化(Keep-Aliveがデフォルト有効、パイプライニング)
 - TLSのサポート
 - プロトコルのアップグレード
 - チャンクエンコーディングのサポート
 
通信の高速化(Keep-Aliveがデフォルト有効、パイプライニング)
HTTP/1.1では以下のような方法で通信の高速化を実現しています。
- Keep-Aliveのデフォルトでの有効化
- 連続したリクエストに対して、再接続時に前回の接続を再利用する技術
 
 - パイプライニング
- 最初のリクエストの送信が完了する前に次のリクエスト送信する技術
 
 
パイプライニングに関しては、エンドポイント間にHTTP/1.0しか解釈できないプロキシがあった場合に動作不能となってしまうことや、正しく実装されていないサーバーがあったことにより、広く使われた技術ではありませんでした。しかし、まったくもって無駄になったわけではなく、あとから出てくるHTTP/2でストリームという仕組みとして生まれ変わります。
TLS(トランスポート・レイヤー・セキュリティ)のサポート
 TLSはHTTPよりも下のレイヤーの通信経路を暗号化するための技術です。HTTP/1.1では、このTLSをサポートしており、この仕組を利用したプロトコルがHTTPSです。HTTPS用いることでセキュアな通信が行えます。
 また、HTTP/1.0やHTTP/1.1ではプロキシサーバなどが内容を解釈し、解釈できないプロトコルなどをブロックしてしまうという問題がありました。しかし、HTTPレイヤーよりも下のプロトコルであるTLSを使うと、プロキシサーバが関われない安定した通信経路を確立でききるためHTTP/2のWebSocketのような、新しい前方互換性のない通信プロトコルを導入するためのインフラ基盤となっています。
プロトコルのアップグレード
HTTP/1.1では、以外へのプロトコルへのアップグレードがとなりました。HTTP/1.1以外のプロトコルへのアップグレードを含めると、以下の3つのようなアップグレードがあります。
- HTTPからHTTPS
 - HTTPからWebSocket(双方向通信プロトコル)
 - HTTPからHTTP/2
 
チャンク方式
サーバーからクライアントへデータを送信する際に、一括で送るのではなく小分けにして送る方式です。チャンクを使うことで、巨大なデータ送受信する際に小分けにして少しづつ送信することが可能になります。これにより、サーバー側では巨大なデータを一括でメモリにロードする必要がなくなり、クライアント側ではデータを逐次的に送られてきたデータを処理できます。
HTTP/2
 HTTP/2では、より効率的なネットワークリソースの活用が可能となり、へッダーの圧縮も行えるようになっています。
HTTPのメッセージの文法などは変わっておらず。HTTP/1.1のセマンティクスなどはこれまでと同様に利用可能です。
 「[HTTP/3 explained] (https://daniel.haxx.se/http3-explained/)」によると2018年の前半にはTOP1000 のWebサイトのうちおよそ40%がHTTP/2の上で動き、Firefoxの約70%のHTTPSのリクエストはHTTP/2のレスポンスを受けます。そして、それは、すべてのメジャーなブラウザーやサーバー、プロキシはHTTP/2をサポートしています。
HTTP/1.1からの変更点
- テキストベースからバイナリベースへ
 - ストリームを使ったデータ送受信
 - サーバープッシュ
 - ヘッダの圧縮
 
テキストベースからバイナリベースへ
HTTP/2ではテキストベースのプロトコルからバイナリベースのプロトコルへと変わりました。各データ「フレーム」と呼ばれる単位でデータを送受信します。
ストリームを使ったデータの送受信
 HTTP/1.1までは1つのリクエストは1つTCPソケットを専有してしまうため、1つのオリジンサーバに対して、複数(2〜6)のTCPコネクションを確立していました。それに対して、HTTP/2では1つのTCPコネクションに対してストリームと呼ばれる仮想TCPソケットを作成し、並列化を行います。この仮想TCPソケットはハンドシェイクを必要としません。
HTTP/2は4層モデルのアプリケーション層のプロトコルですが、フローコントロールなどの機能も備えています。
サーバプッシュ
サーバプッシュはCSSやJavaScript、画像などの要求されることが予測されるコンテンツを事前に送信する技術です。これはWebSocketのような双方向通信の仕組みではなく、あくまで上記のような静的コンテンツをリクエストより前に送信しておくための技術です。
ヘッダの圧縮
HTTP/2ではHPACKと呼ばれる方式でヘッダを圧縮します。HTTPヘッダは決まった名前がよく用いられるため、クライアントとサーバで同じ辞書を持ちその辞書を使うことでヘッダを圧縮します。
HTTP/3
 HTTP/3でもこれまでのメッセージの文法やコンセプトは変わりません。ヘッダーがあって、ボディがあって、リクエストがあり、レスポンス、HTTPメソッドも、ステータスコードもあります。また、HTTP/2と同様にストリームとサーバープッシュも提供します。
HTTP/3はHTTPがQUICの上で動作するための変更とその結果の集まりです。
HTTP/2.0からの変更点
- QUICと呼ばれるUDPソケットを用いたプロトコルの上で動作する。
 - 
HPACKではなく、QPACKと呼ばれるヘッダーの圧縮方式を使っている。 - QUICのおかげで、より早いハンドシェイクが行える(0-RTT or 1-RTT)
 - すべての通信はTLS1.3によって暗号化される。
 
QUICと呼ばれるUDPソケットを用いたプロトコルの上で動作する。
 QUICは、元はGoogleが開発したトランスポート層のプロトコルです。HTTP/3のQUICはGoogleのQUICを元にIETFが独自に策定を進めているものです。HTTP/3ではこのIETF-QUICにより、様々な恩恵を受けています。
HTTP/2とHTTP/3の層の違いをいかに示します。

QUICはUDPソケットを利用して通信を行います。UDP通信の信頼性はQUICが担保します。
HPACKではなく、QPACKと呼ばれるヘッダーの圧縮方式を使っている。
 HTTP/3でも、ヘッダの圧縮は行われます。しかし、HPACKでははくQPACKと呼ばれる圧縮方法を用いています。これらの設計は似ており、QPACKはQUIC版のHPACKと言うことができます。
より早いハンドシェイクが行える(0-RTT or 1-RTT)
 QUICでは、以前に通信を行ったことのあるサーバであれば、その通信のパラメータをキャッシュし0-RTTを可能にします。このおかげで、クライアントはハンドシェイクを待つことなく直ぐにデータを送ることができます。
また、キャッシュが無い場合でも、QUICは1-RTTのハンドシェイクを提供します。
すべての通信はTLS1.3によって暗号化される。
すべての通信はTLS1.3によって暗号化されます。例外はありません。TLS1.3はより少ないハンドシェイクで行えるため、コネクション確立のオーバーヘッドを減らします。
終わりに
この記事では、それぞれのバージョンの違いによる大きな差異をまとめました。HTTP/2までの詳細なバージョン間の違いや、セマンティクスなどをもっと詳しく知りたい場合は以下の書籍に記載されているので、読んだことのない人はぜひ読んでみてください。