バイオリン奏者と詐欺師(Fiddler)

各所で紹介されているので今更だが、最近お気に入りなのが"Fiddler"という名の、.NETで書かれたWindowsプラットホーム(というかWinINET)専用のHTTPモニタ/デバッガだ。

Fiddler HTTP Debugging Proxy

他のよくあるHTTP-Snifferと違い、IEのプロキシ設定を頼りに動くので面倒な設定はいらないし、IEで行っているHTTP通信ほぼ全てをリアルタイムでトレースして、内容をいろいろな形式(ヘッダ、ツリー、テキスト、16進、等)でデコードしてチェックすることができる。また、GZipエンコードされた圧縮データをデコードしてみることもできるのだ。(.NET2.0ベースとなったFiddler2.0ではHTTPSで暗号化された電文にも対応するようだ)

軽快に動くしこれだけでも非常に有用なツールなのだが、Fiddlerが非凡なのはHTTPクライアントとしても、カスタマイズ可能なプロキシとしても使える所だ。例えばFiddlerには「Request Builder」と呼ばれる機能があり、任意のURLに対してヘッダとボディを自由に編集してその場限りのリクエストを作りテストすることができる。
以下は、User-Agentヘッダを"MSIE 6.0"に変更した例である。

(Fiddlerという名は、語源であるバイオリン奏者だと思うが、もう一つの語源には"詐欺師"という意味もある。HTTP通信を"偽る"ことができる処から来ているのだろうか。だとしたら洒落ている)

なお、Fiddlerは.NETの各種言語から公開アセンブリを介して制御できる。この機能では"FiddlerScript"と呼ばれるJScript.NETベースのスクリプトでFiddler自体やHTTPを操作することもできるようで、かなり強力だ。(実際にデフォルトで使っているFiddler自身のキャプチャルールをオーバライドする際もCustomRules.jsというJScript.NETのコードを直接書き換える)
Fiddler Extensibility

殆どのHTTPはこのツールでテストできるのだが、私の環境では唯一(というか、こいつのために使っているのだが).NET HttpWebRequest/HttpWebResponseを使ってサーバと通信するアプリケーションをテストしている際に「コネクションを切断された」という例外がスローされて接続を継続できないトラブルが発生した。(間にFiddlerを挟まなければ問題は発生しないのを確認している)

Exception: System.Net.WebException
Message: 基になる接続が閉じられました: 送信時に、予期しないエラーが発生しました。
Source: 〜
〜
Nested Exception

Exception: System.IO.IOException
Message: 転送接続にデータを書き込めません: 確立された接続がホスト コンピュータのソウトウェアによって中止されました。。
Source: System
   場所 System.Net.ConnectStream.InternalWrite(Boolean async, Byte buffer, Int32 offset, Int32 size, AsyncCallback callback, Object state)
   場所 System.Net.ConnectStream.Write(Byte buffer, Int32 offset, Int32 size)
   場所 System.IO.BufferedStream.FlushWrite()
   場所 System.IO.BufferedStream.Flush()
   場所 System.IO.BufferedStream.Dispose(Boolean disposing)
   場所 System.IO.Stream.Close()
   場所 System.IO.StreamWriter.Dispose(Boolean disposing)
   場所 System.IO.StreamWriter.Close()
   場所 System.Xml.XmlTextWriter.Close()
   場所 System.Xml.XmlWriter.Dispose(Boolean disposing)

元をただせばいわゆる、"Socket ErrorCode = 10053"だが、これは既知の問題のようでFiddler - Known Issuesにきちんと掲載されていた。

2 If you are debugging a .NET client and get the following exception: System.Net.WebException: The underlying connection was closed: A connection that was expected to be kept alive was closed by the server, click Rules > Customize Rules. Scroll down to the OnBeforeResponse handler and uncomment as directed.

原因までは書いていないので推測になるが、恐らくはHTTP1.1 Keep-Alive接続時に本来は接続が完了した際にサーバ側が送ってくるはずの"Connection: close"ヘッダが無いので、クライアント側は接続を持続しようとする -> サーバ側はKeep-Aliveタイムアウト等の事象が発生するので、強制的に切断 -> クライアント側で例外となるのではないか。

この問題をFIXする手順だが、Fiddlerのメニューから、Rules -> Customize Rules により開いた"CustomRules.js"のOnBeforeResponseメソッドで以下の行のコメントを外すだけだ。(以下は既にコメントを外した状態)

// Uncomment to reduce incidence of "unexpected socket closure" exceptions in .NET code.
// Note that you really should also fix your .NET code to gracefully handle unexpected connection closure.
//
if ((oSession.responseCode != 401) && (oSession.responseCode != 407)){
   oSession.oResponse["Connection"] = "close";
}

この修正により、レスポンスヘッダに強制的に"Connection: close"が付加されることで、例外がスローされなくなる。この例で解ると思うがプロキシとしての振る舞いをスクリプトで記述しているので、カスタマイズは自由自在だ。

このようにFiddlerは.NETを利用した道具はかくあるべき(ツール本体 + 公開されているアセンブリ)、という見本のようなツールだ。

追記:

トラックバックを頂いたInsideHTTP: New Fiddler Betas - 葉っぱ日記によると、最新のβ版では、"AutoResponder" と呼ばれる機能が追加されているようだ。こりゃまた便利。