よーでんのブログ

One for All,All for わんわんお!

HTTP/1.0とHTTP/1.1のパケットを比較してみる

HTTPの比較

HTTPの仕様についてわかりやすくまとまっている記事やブログはたくさんあるけど、
読んでも実感がわかない。

ということで、

HTTP/1.0とHTTP/1.1をWSLからcurlで叩いてWiresharkでキャプチャし、その様子を見比べてみる。
HTTP/1.0とHTTP/1.1それぞれhttpとhttps両方やったが、気が向いたのでおまけにHTTP/2もチラ見。

今回は、バージョンごとの仕様の違いをわかりやすくするため以下のような感じに二個連続でリクエストを送る。

curl http://example.com/ http://example.com -v --http1.0

pcapやログ等は下記のリポジトリ

github.com

ちなみに、筆者はHTTPの仕様などは全く知らないので悪しからず・・・

HTTP/1.0 (http)

curl http://example.com/ http://example.com -v --http1.0

全体はこんな感じ。

http/1.0

DNSから始まってTCPやHTTPで通信している。
細かく見ていこう。

DNS

1 ~ 4

まずはDNS
WSL(172.17.32.52)からホストPC(172.17.32.1)へDNS問い合わせをしている。
AIPv4AAAAIPv6でそれぞれリクエストとレスポンスで4行。

3ウェイハンドシェイク

5 ~ 7

DNSIPアドレスがわかったので、次は3ウェイハンドシェイクでコネクションの確立。
SYN, SYN/ACK, ACKがしっかり見える。(ちょっと感動した)

データ転送

8 ~ 11

コネクションの確立ができたので、次は実際にデータ転送。
しっかりとリクエストとレスポンスが確認できる。

コネクション切断

12 ~ 16

データ転送がすんだのでコネクションを接続する。
FIN/ACK, ACK, FIN/ACK, ACKでコネクションが終了。*1

これで1つのリクエストが終わった。

二個目

15 ~

curlでは2つURLを指定したのでもう1回同じのがある。
DNSのやり取りがないだけで、3ウェイハンドシェイクとデータ転送とコネクションの切断と、
一回目とほぼ同じやりとりをしていることがわかる。

HTTP/1.1 (http)

1.0より効率良くやり取りするらしい。

curl http://example.com/ http://example.com -v --http1.1

全体はこんな感じ

http/1.1

HTTP/1.0より少し行数が少ない。

詳細

DNSと3ウェイハンドシェイク、データ転送部分はHTTP/1.0と同じ。

1 ~ 11

ここからHTTP/1.0と違ってくる。

12 ~ 17

HTTP/1.0ではここでFIN/ACKとかしてコネクション切断したあとSYN/ACKとかして次のコネクションを確立していたが、
HTTP/1.1では「レスポンスを受け取ったよ」というACKを送信した後、
コネクションを切断せずにそのまま2個目をやり取りする

18 ~

これより後はまたHTTP/1.0と同じようにコネクションの切断をする。

HTTP/1.1の良い点

この比較において、HTTP/1.1が1.0より高速化してると確認できる要素は以下。

連続したリクエストに対して、前回のコネクションを再利用する

5 ~ 21

Keep-Aliveがデフォルトで有効になったおかげ。
一個目のリクエストのFINと二個目のリクエストのSYNが無いのが確認できる

HTTP/1.0 (https)

HTTPだけでは物足りなかったので、HTTP/1.0をHTTPSでも見てみる。
(HTTPSの暗号化云々とかはわからないので流します)

SSLKEYLOGFILE=/tmp/secret.log curl https://example.com/ https://example.com -v --http1.0

http/1.0 (https)

SSLKEYLOGFILEを設定>Protocols>TLS>Master-Secret log filenameからインポートすればHTTPSの中身が見える

パケットの量がめっちゃ増えた。スクショに写りきってないが、48行ある。
でも、暗号化云々のパケットが増えただけでやってることはあまり変わってない。

DNS

1 ~ 4

まずはDNS問い合わせ。

3ウェイハンドシェイク

5 ~ 7

さっきまでと色が違う。
あと、HTTPSなので宛先ポートが443。

でもやってることは同じで、SYN, SYN/ACK, ACK

SSL/TLSハンドシェイク

8 ~ 17

Client Hello, Hello Retry Request, Change Cipher Spec, Change Cipher Spec, Client Hello, Server Hello, Encrypted Extensions, Certificate, Certificate Verify, Finished, Finishedなどの通信でTLS 1.3のハンドシェイクをしてる。

このハンドシェイクはClientHelloのkey_shareが不正らしく、Hello Retry Request等が入ってきた。
本来のハンドシェイクはもうちょっとシンプル。

データ転送

18 ~ 21

GETしてNew Session Ticketとかの後にレスポンスが返ってくる。

コネクション切断

22 ~ 26

AlertとかFINとか、コネクションの切断周りの物がある。

二個目

これで一個目のリクエストは終わりで、二個目はやはりDNSが無いだけで同じことをしている。

27 ~

HTTP/1.1 (https)

http/1.1 (https)

34行。やってることはあまり変わらないので、要点だけ見る。

データ転送

18 ~ 25

HTTP/1.1はコネクションの再利用をするので、一個目のFINと二個目のTLSv1.3ハンドシェイクが不要になる。
結果、HTTP/1.0より14行も少なくなっている。凄い。

おまけ

HTTP/2 (http)

curl http://example.com/ http://example.com -v --http2

http/2

HTTP/2をhttpでやってみようとしたところ、良く見るとHTTP/1.1になっている。
少し調べたところ「HTTP/2はTLSのみ」みたいなことが書いてあったので、HTTPSでやってみる。

HTTP/2 (https)

http/2 (https)

DNSとTLSv1.3ハンドシェイクは同じ。

データ転送

19 ~ 34

zoom

MagicSETTINGSWINDOW_UPDATE?なんだこれ・・・」

今までとは全然違う、見たことないような通信をしている。
今回はHTTP/2の流れを理解するのは目標ではないので、とりあえずチラ見だけ。

HEADERS[TLS segment of a reassembled PDU]、そしてDATAは見覚えのある内容があった。

req header
res header
res body

ヘッダとボディがバラバラになっているのは面白い。

他のストリーム設定用の通信等はあんまり理解できなかった。
まだ自分はHTTP/1.1で感動するレベルだったので、そのうちHTTP/2も勉強してみたい。

*1:15番は次のリクエストのが混ざってしまったのでとりあえずignore