簡単にHTTP/2通信を試す
仕事でちょっとHTTP/2通信のフレームの内容を確認する必要があったのでツールを作りました。
curlやブラウザ組み込みの開発ツールでは、HTTP/2で通信してもHTTP/1.1レベルの情報しか表示してくれず、HTTP/2のフレームレベルの確認はできません。Wiresharkでキャプチャしてもいいのですが、送信データを少しいじって試したかったので、今回簡単なものを作りました。
https://github.com/kztomita/http-dump
シェル上で実行するコマンドで、指定URLにHTTP/2でGETリクエストを送信し、レスポンスを受信するまでのHTTPフレームのやりとりを出力します(詳細はリンク先のREADMEを参照)。
使用例
./http-dump -v --http2 https://github.co.jp/
実行結果例
HTTP/2で通信できれば以下のように送受信したフレームの内容が表示されます。
SEND SETTINGS ←SETTINGSフレームを送信 Header: ←フレームのヘッダーとペイロードを表示 00 00 00 04 00 00 00 00 00 ......... RECV SETTINGS ←SETTINGSフレームを受信 Header: 00 00 06 04 00 00 00 00 00 ......... Payload: 00 03 00 00 00 64 .....d SETTINGS_MAX_CONCURRENT_STREAMS: 100 ←ペイロードの解析結果(対応しているのは一部のフレームのみ) ...略... RECV HEADERS Header: (Flags:END_HEADERS) 00 01 64 01 04 00 00 00 01 ..d...... Payload: 88 5f 92 49 7c a5 89 d3 4d 1f 6a 12 71 d8 82 a6 ._.I|...M.j.q... 0b 53 2a cf 7f 76 88 c4 64 e3 b6 35 c8 7a 7f 6c .S*..v..d..5.z.l 96 d0 7a be 94 13 2a 6e 2d 6a 08 01 7d 40 bf 71 ..z...*n-j..}@.q 91 5c 6d f5 31 68 df 62 8c fe 5b 91 e7 c3 21 63 .\m.1h.b..[...!c 59 f9 49 2f f3 54 01 2a 64 96 e4 59 3e 94 03 8a Y.I/.T.*d..Y>... ...略... HEADERSフレーム受信後はHPACK形式のデータを解析してHTTPヘッダーを取得する。 ヘッダー取得の過程で作成したDynamic Tableの内容をダンプ。 HPACK Dynamic Table Table Size: 1124 (Maximum:4096) [1] x-fastly-request-id 7aa35e6172bdc0d2bb89eb7dd5c3def067195299 [2] :vary Accept-Encoding [3] x-timer S1573011759.218532,VS0,VE171 [4] x-cache-hits 0 [5] x-cache MISS ...略... 最終的に取得したHTTPヘッダーのリストを表示 HPACK Decoded header list :status 200 :content-type text/html; charset=utf-8 :server GitHub.com :last-modified Mon, 23 Sep 2019 19:32:59 GMT :etag "5d891deb-9fcf" :access-control-allow-origin * :expires Wed, 06 Nov 2019 00:30:42 GMT ...略... HTTP/1.1の形式に変換してレスポンスコードとHTTPヘッダーを表示 HTTP Response Status 200 Headers Content-Type: text/html; charset=utf-8 Server: GitHub.com Last-Modified: Mon, 23 Sep 2019 19:32:59 GMT ...略... 最後に取得したレスポンスボディを出力
HTTP/1.1の頃はテキストデータのやりとりだったので、telnet等で簡単にリクエストを送信して内容を確認したりできたのですが、HTTP/2になって転送形式がバイナリになったり、TLSが必要になったりで手軽にリクエスト送信して内容を確認することができなくなってしまいました。
勉強のためにもHTTP/1.1やSMTPのように簡単に試せるというのは結構重要だと思うんですよね。以前からHTTP/2の通信を簡単に試せるツールが欲しいと思っていたので今回作成しました。
機能自体は少ないので、送信するHTTPヘッダーを変更したい場合などはソースコードを直接修正する必要があります。
HTTP/2の通信手順はh2.ccをみればだいたいわかると思います。GETリクエストを送信してレスポンスを受け取るだけならSETTINGS,HEADERS,DATA,GOAWAYの4種類のフレームをやりとりするだけですみます。送信するSETTINGSフレームの内容やHTTPヘッダーを変えたい場合もh2.ccを修正すれば対応できます。
実際に実装して面倒だったのが、HTTPヘッダーのやり取り。
HTTP/2ではHTTPヘッダーをHPACKという方式で圧縮してHEADERSフレームでやり取りするのですが、ハフマン符号化される場合があったり、Dynamic Tableの管理が必要だったりとそれなりにやることが多いです。このあたりもHTTP/2通信の中身をちょっと覗いてみたいという人にとっては壁になるのではないかと思います。
とりあえずレスポンスを取得するだけなら、HEADERSフレームの中身は無視してしまってもいいのですが、今回はHPACKのデコード処理はそれなりに真面目に実装しました。リクエストを1回送るだけなのでDynamic Tableの更新はあまり意味がありませんが。
HPACK関連の処理はhpack_*.ccのファイルにあります。
現状、HTTP/2通信を試してみるレベルのものなので、ストリームも一つしか使っていませんし、ストリームの状態管理のようなことも行っていません。イレギュラーなフレームを受信したり、本来、PROTOCOL ERRORを返すべきところでもそのまま終了しています。
作っていたらいろいろおもしろくなってきたので、時間があれば複数ストリームを使った通信やPRIORITYまわりもいじれるようにしてみたいと思います。
[参考]
Hypertext Transfer Protocol Version 2 (HTTP/2)
https://tools.ietf.org/html/rfc7540
HPACK: Header Compression for HTTP/2
https://tools.ietf.org/html/rfc7541
投稿日:2019/11/06 15:19