-
Notifications
You must be signed in to change notification settings - Fork 0
MS_ISAPIandHttpPlatformHandler
- 戻る(IIS)
- IISの動作モデル
- IIS config
- ホストヘッダー
- ISAPI、HttpPlatformHandler
ISAPIと、HttpPlatformHandlerについて。
補足(この 2 つを並べる意味): 一見無関係に見えるが、
**どちらも「IIS に別の処理系を載せる仕組み」**であり、
世代が違うという関係にある。【第1世代】ISAPI(1996〜) … C/C++ の DLL を IIS に直接ロード ↓ 危険(プロセス内で動く)・作るのが大変 【第2世代】CGI / FastCGI … 別プロセス。パイプで通信 ↓ 遅い / Windows と相性が悪い 【第3世代】HttpPlatformHandler(2015) … 別プロセス。HTTP で通信 ↓ 【現在】 ASP.NET Core モジュール(ANCM) … 上記の後継。Kestrel を起動つまり、**「IIS 以外のもの(PHP、Node.js、Java、
ASP.NET Core)をどうやって IIS の下でホストするか」**という
一貫した課題への、時代ごとの回答が並んでいる。ISAPI 側は過去の遺産の理解として、
HttpPlatformHandler 側は現在の ANCM の前身として読むとよい
(IISの動作モデル)。
- DLL として IIS に直接ロードされるため、オーバーヘッドが少なく高性能・高機能
- 直接呼び出すこともスクリプトマッピングすることも可能。
以下のインターフェイスを実装(DLL なので以下の関数をエクスポート)
-
GetExtensionVersion
DLL の読み込み時に呼び出される。 -
HttpExtensionProc
HTTP リクエストを処理する。 -
TerminateExtension
DLL のアンロード時に呼び出される。
- (まだロードされていない場合)DLL をロード。
- ロード後、IIS は、
- DLL の
GetExtensionVersionメソッドを呼び出す。 -
EXTENSION_CONTROL_BLOCKを作成する。 -
HttpExtensionProcメソッドの引数に ECB のポインタを指定し呼び出す。
- DLL の
- ISAPI Extension DLL は、ECB を使用して処理を行う。
- ECB : Extension Control Block
- ECB には、以下が含まれる。
- 基本的なデータブロック
- QueryString, Method…
- データバッファとデータ長等
- 関数ポインタ
GetServerVariableWriteClientReadClientServerSupportFunction
- 基本的なデータブロック
移行メモ(体裁): 原典の「ECB には、如何含まれる含まれる。」は
「以下が含まれる。」の誤変換+重複であるため修正した。
補足(ISAPI が廃れた理由): 「オーバーヘッドが少なく高性能」という
利点は事実だが、それはIIS のプロセス内で直接動くことの裏返しでもある。
問題 内容 クラッシュが IIS を巻き込む ネイティブ コードのバグでワーカー プロセスごと落ちる メモリ リークが蓄積する プロセスが長時間動くため マルチスレッド前提 スレッド セーフに書く必要があり、難易度が高い 移植性が無い Windows / IIS 専用 開発コスト C/C++ で低レベルな API を扱う このため、
- 安全性を取るなら別プロセス(CGI / FastCGI / HttpPlatformHandler)、
- 生産性を取るならマネージド コード(ASP.NET の HttpHandler / HttpModule)
という方向に置き換わっていった。
現在 ISAPI の知識が必要になるのは、
- クラシック モードで動く古い ISAPI 拡張の保守、
aspnet_isapi.dllの挙動の理解
(クラシック モードでは ASP.NET 自体が ISAPI 拡張として動く)といった場面に限られる。
-
ISAPI エクステンションと並び、
IIS の早期のバージョンから実装されている API。 - 主に、HTTP のフィルタ、書き換え、HTTP 圧縮などを目的とした API。
- 以下のインターフェイスを実装(DLL なので以下の関数をエクスポート)
-
GetFilterVersion
DLL の読み込み時に呼び出される。 -
HttpFilterProc
通知ごとにそれぞれ特有のデータを受け取る。
戻り値でフィルターの動作を細かく制御できる。 -
TerminateFilter
DLL のアンロード時に呼び出される。
-
- ポイント
-
AllocMem- フィルタ内でメモリを割り当てるときは
AllocMemを使う -
AllocMemで割り当てたメモリは自動的に解放される
- フィルタ内でメモリを割り当てるときは
-
pFilterContext- 初期値は NULL
- ユーザーデータの格納場所
SF_STATUS_REQ_READ_NEXT
-
(記載なし)
| # | 通知 | 説明 |
|---|---|---|
| 1 | SF_NOTIFY_READ_RAW_DATA | クライアントが要求を送信した際。 |
| 2 | SF_NOTIFY_PREPROC_HEADERS | 各要求に対して発生。ヘッダーの前処理を完了後に発生。 |
| 3 | SF_NOTIFY_URL_MAP | 物理パスに変換しているときに発生。ヘッダーの前処理を完了後、1 回以上発生。 |
| 4 | SF_NOTIFY_AUTHENTICATION | 匿名リクエスト、authorization header を含むリクエストの度に発生。直後、IIS はクライアントの認証を試みる。 |
| 5 | SF_NOTIFY_AUTH_COMPLETE | 認証完了後に発生。HTTP メソッド、URL、バージョン、ヘッダの表示と変更が可能。 |
| 6 | SF_NOTIFY_READ_RAW_DATA ※ | チャンクなどで以降のクライアント・データを受信した際。 |
| 7 | SF_NOTIFY_SEND_RESPONSE | 要求が処理され、ヘッダがクライアントに返送される前に発生。 |
| 8 | SF_NOTIFY_SEND_RAW_DATA | クライアントにデータを返信した際。 |
| 9 | SF_NOTIFY_END_OF_REQUEST | 各要求の終わりに発生。HTTP 要求が完了した際。 |
| 10 | SF_NOTIFY_LOG | IIS がログに要求を書き込む直前に発生。 |
| 11 | SF_NOTIFY_END_OF_NET_SESSION | TCP/IP 接続が閉じられると発生 |
移行メモ(正誤): 原典の項番 4 の「リクエストの旅に発生」は
「リクエストの度に発生」の誤変換であるため修正した。
また、表の直後に「126/5000」「HTTP要求が完了し、」という
翻訳ツールの出力が混入したと思われる断片が残っていたため、
文意から項番 9 の説明に統合した。
- 戻り値
| # | 戻り値 | 説明 |
|---|---|---|
| 1 | SF_STATUS_REQ_FINISHED | フィルタが HTTP 要求を処理しました。サーバーはセッションを切断する必要があります。 |
| 2 | SF_STATUS_REQ_FINISHED_KEEP_CONN | #1 と同じだが、キープアライブの際は切断しない。 |
| 3 | SF_STATUS_REQ_NEXT_NOTIFICATION | 通知チェーンの次のフィルタを呼び出す。 |
| 4 | SF_STATUS_REQ_HANDLED_NOTIFICATION | このフィルタは通知の処理を完了(次のフィルタを呼び出さない) |
| 5 | SF_STATUS_REQ_ERROR | エラー発生。GetLastError でエラーをクライアントに通知。 |
| 6 | SF_STATUS_REQ_READ_NEXT | Raw 読み取り通知の場合にのみ有効。 |
補足(この通知一覧は「パイプラインの順序」を表している): 11 個の通知は
要求が処理される順序に並んでおり、
ASP.NET のHttpApplicationのイベントと対応する。
ISAPI フィルタの通知 ASP.NET の対応するイベント SF_NOTIFY_PREPROC_HEADERS BeginRequestSF_NOTIFY_AUTHENTICATION AuthenticateRequestSF_NOTIFY_AUTH_COMPLETE PostAuthenticateRequestSF_NOTIFY_URL_MAP MapRequestHandlerSF_NOTIFY_SEND_RESPONSE PreSendRequestHeadersSF_NOTIFY_END_OF_REQUEST EndRequestSF_NOTIFY_LOG LogRequest統合モードでネイティブ モジュールとマネージド モジュールが
混在できるのは、この順序が 1 本に統合されたからである
(IISの動作モデル)。したがって、現在 ISAPI フィルタでやっていたことは、
用途 現在の手段 URL 書き換え URL Rewrite モジュール(設定のみ) 認証の差し込み HttpModule HTTP 圧縮 IIS の標準機能(動的圧縮/静的圧縮) ログの加工 高度なログ、カスタム フィールド で代替でき、新規に ISAPI フィルタを書く理由はほぼ無い。
- 「統合モード」の動作モデルで動作する。
-
ARRに似ているが、
- リモート・サーバーではなく、特定のアウト・プロセスのみを対象にしている。
アウト・プロセス(指定された実行ファイルのプロセス)の管理までを行う。 - プロキシでは無いので、HTTPS トラフィックは全て HTTP にオフロードされて渡される。
- リモート・サーバーではなく、特定のアウト・プロセスのみを対象にしている。
- CGI / FastCGI にも似ているが、
- FastCGI(NamedPipe or TCP)に近い用途だが、HTTP を使用する。
- CGI / FastCGI よりも実用的なパフォーマンスを出せる
補足(この 3 者の比較が本節の要点): 「ARR に似ている」「CGI に似ている」と
2 方向から説明されているが、表にすると位置付けが明確になる。
ARR FastCGI HttpPlatformHandler 転送先 リモート サーバ ローカルの別プロセス ローカルの別プロセス プロトコル HTTP FastCGI(独自バイナリ) HTTP プロセスの起動・管理 しない(相手は既に動いている) する する 主な用途 負荷分散、リバース プロキシ PHP Node.js、Java、Python、ASP.NET Core つまり HttpPlatformHandler は
**「ARR のプロトコル(HTTP)+ FastCGI のプロセス管理」**という
組み合わせである。HTTP を使う利点は大きく、
- 相手が普通の Web サーバでよい(Node.js の
http.createServer等がそのまま使える)、- デバッグしやすい(HTTP なので中身が見える)、
- 言語・処理系を選ばない
という汎用性を得た。
これが後の **ASP.NET Core モジュール(ANCM)**に繋がる。なお「HTTPS が HTTP にオフロードされる」点は重要で、
影響 対処 アプリ側からは HTTP に見える X-Forwarded-Protoヘッダーで判定するリダイレクト URL が http://になる転送ヘッダーの処理を有効化 クライアント IP が取れない X-Forwarded-Forを見るASP.NET Core では
ForwardedHeadersミドルウェアが
この処理を担当する。
HttpApplication(Global.asax)、HttpModule、HttpHandlerを参照。
- パス指定(基本的には、全てのパス)
- HTTP メソッドを指定(基本的には、全ての HTTP メソッド)
- 起動する実行ファイルを指定。
Web.configに設定を行う。
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<handlers>
<add name="httpPlatformHandler" path="*" verb="*" modules="httpPlatformHandler" resourceType="Unspecified" />
</handlers>
<httpPlatform processPath="startup.bat" arguments="">
<environmentVariables>
<environmentVariable name="PORT" value="%HTTP_PLATFORM_PORT%" />
</environmentVariables>
</httpPlatform>
</system.webServer>
</configuration>補足(
%HTTP_PLATFORM_PORT%が仕組みの核心): このテンプレートで
最も重要なのは環境変数HTTP_PLATFORM_PORTである。① IIS が空いているポートを 1 つ選ぶ(例: 30125) ② 環境変数 HTTP_PLATFORM_PORT=30125 を設定して子プロセスを起動 ③ 子プロセス(アプリ)は、そのポートで listen する ④ IIS は受け取った要求を http://localhost:30125/ へ転送するつまり、ポート番号を固定で決め打ちしないという設計であり、
これにより
- 同一サーバで複数のアプリを共存できる(ポート衝突しない)、
- アプリ プールのリサイクル時も自動で追随する
という利点が得られる。
アプリ側は
この環境変数を読んで listen ポートを決める必要がある。
ASP.NET Core ではUseIISIntegration()(または ANCM)が
自動的にこれを処理する。
- handlers - add 要素
-
processPath
起動する実行ファイル -
arguments
実行ファイルに渡されるコマンドライン引数 -
startupTimeLimit
起動完了までの最大時間 -
startupRetryCount
起動失敗時のリトライ回数 -
requestTimeout
HTTP リクエストのタイムアウト時間 -
rapidFailsPerMinute
ラピッドフェール保護されるまでの失敗回数/分 -
stdoutLogEnabled
標準出力、標準エラー出力のログ保存 -
stdoutLogFile
ログファイルのパス
-
- httpPlatform 要素
- environmentVariables - environmentVariable 要素
- ポート番号
- リモートデバッグ用ポート番号
- environmentVariables - environmentVariable 要素
移行メモ(構成): 原典では
processPath以下の設定項目が
「handlers - add 要素」の配下に列挙されていたが、
テンプレートを見れば分かるとおり
これらはhttpPlatform要素の属性である。
原典どおりの構成で移行したが、実際の記述位置に注意が要る。
補足(
stdoutLogEnabledは障害調査の生命線): 別プロセスで動く以上、
アプリが起動に失敗しても IIS 側には理由が分からない。
ブラウザにはHTTP Error 502.5 - Process Failureのような素っ気ないエラーしか出ない。
このとき、
stdoutLogEnabled="true"にしておけば、
アプリが標準出力/標準エラーに出した内容
(例外のスタック トレース、設定ファイルの読み込み失敗など)が
ファイルに残る。原因はほぼここに書かれている。注意点として、
注意 内容 ログ フォルダを事前に作る 無いと出力されない 書き込み権限 アプリ プールの ID に必要 本番では無効に戻す ファイルが際限なく増える がある。恒久的な有効化ではなく、障害時に一時的に有効化するのが正しい。
ASP.NET をホストするワーカープロセスである w3wp.exe を processPath に指定できない模様。
(ASP.NET の中では HttpPlatformHandler を使用できないので、潔く HttpHandler(HttpApplication(Global.asax)、HttpModule、HttpHandler)を使用する。)
補足(最新化:HttpPlatformHandler の後継): HttpPlatformHandler は
**ASP.NET Core モジュール(ANCM)**に発展的に置き換わった。
HttpPlatformHandler ASP.NET Core モジュール(ANCM) 対象 任意の実行ファイル ASP.NET Core に特化 ホスティング アウトプロセスのみ インプロセス(既定)/アウトプロセス 性能 プロセス間 HTTP のホップあり インプロセスならホップ無し 現状 保守のみ 現行 ANCM のインプロセス ホスティングでは、
w3wp.exeの中で Kestrel が動く。
本文の「w3wp.exeをprocessPathに指定できない」という制約が、
別の方式で解決された格好になる。一方、PHP / Node.js / Java を IIS でホストしたい場合は、
HttpPlatformHandler が今も使える
(PHP は FastCGI、Node.js は iisnode という選択肢もある)。
- ISAPI - Wikipedia
https://ja.wikipedia.org/wiki/ISAPI - HttpPlatformHandler を使用する
https://technet.microsoft.com/ja-jp/library/mt125371.aspx
- ネイティブコード API を用いた開発
http://keicode.com/iis/index4.php- ISAPI エクステンション (拡張) 概要
http://keicode.com/iis/iis-isapi-extension-overview.php - ISAPI フィルタ概要
http://keicode.com/iis/iis-isapi-filter-overview.php- ISAPI フィルタによるログの書き換え
http://keicode.com/iis/isapi-filter-log-change.php - カスタムの ISAPI Extension を利用する方法 (IIS7 on Windows Vista)
http://keicode.com/iis/iis02.php
- ISAPI フィルタによるログの書き換え
- ISAPI エクステンション (拡張) 概要
- httpPlatformHandler をもっと面白く使っていきたい
http://blog.shibayan.jp/entry/20150107/1420604057 - HttpPlatformHandler が IIS 8 以降の拡張機能として正式にリリースされていました
http://blog.shibayan.jp/entry/20150128/1422429554
HttpApplication(Global.asax)、HttpModule、HttpHandler
Tags: 移行, Windows, IIS
このWikiは「Open棟梁Project」,「OSSコンソーシアム 開発基盤部会」によって運営されています。