.NET Frameworkでは、IHttpModuleを実装すると、IISを通過するリクエストやレスポンスを操作できるモジュールを作成できます。
たとえば、リクエストに合わせてレスポンス内容を変化させるなんてことも・・・
そう、いつも通り簡単にできるだろうと思っていました。
HttpResponse.OutputStreamの中にはレスポンスコンテンツが蓄えられるはずです。
これを読み取って、書き換えてしまえばよい、そう思っていました・・・
HttpResponse.OutputStreamは出力(書き込み)専用のStreamであり、読むことは不可能です。
即ち、レスポンス内容の一部の書き換えは不可能・・・
ハンドラでなければレスポンス書き換えできないのでしょうか。
んなわきゃありません。
IIS 7.0 における ASP.NET アプリケーションのライフ サイクルの概要を参照しますと、HttpApplicationパイプラインの処理で
19. Filter プロパティが定義されている場合は、応答フィルタ処理を実行します。
とあるのを発見しました。
そうです、モジュールはフィルタではなかったわけです。
では、Filterとは何かというと、Streamなわけですが、これのつくり方もよくわかりませんでしたが、参考になるものが[ASP.NET]Webページに含まれるリンクを動的に変更するには?[C#、VB]にありましたので、活用します。
しかし、文字単位で書き換えるなどバッファの切れ目を考えなかったり、たとえばソースコードのコンパイルを動的に実行したい場合などには不向きです。
画像コンテンツなどバイナリの書き換えにも不向きです。
そこで、フィルタ用StreamクラスにMemoryStreamを1つ、バッファとして用意し、そこに書き込み、Flush時に実際に書き込みを実行します。
たとえば、上記のようなStreamフィルタをモジュールのBeginRequestなどでnewすれば、htmlコンテンツの文字列を書き換えることが可能になります。
#Flush時MemoryStreamを解放すべきかも知れません。
注意すべきはFilterをチェイン化するところと、実際のレスポンスはHTTPヘッダ等も含めてBeginRequest時には確定していないという点です。
#PostRequestHandlerExecute時にはほぼ確定しているようですが、フィルタチェインによってはイベント時とは異なるConetent-Type等になる場合もありそうです(未確認)。
あとは、モジュールをサイトやアプリケーションに登録すれば、たとえ静的なコンテンツでも、意図したとおり、自由に書き換えることができるようになります。
そして、エンドツーエンドの拡張性を持つ Web サーバー ソリューションを構築するにあるようなさらなる拡張性を持たせることができれば、より簡単に操作できると思われます。
コメントしちゃいなよ