103 EarlyHints (RFC 8297) を送信するNginxモジュール書いた

これは、nginx Advent Calendar 2016の8日目の記事です。


103 Early Hints

先日の「Apache mod_http2 で 103 EarlyHints を試す」という記事でも書きましたが。軽くおさらい。


103 Early Hintsは、@kazuho氏によって提案されている仕様です。すでに Individual-Draftが提出されています。
https://tools.ietf.org/html/draft-kazuho-early-hints-status-code-00


IETF97でも仕様についての議論が行われており、その際のスライドを見ると分かりやすいかと思います。
https://www.ietf.org/proceedings/97/slides/slides-97-httpbis-sessb-early-hints-00.pdf


ステータスコードはコンテンツの生成が終わったあとに決定されるため、コンテンツの生成が終わるまでHTTPレスポンスは送信開始できません(1行目がステータスコードのため)。


103ステータスコードのレスポンスは本来のHTTPレスポンスに先んじて送信できるので、先行してHTTPレスポンスヘッダを送信することができます。たとえばLinkヘッダでPreloadを先に送信すれば今後必要になるリソースをより早くクライアントに知らせることができます。



前回の103ステータスコードを用いたmod_http2の実験では、103ステータスコードを返すサーバはモックサーバを立てましたが今回はNginxモジュールを書いてみました。(試験実装なので怪しいとは思います)

ngx_http_early_hints

試験実装ですがngx_http_early_hints モジュールとして、すでに公開済になります。
https://github.com/flano-yuki/ngx_http_early_hints


以下のように、locationディレクティブに add_early_header を宣言すると、マッチする際に103ステータスのレスポンスを返すようになります。

location /103.html {
    add_early_header "Link" "</main.css>;rel=preload";
}


実際にHTTPリクエストを送信してみると以下のように103スレータスのレスポンスがまず送信されます。
(NGX_HTTP_ACCESS_PHASEでフックしてるので、コンテンツの生成より早いタイミングで送信されます)

vagrant@vagrant:~$ telnet localhost 80
Connected to localhost.
Escape character is '^]'.
GET /103.html HTTP/1.1
host:localhost
HTTP/1.1 103 Early Hints
Link: </main.css>;rel=preload

HTTP/1.1 200 OK
Server: nginx/1.11.6
Date: Wed, 07 Dec 2016 13:29:12 GMT
Content-Type: text/html
Content-Length: 22
Last-Modified: Wed, 07 Dec 2016 13:28:44 GMT
Connection: keep-alive
ETag: "58480e8c-16"
Accept-Ranges: bytes

This is main contents

あとがき

Nginxモジュールを初めて書くので、お作法がだいぶわからなかったのですが、下記サイトが非常に参考になりました。ありがとうございます。


実用に足るかはわかりませんが、エラーハンドリング、HTTP/2のサポート、複数add_early_headerのサポート、ほかモジュールとの併用検証など進めていければと思います。