Skip to content

Instantly share code, notes, and snippets.

@tatsuhiro-t
Last active December 27, 2015 22:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tatsuhiro-t/7397929 to your computer and use it in GitHub Desktop.
Save tatsuhiro-t/7397929 to your computer and use it in GitHub Desktop.

HTTP/2.0 ヘッダー圧縮エンコーダーを簡単に書くには ?

現在策定が進んでいる HTTP/2.0 では独自のヘッダー圧縮方法を使用している. 最新版は, http://http2.github.io/http2-spec/compression.html で公開されている. この文章を書いている時点での最新版は, http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-04 である.

以下では, draft-XX は, HTTP/2.0 ドラフト XX を指し, HPACK-XX は, ヘッダー圧縮ドラフト XX を指すこととする.

このヘッダー圧縮に対しては複雑すぎるという批判がある. 確かに, zlib をそのまま使えた SPDY に対して実装すべき部分は多い. またヘッダー圧縮がそもそも存在しない HTTP/1 に比べるとはるかに複雑である.

筆者はヘッダー圧縮について, HPACK-04 まで実装してきた. 圧縮されたヘッダーを元に戻すデコーダーにおいてはコーナーケースは少ないが, しかし, エンコーダーにおいては, 厄介なコーナーケースがいくつか存在する. だがこのコーナーケースは「スマート」な高圧縮を実現するエンコーダーを書こうとすると直面するという代物なのであり, 圧縮率はあまり気にしないからとにかく動くコードがほしいという場合においては, 実は問題にならない.

この文章では, 圧縮率を気にせずとにかく簡単にエンコーダーを書く方法を記述しようと思う.

ヘッダー圧縮におけるコンポーネント

仕様書にはコンセプトとしてコンポーネントが説明されている. HPACK-04 では 8 個のコンポーネントが記載されている. 本文章の趣旨は「とにかく簡単」を目指すので必要最低限のコンポーネントしか使わない. 不要なコンポーネントは以下のとおりである:

Header Table

ダイナミック・ヘッダー・テーブルとも呼ばれる. これは incremental indexing という処理をすることで一度エンコードしたヘッダーを格納しておいて, 次回はテーブルのインデックスだけで参照し, ワイアー上の転送量を少なくする仕組みである. 我々は圧縮率を気にしないのでこのテーブルは使わないことにする.

Static Table

これはよく使うヘッダーフィールドの名前と値のペアを事前に登録しておく, Read-only なテーブルである. ここに登録されている名前と値のペアに一致するヘッダーや, 名前だけ一致するヘッダーをエンコードする場合は, 文字列ではなく, テーブルのインデックスを使うことでワイアー上の転送量を少なくすることができる. 圧縮率を気にしない我々はこのテーブルは使わない.

Reference Set

ヘッダー圧縮においては, ひとつ前のヘッダーセットと違うヘッダー, すなわち追加されたヘッダーと削除されたヘッダーのみをエンコードするという delta encoding という手法を使っている. その際に参照するのがこの Reference Set である. 圧縮率を気にしない我々は delta encoding をしなくてもよいので, Reference Set も使わないことにする.

Header Field Representation

これはワイアー上のヘッダーのエンコーディング方法で, HPACK-04 では現在 5 種類ある. このうち, 我々が使うのは Literal Header Field without Indexing - New Name だけである. その他 4 種類は使わない.

その他, 使わない仕様

HAPCK-04 からはさらなる圧縮率を実現するため, ヘッダーの名前, 値をハフマン符号化する方式が導入された. ただし, ハフマン符号化は元の文字列によっては効果がなかったり逆に文字数が増えたりもするので, 各文字列単位で符号化をしないというオプションが用意されている. 「とにかく簡単」を目指す我々はもちろんハフマン符号化を使わないことはいうまでもない.

Header Table のサイズ制限

Header Table はメモリ使用量を制限するため, 厳密に設定値以下の容量になるように調整されるようになっている. 初期値は 4096 バイトである. draft-07 からはリモートのデコーダーがサイズ制限を変更できるようになり, エンコーダーはそれを守らなくてはならない. デコーダーが 16KB にしたいといってもエンコーダーとしては 4KB のままで行きたい場合もある. 現在の仕様ではこのことも実現可能なのだが, テーブルと Reference Set の操作が若干複雑である. 幸い, 我々は Header Table を使わないことにしたので, サイズの変更など気にしなくてよいのである.

Header Table でバグが多い部分はサイズ制限により古いヘッダーを削除する処理である. 幸い, 我々は Header Table を使わないことにしたので, 削除など一切考えなくて良い.

簡略化されたエンコーダーアルゴリズム

では以上のことを踏まえて簡略化されたエンコーダーアルゴリズムを以下に示す, といいたいところだが, もうアルゴリズムどころの話ではない. 単純に各ヘッダーフィールドの名前と値のペアを Literal Header Field without Indexing - New Name でエンコードするだけである. もう複雑だとは言わせない.

圧縮率は ?

そもそも我々は圧縮率を気にしないという前提でここまでやってきたのであって, 圧縮率などを気にしてはいけない. 強いて言うなら圧縮率 0, あるいは HTTP/1 に比べて若干増えるだろう.

最後に

圧縮率を気にせずとにかく簡単に HTTP/2.0 ヘッダー圧縮エンコーダーを書く方法を述べた. まずはこの方法で実装し, 徐々に圧縮率を高める方法を目指すのもいいだろう.

本文章ではデコーダーについては触れなかったが, ここまで割り切れるエンコーダーとは違ってデコーダーは, 仕様すべてを満たさないと使い物にならない. そのため Header Table も実装しなくてはならないし, ハフマン符号化のデコードも実装しなければならない. 実装量は多くなるが, エンコーダーのフル実装よりもトラップははるかに少ない (あるいは 0) と筆者は確信している.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment