WiresharkでWebSocket通信をパケットキャプチャしてみた(WebSocketの接続)

Wiresharkはバージョン1.8.0から対応プロトコルにWebSocketが追加されていて、WebSocketの通信はWebSocketと表示される

そんなわけで、早速パケットを覗いてみる。
使った環境は「WebSocketでEchoServerをつくる(Jetty8編)」のもの。
つまり、以下。
サーバ:Jetty 8.1.8.v20121106
クライアント:Google Chrome 24.0.1312.52

まずは、WebSocketのコネクション接続時。と言っても、ここはHTTP通信で行われるので、普通にHTTPリクエストとHTTPレスポンスだったりする。

HTTPリクエストはこんな感じ。

GET /WebSocket_Jetty/EchoServlet HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Host: 192.168.1.5:8080
Origin: http://192.168.1.5:8080
Pragma: no-cache
Cache-Control: no-cache
Sec-WebSocket-Key: 30NeuZ+L6XOBboj/l7m/tg==
Sec-WebSocket-Version: 13
Sec-WebSocket-Extensions: x-webkit-deflate-frame

今回の接続先は "ws://192.168.1.5:8080/WebSocket_Jetty/EchoServlet" でJavaScript

var ws = new WebSocket("ws://localhost:8080/WebSocket_Jetty/EchoServlet");

と書くと上のようなHTTPリクエストが送信される。
では、HTTPリクエストの内容をもうちょっと見てみる。

GET /WebSocket_Jetty/EchoServlet HTTP/1.1
Host: 192.168.1.5:8080
Pragma: no-cache
Cache-Control: no-cache

このあたりは通常のHTTPと変わらない。普通のGET。
"no-cache"の指定がされているが、RFC6455ではキャッシュについての記述は見当たらないので、あってもなくてもいいのではないかと。

Upgrade: websocket
Connection: Upgrade

この2つは必須のヘッダ。"Upgrade"には"websocket"、"Connection"には"Upgrade"を必ず指定する。

Origin: http://192.168.1.5:8080

ブラウザからのリクエストの場合は必須。ブラウザ以外の場合はあってもなくてもよい。超簡単に言うと、このWebSocket接続のリクエストを投げたJavaScriptをダウンロードしたオリジン。
今回は、"http://192.168.1.5:8080/WebSocket_Jetty/index.html" の中に書かれたJavaScriptがWebSocketの接続をしているので、上の値が設定されている。オリジンの詳細についてはRFC6454 "The Web Origin Concept"を参照。

Sec-WebSocket-Key: 30NeuZ+L6XOBboj/l7m/tg==

これも必須。ランダムに4バイトの値を作成し、さらにbase64エンコードした値が設定される。ランダム値なので、この値は毎回違うものが使用される。

Sec-WebSocket-Version: 13

WebSocketのバージョンで、必須のヘッダ。現在のRFC6455では、必ず"13"を指定。

Sec-WebSocket-Extensions: x-webkit-deflate-frame

オプションのヘッダ。どうもChromeは "x-webkit-deflate-frame" を入れるらしい。
"x-webkit-deflate-frame"はWebSocketのフレームを圧縮するものだが、少なくともJettyやTomcatでは使えないので無視しておこう。

他にも "Sec-WebSocket-Protocol" なんていうオプションのヘッダもRFC6455にはあるが、今回は使ってないので、また今度。

以上でHTTPリクエストは終了し、HTTPレスポンスはこんな感じでやってくる。

HTTP/1.1 101 Switching Protocols
Upgrade: WebSocket
Connection: Upgrade
Sec-WebSocket-Accept: fdJzSVExohGlkkwXcc59Jq1yEkE=

では、詳細を見てみよう。

HTTP/1.1 101 Switching Protocols

ステータスコードなので、当然、必須ヘッダ。サーバ側がWebSocketの接続を受け入れる場合のステータスコードは"101"。

Upgrade: WebSocket
Connection: Upgrade

リクエスト同様、必須ヘッダ。

Sec-WebSocket-Accept: fdJzSVExohGlkkwXcc59Jq1yEkE=

必須ヘッダ。この値は以下の手順で作られる

  1. 1. リクエストの中にあった"Sec-WebSocket-Key"の値と、固定の文字列"258EAFA5-E914-47DA-95CA-C5AB0DC85B11" を連結する。
  2. 2. その値のSHA-1ハッシュを算出する。
  3. 3. そこから得られる20バイトをbase64エンコードする。

ここまでのやり取りでWebSocketの接続が完了。
データ送受信のパケットキャプチャは次回にでも。