最近、h2o で mruby がサポートされたので、まずはコンパイルしてみた。

https://github.com/h2o/h2o

h2o は、@kazuho さんが作成されている HTTP/2 & HTTP/1.x 対応の高速な WEBサーバです。

環境

いつものごとく vagrant で。

  • CentOS 7.1 (3.10.0-229.el7.x86_64)
  • h2o 1.4.2
  • mruby 1.1.0

手順

現状 h2o で mruby を利用する場合は、h2o と mruby のコンパイルを、別々に行わなければいけない(mod_mruby とかだとそのなかで mruby をビルドしてくれる)。

流れとしてはまず、libmruby.a を作成し、h2o コンパイル時にそれをリンクする感じ。

  1. 作業ディレクトリの作成

    mkdir work
    cd $_
    

    vagrant の共有フォルダ上は NG。vboxfs はハードリンクの作成ができないので h2o のビルドに失敗する。

  2. mruby と h2o のコンパイルに必要なパッケージのインストール

    sudo yum install -y git gcc bison ruby cmake openssl-devel
    
  3. libmruby.a の作成(mruby のコンパイル)

    git clone https://github.com/mruby/mruby.git
    cd mruby
    ./minirake
    

    追加で利用したい mrbgems がある場合は、ここで設定しておく。

  4. libmruby.pc の作成

    h2o コンパイル時に、作成した libmruby.a 等を参照できるよう libmruby.pc (pkg-config 用の設定ファイル)を作成し、環境変数PKG_CONFIG_PATH に登録しておく。

    cat <<EOD>build/host/lib/libmruby.pc
    prefix=$PWD
    libdir=\${prefix}/build/host/lib/
    includedir=\${prefix}/include
    
    Name: libmruby
    Description: mruby libraries
    Version: 1.1.0
    Libs: -L\${libdir} -lmruby
    Cflags: -I\${includedir}
    EOD
    
    export PKG_CONFIG_PATH="$PWD/build/host/lib/"
    
  5. h2o のコンパイル

    cd ..  # work 直下に移動
    git clone https://github.com/h2o/h2o.git
    cd h2o
    git submodule update --init --recursive
    
    $ cmake -DWITH_MRUBY=ON .
    -- The C compiler identification is GNU 4.8.3
    -- Check for working C compiler: /usr/bin/cc
    -- Check for working C compiler: /usr/bin/cc -- works
    -- Detecting C compiler ABI info
    -- Detecting C compiler ABI info - done
    -- Found PkgConfig: /usr/bin/pkg-config (found version "0.27.1")
    -- Looking for include file pthread.h
    -- Looking for include file pthread.h - found
    -- Looking for pthread_create
    -- Looking for pthread_create - not found
    -- Looking for pthread_create in pthreads
    -- Looking for pthread_create in pthreads - not found
    -- Looking for pthread_create in pthread
    -- Looking for pthread_create in pthread - found
    -- Found Threads: TRUE
    -- Found OpenSSL: /usr/lib64/libssl.so;/usr/lib64/libcrypto.so (found version "1.0.1e")
    -- checking for module 'libuv>=1.0.0'
    --   package 'libuv>=1.0.0' not found
    -- Could NOT find LIBUV (missing:  LIBUV_LIBRARIES LIBUV_INCLUDE_DIR)
    -- checking for module 'libwslay'
    --   package 'libwslay' not found
    -- Could NOT find WSLAY (missing:  WSLAY_LIBRARIES WSLAY_INCLUDE_DIR)
    -- checking for module 'libmruby'
    --   found libmruby, version 1.1.0
    -- Configuring done
    -- Generating done
    -- Build files have been written to: /home/vagrant/work/h2o
    
    $ make h2o
     :
    Linking C executable h2o
    [100%] Built target h2o
    
    $ ls -l h2o
    -rwxrwxr-x 1 vagrant vagrant 11680735  8月  4 22:39 h2o
    

動作確認

サンプルの conf で起動。

$ ./h2o -c ./examples/h2o_mruby/h2o.conf
[OCSP Stapling] failed to execute share/h2o/fetch-ocsp-response:No such file or directory
[OCSP Stapling] disabled for certificate file:examples/h2o/server.crt
[OCSP Stapling] failed to execute share/h2o/fetch-ocsp-response:No such file or directory
[OCSP Stapling] disabled for certificate file:examples/h2o/server.crt
[OCSP Stapling] failed to execute share/h2o/fetch-ocsp-response:No such file or directory
[OCSP Stapling] disabled for certificate file:examples/h2o/alternate.crt
[INFO] raised RLIMIT_NOFILE to 4096
[OCSP Stapling] failed to execute share/h2o/fetch-ocsp-response:No such file or directory
[OCSP Stapling] disabled for certificate file:examples/h2o/alternate.crt
h2o server (pid:27481) is ready to serve requests

curl でアクセス

# curl http://localhost:8080/
hello from h2o_mruby. User-Agent:curl/7.29.0 New User-Agent:new-curl/7.29.0-h2o_mruby path:/ host:localhost method:GET query: remote_ip:::1

hello 。

examples/h2o_mruby

ちなみに examples の conf 等はこんな感じだった。

# to find out the configuration commands, run: h2o --help
listen: 8080
listen:
  port: 8081
  ssl:
    certificate-file: examples/h2o/server.crt
    key-file: examples/h2o/server.key
hosts:
  "127.0.0.1.xip.io:8080":
    paths:
      /:
        file.dir: examples/doc_root
        mruby.handler_path: examples/h2o_mruby/hello.rb
    access-log: /dev/stdout
  "alternate.127.0.0.1.xip.io:8081":
    listen:
      port: 8081
      ssl:
        certificate-file: examples/h2o/alternate.crt
        key-file: examples/h2o/alternate.key
    paths:
      /:
        file.dir: examples/doc_root.alternate
    access-log: /dev/stdout
# paths:
#   /:
#     file.dir: examples/doc_root
#     mruby.handler_path: /path/to/hello.rb

r = H2O::Request.new

h = "hello"
m =  "from h2o_mruby"

ua = r.headers_in["User-Agent"].to_s
new_ua = r.headers_in["User-Agent"] = "new-#{ua}-h2o_mruby"
uri = r.uri
host = r.hostname
method = r.method
query = r.query

msg = "#{h} #{m}. User-Agent:#{ua} New User-Agent:#{new_ua} path:#{uri} host:#{host} method:#{method} query:#{query} remote_ip:#{H2O::Connection.new.remote_ip}"

r.log_error msg

H2O.return 200, "OK", msg + "\n"