読者です 読者をやめる 読者になる 読者になる

SPDYと「やったー、net-http-spdyできたよー」の話

SPDYを知る

SPDYという実験的なプロトコルがありまして、
SPDY - The Chromium Projects
HTTP2.0はSPDYをベースに作られるかも、みたいな話も風の噂で聞いたりするのでじゃあどんなもんかなあと仕様を読んで見ました。
SPDY Protocol - Draft 2 - The Chromium Projects
SPDY Protocol - Draft 3 - The Chromium Projects
SPDYv2とSPDYv3というのがあって、基本的にはSPDYv3の方を読んどけばいいのかなあとは思います。
ただSPDYv2もすでにいろんなところで使われていますので、仕様書の「7.Incompatibilities with SPDY draft #2」の部分もチェックしておきましょう。

HTTP Layering over SPDY

SPDYというのは一つのTCPソケットのコネクション上に複数の「ストリーム」と呼ばれるものを構築しちゃおうぜ、みたいなそういうプロトコルなんですけど、仕様書の下の方にはそのSPDYプロトコルの上にHTTPをのっけてしまおうという部分が書かれています。
HTTP1.1(や1.0)に対する仕様変更はそれほどなく(使ってはいけないヘッダとかは多少あるけど)、Webアプリケーションのレベルでの対応はほぼないでしょう。

どして速いのん?

SPDY使わない版のHTTPだと基本的には1つのTCPコネクションにおいて「リクエスト送るー、レスポンスが全部帰ってくるまで待つー」と順番を守らなければならないのですが(HTTP Pilpeliningがあるけど、ここでは省略)。
SPDY版だと「ストリーム作る〜、リクエスト送る〜、別のストリーム作る〜、別のリクエスト送る〜、全部のレスポンス待つ〜」とかできるので、コネクションも少なく済んでしかもある程度速いよーということかなあと思いました。
あとはよくわかんないけど圧縮とかもするみたいですねえ。

デモとしてわかりやすいのは以下の動画だと思います。実際の国旗のページは以下にあります。
https://www.modspdy.com/world-flags/

あとはとてもわかりやすい発表用の資料があったのでそちらもどぞ
SPDYの話

NPN氏〜登場〜

今、みなさんが見ている、google.comはきっとSPDYでやり取りしていることでしょう(IE???Safari???)。
でもこれってどうやってSPDYに対応してるページを検知しているのかなあと疑問だったのですが、TLSのNPNというものがあったんですね。恥ずかしながら知りませんでした。
draft-agl-tls-nextprotoneg-00 - Transport Layer Security (TLS) Next Protocol Negotiation Extension

クライアントとサーバー側がSSLハンドシェイクするときに
(ク)「君、なんのプロトコル持ってる?」
(サ)「うーんと、httpとspdy/v2とspdy/v3かなー」
(ク)「じゃあ、spdy/v3でよろしくー☆(ゝω・)vキャピ」
(サ)「うふふ、オッケー」
みたいなやりとりをするようですね(関係ないけど縦読みで「クサクサ」!!)。
なので、HTTP over SPDYというのは実質がSSL/TLSを提供しているWebページでしかつかえなさそうです。
あー、そういえばgoogle.comもtwitter.comもhttpsだわー。

NPNについてはmod_spdyのスライドがわかりやすかったです。
mod_spdy Architectural Overview - Google スライド

net-http-spdyできたよ〜

最近、golangの開発者用MLを購読しているのですが、そこで@Jxck_さんからnet/spdyをSPDYv3に上げたよーというレビュー依頼がでていて、SPDYの時代来るのかなあーと思って興味を持ったのが事のきっかけです。

じゃあ、RubyでSPDY試してみよーと思ったけど、手軽に使えるクライアントがないではないですか。
調べてみたところ、一応、SPDYのフレームのパーサは作られていて(SPDYv2なんだけど)、
igrigorik/spdy · GitHub
あーじゃあこれでnet-http-spdy作ってしまおうと一念発起して書いてみました!
authorNari/net-http-spdy · GitHub

こんな感じで書けます。

require 'net/http/spdy'

Net::HTTP::SPDY.start("www.google.com", 443, use_ssl: true) do |http|
  p http.get("/")
end

Net::HTTPを継承して拡張している感じなので、Net::HTTPでできることは大体できるはず(たぶん)。

ドキュメントない上に、テストもほぼないですが、まあそれはおいおいということで…。

ちなみに実質net-http-spdyはRuby2.0.0が必須となっています(これは警告ださんといかんかなあ)。
というのも前述したNPNが実装されたのがRuby2.0.0からだからなんですね。
Feature #6503: Support for the NPN extension to TLS/SSL - Ruby trunk - Ruby Issue Tracking System
@embossに感謝〜。