Hatena::Groupsubtech

NaN days

ブログを移転しています。最新の記事は motemen.hatenablog.com へどうぞ

2010-10-19

Twiggy で WebSocket (draft-ietf-hybi-thewebsocketprotocol-00) のサーバサイド実装

| 00:20 | Twiggy で WebSocket (draft-ietf-hybi-thewebsocketprotocol-00) のサーバサイド実装 - NaN days を含むブックマーク はてなブックマーク - Twiggy で WebSocket (draft-ietf-hybi-thewebsocketprotocol-00) のサーバサイド実装 - NaN days

自分が使っている Google Chrome 6 では Twiggy の eg/ にある WebSocket のサンプルが動かないなーと思ったら、プロトコルがまだ確定していないためクライアントのバージョンによって実装されている仕様が違うそうです。せっかくなので Google Chrome 6 が対応しているという draft-ietf-hybi-thewebsocketprotocol-00 (これ?) に対応した echo サーバを書いてみました。

http://gist.github.com/632374

スクリプトを起動後 9090 ポートにアクセスし、フォームを送信すると返事が返ってきます。ページを閉じるまで接続は持続されています。

f:id:motemen:20101019001232p:image

WebSocket のプロトコルで前の版と大きく違うのは handshake の部分で、Challenge-and-Response 式の認証を経なくてはならなくなったようです。これがしちめんどくさくて、ソースの通りなのですが、

  1. クライアントの送った Sec-WebSocket-Key1: ヘッダから数字部分のみを取り出し連結した数字を、ヘッダに含まれる空白文字列の数で割った数を求める (たぶん整数になる)
  2. Sec-WebSocket-Key2: ヘッダについても同様の数を求める
  3. 1, 2 で得られた整数をそれぞれ big-endian の 4 バイト列とみなし、ヘッダに続いてクライアントが送ってくる 8 バイトのバイト列とこの順序で連結
  4. こうして得られた 16 バイトの文字列を MD5 でハッシュ化した長さ 16 のバイト列が、サーバの応答となる。これをヘッダにつづけて返す

という手順を経てハンドシェイク完了です。このクライアントのボディ部分を得るところに AnyEvent::Handle を使おうとすると、いつまでも読み込めなくてはまった。Perl の read() 関数を使えばうまく読み取れたので、なにか sysread と read の違いがあるんだろうなと思ったけど、はっきりとはわかりませんでした。Perl の層のバッファに蓄えられてるのかな。