mrubyでSPDYやHTTP2通信

年末にSPDYやHTTP2の勉強がてら、mrubyでSPDYやHTTP2通信可能なmrbgemを作りました。

これで、mrubyを組み込んだアプリケーションやデバイスからSPDY・HTTP2通信ができるようになって未来が広がりますね。

現状はクライアントのGETのみができます。これで、例えばmod_mrubyやngx_mrubyに組み込んで、あるURLにアクセスした場合はバックエンドでSPDYやHTTP2な通信をすることもできますね。

サンプル

SPDYやHTTP2通信をするためにはRubyで以下のように書きます。

SPDY通信

r = SPDY::Client.get 'https://www.google.co.jp/'

p r
p r.body
p r.body_length
p r.spdy_version
p r.stream_id
p r.syn_reply
p r.syn_stream

以下のようなレスポンスが得られます。

#r
{
    :syn_reply=>{
        "x-frame-options"=>"SAMEORIGIN",
        "x-xss-protection"=>"1; mode=block",
        "expires"=>"-1",
        "p3p"=>"CP=¥"This is not a P3P policy! See http://www.google.com/support/accounts/bin/answer.py?hl=en&answer=151657 for more info.¥"",
        "server"=>"gws",
        "set-cookie"=>"; expires=Sun, 29-Jun-2014 17:16:55 GMT; path=/; domain=.google.co.jp; HttpOnly",
        ":version"=>"HTTP/1.1",
        "alternate-protocol"=>"443:quic",
        "cache-control"=>"private, max-age=0",
        "content-type"=>"text/html; charset=Shift_JIS",
        "date"=>"Sat, 28 Dec 2013 17:16:55 GMT",
        ":status"=>"200 OK"
    },
    :recieve_bytes=>953.0,
    :body=>"<html> - (snip) - </html>",
    :body_length=>953,
    :spdy_proto_version=>4,
    :stream_id=>1,
    :syn_stream=>{
        ":method"=>"GET",
        ":path"=>"/",
        ":scheme"=>"https",
        ":version"=>"HTTP/1.1",
        ":host"=>"www.google.co.jp",
        "accept"=>"*/*",
        "user-agent"=>"mruby-spdy/0.0.1"
    }
}

#r.body
"<html> - (snip) - </html>"

#r.body_length
953

#r.spdy_version
4

#r.syn_stream
{
  ":method"=>"GET",
  ":path"=>"/",
  ":scheme"=>"https",
  ":version"=>"HTTP/1.1",
  ":host"=>"www.google.co.jp",
  "accept"=>"*/*",
  "user-agent"=>"mruby-spdy/0.0.1"
}

#r.syn_reply
{
  "x-frame-options"=>"SAMEORIGIN",
  "x-xss-protection"=>"1; mode=block",
  "expires"=>"-1",
  "p3p"=>"CP=¥"This is not a P3P policy! See http://www.google.com/support/accounts/bin/answer.py?hl=en&answer=151657 for more info.¥"",
  "server"=>"gws",
  "set-cookie"=>"; expires=Sun, 29-Jun-2014 17:16:55 GMT; path=/; domain=.google.co.jp; HttpOnly",
  ":version"=>"HTTP/1.1",
  "alternate-protocol"=>"443:quic",
  "cache-control"=>"private, max-age=0",
  "content-type"=>"text/html; charset=Shift_JIS",
  "date"=>"Sat, 28 Dec 2013 17:16:55 GMT",
  ":status"=>"200 OK"
}

HTTP2通信

コードは以下になります。

r = HTTP2::Client.get 'https://106.186.112.116/'

p r
p r.body
p r.request_headers
p r.response_headers
p r.status
p r.body
p r.body_length
p r.stream_id

レスポンスは以下のようにハッシュで得られます。

#r
{
  :body=>"---- snip ----",
  :body_length=>1400,
  :stream_id=>1,
  :frame_send_header_goway=>true,
  :recieve_bytes=>1400.0,
  :request_headers=>{
    ":path"=>"/",
    ":scheme"=>"https",
    "user-agent"=>"mruby-http2/0.0.1",
    ":authority"=>"106.186.112.116",
    ":method"=>"GET",
    "accept"=>"*/*"
  },
  :response_headers=>{
    "last-modified"=>"Wed, 18 Dec 2013 15:12:23 GMT",
    "etag"=>"¥"52b1bb57-2450¥"",
    "x-varnish"=>"340171131",
    "content-length"=>"9296",
    "date"=>"Tue, 31 Dec 2013 11:04:13 GMT",
    "age"=>"0",
    "accept-ranges"=>"bytes",
    "content-type"=>"text/html",
    ":status"=>"200",
    "server"=>"nginx/1.4.1 (Ubuntu)",
    "via"=>"1.1 varnish, 1.1 nghttpx"
  }
}

#r,status
200

#r.request_headers
{
  ":path"=>"/",
  ":scheme"=>"https",
  "user-agent"=>"mruby-http2/0.0.1",
  ":authority"=>"106.186.112.116",
  ":method"=>"GET",
  "accept"=>"*/*"
}

#r.response_headers
{
  "last-modified"=>"Wed, 18 Dec 2013 15:12:23 GMT",
  "etag"=>"¥"52b1bb57-2450¥"",
  "x-varnish"=>"340171131",
  "content-length"=>"9296",
  "date"=>"Tue, 31 Dec 2013 11:04:13 GMT",
  "age"=>"0",
  "accept-ranges"=>"bytes",
  "content-type"=>"text/html",
  ":status"=>"200",
  "server"=>"nginx/1.4.1 (Ubuntu)",
  "via"=>"1.1 varnish, 1.1 nghttpx"
}

#r.body

まとめ

このように簡単にmrubyでSPDY・HTTP2でGETが簡単にできるようになりました。是非遊んでみて下さい。今後やりたいこととしては、

  • 通信中のコールバック関数をRubyで書けるようにする
  • サーバ・プロキシ実装
  • クライアント・サーバ・プロキシの細かい機能を追加
  • httpパーサやsslをmrubyのクラスに分離

を考えています。また、pull-requestも大歓迎であります。

Leave a Comment