2014年11月19日水曜日

HTTP2: nghttp2_asioにウェブブラウザーでアクセスしてみる

HTTP2サーバーを組み込んだソフトウェアを開発しようと思うと、現在有力な選択肢は nghttp2h2o かなって思います。今回は nghttp2 をビルドして得られる libnghttp2_asio.so をリンクしたサーバーと、このサーバーをHTTP2で利用可能なクライアントとして Firefox 35 Developer Edition を使ってみます。

libnghttp2_asio.so のビルドとインストール

boost::asio

libnghttp2_asio.so のビルドには boost::asio が必要です。
Ubuntu-14.04 などのGNU/Linux環境でaptによらず最新版をまるっとビルドして使いたい場合の例:
git clone git clone --recursive git@github.com:boostorg/boost.git
cd boost
./b2 header
sudo ./b2 --build-type=complete --layout=tagged -j12 install
既に clone 済みからなら git submodule update --init してから ./b2 する。”/usr/local”以外に入れたければ --prefix=$HOME とかそういう感じでお忘れなく($HOMEに入れるなら sudo も要りません)。

libnghttp2_asio.so

./configure にオプションを明示しないと boost::asio 版のライブラリーはビルドされないので忘れずに。
git clone git@github.com:tatsuhiro-t/nghttp2.git
cd nghttp2
./configure --enable-asio-lib
make -j12
sudo make install
こちらも”/usr/local”以外に入れたければ ./configure--prefix=$HOME などお忘れなく($HOMEに入れるなら install の際に sudo も要りません)。
また、システムに JanssonJemalloc が導入されていれば ./configure で検出して使ってくれる。Ubuntu-14.04 なら apt-get install libjanson-dev libjemalloc-dev で用意できる。

nghttp2_asio のサーバーを書いて動かす

凡そ、公式ドキュメントの libnghttp2_asio: High level HTTP/2 C++ library をほぼそのまま参考に、リクエストが来たら標準出力にリクエストのパスを表示する程度、またサーバーの待ち受けアドレスをIPv4系の任意アドレスにするとこんな具合:
#include <nghttp2/asio_http2.h>
#include <iostream>

namespace
{
  using namespace nghttp2::asio_http2;
  using namespace nghttp2::asio_http2::server;

  constexpr auto ssl_key = "test.key";
  constexpr auto ssl_crt = "test.crt";
}

auto main() -> int
{
  http2 server;

  server.tls(ssl_key, ssl_crt);

  std::cout << "begin listen" << std::endl;

  server.listen
  ( "0.0.0.0"
  , 12121
  , []
    ( const std::shared_ptr<request >& req
    , const std::shared_ptr<response>& res
    )
    {
      std::cout << "request: " << req->path() << std::endl;
      if ( req->path() == "/" || req->path() == "index.html" ) {
        res->write_head( 200 );
        res->end( file_reader( "index.html" ) );
      } else {
        res->write_head( 404 );;
        res->end("404");
      }
    }
  );
}
ビルド:
g++ -O0 -g std=c++11 -o nghttp2-test1 nghttp2-test1.cxx -lnghttp2_asio
待ち受けアドレスは "*" にすると IPv6 系になるので、その際は IPv6 のネットワークデバイスのアドレスか、 ::1 でアクセスする必要がある。IPv4で待ち受ける場合は、 localhost 、 127.0.0.1 あるいはIPv4のデバイスのアドレスなど。

SSL 準備

Apache/SSL自己証明書の作成とmod sslの設定 など参考にテスト用に "test.key""test.csr" を用意。
openssl genrsa -aes128 2048 > test.key
openssl req -new -key test.key > test.csr
openssl x509 -in test.csr -days 65535 -req -signkey test.key > test.crt
openssl rsa -in test.key > test_no_passwd.key
mv test_no_passwd.key test.key

index.html 準備

適当に準備。
echo 'hello, nghttp2!' > index.html

Firefox 35 Developer Edition 準備

URL about:config から network.http.spdy.enabled.http2true にする(初期状態では false)。

お試しアクセス

ビルドしたサーバーを起動し、
./ghttp2-test1
HTTP2を利用可能に設定して再起動したFirefoxで、今回のソースの例であれば URL https://localhost:12121/ などアクセスしてみよう。
準備した "index.html" の内容がブラウザーに表示されれば、 HTTP2 で libnghttp2_asio を使ったサーバーとウェブブラウザーがうまく通信できたという事。未対応のウェブブラウザーではHTTP2のバイナリーフレームを解釈できないのでどうにもならないか、謎のデータが表示される事になる。
サーバーも std::cout を仕込んであったので、 Firefox からのリクエストに応じて //favicon.ico のパスを要求された旨を標準出力に示す。もちろん、適当なURLを要求してもブラウザーには 404 が返り、ログにはその要求されたパスが表示される。
ちなみに、 Chromium-38 では chrome://flags/#enable-spdy4 あたりを有効化したらもしかして、と思ったけれども対応できず。今のところ、 HTTP2 を nghttp2 で直接試そうと思ったのなら Firefox を使うのが良さそう。もちろん、 curl-7.35 や wget-1.15 でも HTTP2 の nghttp2 との通信には未対応。
おまけ
この記事から、 StackEdit というWebブラウザーアプリの Markdown のリアルタイムプレビュー付きのエディターを使ってみている。わりと良い。これまで幾度と無く Blogger 標準機能のエディターにはうんざりしていたものの、 StackEdit には Blogger へのパブリッシュ機能があるので、今回の記事からはとても快適に Blogger へとポストできる。嬉しい(╹◡╹)

0 件のコメント:

コメントを投稿