<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Hopes

    Start Here..

     

    轉(zhuǎn) IIS的ISAPI接口簡介

    IIS的ISAPI接口簡介

    摘要:IIS的ISAPI接口簡介


    ISAPI(Internet Server Application Programming Interface)作為一種可用來替代CGI的方法,是由微軟和Process軟件公司聯(lián)合提出的Web服務(wù)器上的API標(biāo)準(zhǔn)。ISAPI與Web服務(wù)器結(jié)合緊密,功能強(qiáng)大,能夠獲得大量的信息,因此利用ISAPI可以開發(fā)出靈活高效的Web服務(wù)器增強(qiáng)程序。由于ISAPI程序與Web服務(wù)器的關(guān)系,使得ISAPI接口在安全方面有一定的研究價(jià)值。本文主要討論ISAPI在IIS和VC++ 6.0中的實(shí)現(xiàn)。

    一、ISAPI接口和CGI接口的不同。

    ISAPI程序和CGI程序完成類似的功能,但是實(shí)現(xiàn)方法不同。

    1、ISAPI程序以DLL形式被Web服務(wù)器加載到自己的進(jìn)程空間中,因此和服務(wù)器共用同一個(gè)地址空間,且在沒有客戶請求時(shí)可以將其從內(nèi)存中卸載;而對(duì)客戶端發(fā)來的每個(gè)對(duì)CGI程序的請求則需要服務(wù)器為它單獨(dú)啟動(dòng)一個(gè)進(jìn)程,這需要耗費(fèi)大量的時(shí)間和內(nèi)存。當(dāng)并發(fā)的請求數(shù)目很大時(shí),使用CGI在效率上不如ISAPI。

    2、CGI程序通過環(huán)境塊和標(biāo)準(zhǔn)輸入輸出與Web服務(wù)器進(jìn)行通信,而ISAPI程序與服務(wù)器結(jié)合得更為緊密,與服務(wù)器共享同一個(gè)進(jìn)程上下文,主要通過一個(gè)參數(shù)塊與服務(wù)器進(jìn)行交互,可以從服務(wù)器那里獲得關(guān)于當(dāng)前HTTP連接的大量信息。

    ISAPI主要分為ISA和ISAPI Filter兩部分。ISA方法相對(duì)而言要傳統(tǒng)一些,利用一些特殊的鏈接,指向服務(wù)器的作業(yè),供程序開發(fā)人員設(shè)計(jì)一些擴(kuò)展功能;而ISAPI過濾器則傾向于構(gòu)造服務(wù)器直接調(diào)用的模塊,提供一種無縫鏈接部件用于監(jiān)測直接來自于服務(wù)器的HTTP請求。


    二、ISA

    ISA(Internet Server Application)也可稱為ISAPI DLL,其功能和CGI程序的功能直接相對(duì)應(yīng),使用方法和CGI也類似,由客戶端在URL中指定其名稱而激活。例如下面的請求將調(diào)用服務(wù)器的虛擬可執(zhí)行目錄Scripts下的function.dll(ISAPI DLL必須放在服務(wù)器的虛擬可執(zhí)行目錄下):
    http://www.abc.com/Scripts/function.dll?

    ISA和服務(wù)器之間的接口主要有兩個(gè):GetExtentionVersion( )和HttpExtentionProc( )。任何ISA都必須在其PE文件頭的引出表中定義這兩個(gè)引出函數(shù),以供Web服務(wù)器在適當(dāng)?shù)臅r(shí)候調(diào)用。

    1、當(dāng)服務(wù)器剛加載ISA時(shí),它會(huì)調(diào)用ISA提供的GetExtentionVersion( )來獲得該ISA所需要的服務(wù)器版本,并與自己的版本相比較,以保證版本兼容。函數(shù)原型如下:

    BOOL WINAPI GetExtentionVersion(HSE_VERSION_INFO *version);
    typedef struct _HSE_VERSION_INFO
    {
    DWORD dwExtensionVersion; //版本號(hào)
    CHAR lpszExtensionDesc[HSE_MAX_EXT_DLL_NAME_LEN]; //關(guān)于ISA的描述字符串
    } HSE_VERSION_INFO, *LPHSE_VERSION_INFO;

    2、ISA的真正入口是HttpExtentionProc( ),它相當(dāng)于普通C程序的main( )函數(shù),在這個(gè)函數(shù)中根據(jù)不同的客戶請求作不同的處理。服務(wù)器和HttpExtentionProc( )之間是通過擴(kuò)展控制塊(Extention Control Block)來進(jìn)行通信的,即ECB中存放入口參數(shù)和出口參數(shù),包括服務(wù)器提供的幾個(gè)回調(diào)函數(shù)的入口地址。函數(shù)原型如下:

    DWORD HttpExtensionProc( EXTENSION_CONTROL_BLOCK *pECB );

    ECB的結(jié)構(gòu)定義如下(IN表示入口參數(shù),OUT表示出口參數(shù)):

    typedef struct _EXTENSION_CONTROL_BLOCK
    {
    DWORD cbSize; //IN,本結(jié)構(gòu)的大小,只讀
    DWORD dwVersion //IN,版本號(hào),高16位為主版本號(hào),低16位為次版本號(hào)
    HCONN ConnID; //IN,連接句柄,由服務(wù)器分配,ISA只能讀取該值
    DWORD dwHttpStatusCode; //OUT,當(dāng)前完成的事務(wù)狀態(tài)
    CHAR lpszLogData[HSE_LOG_BUFFER_LEN]; //OUT,需要寫入到日志文件中的內(nèi)容
    LPSTR lpszMethod; //IN,等價(jià)于CGI的環(huán)境變量REQUEST_METHOD
    LPSTR lpszQueryString; //IN,等價(jià)于環(huán)境變量QUERY_STRING
    LPSTR lpszPathInfo; //IN,等價(jià)于環(huán)境變量PATH_INFO
    LPSTR lpszPathTranslated; //IN,等價(jià)于環(huán)境變量PATH_TRANSLATED
    DWORD cbTotalBytes; //IN,等價(jià)于環(huán)境變量CONTENT_LENGTH
    DWORD cbAvailable; //IN,緩沖區(qū)中的可用字節(jié)數(shù)
    LPBYTE lpbData; //IN,緩沖區(qū)指針,指向客戶端發(fā)來的數(shù)據(jù)
    LPSTR lpszContentType; //IN,等價(jià)于環(huán)境變量CONTENT_TYPE

    //回調(diào)函數(shù),用于返回服務(wù)器的連接信息或特定的服務(wù)器詳細(xì)情況
    BOOL ( WINAPI * GetServerVariable )
    ( HCONN hConn,
    LPSTR lpszVariableName,
    LPVOID lpvBuffer,
    LPDWORD lpdwSize );

    BOOL ( WINAPI * WriteClient ) //回調(diào)函數(shù),從客戶端的HTTP請求中讀取數(shù)據(jù)
    ( HCONN ConnID,
    LPVOID Buffer,
    LPDWORD lpdwBytes,
    DWORD dwReserved );

    BOOL ( WINAPI * ReadClient ) //回調(diào)函數(shù),向客戶端發(fā)送數(shù)據(jù)
    ( HCONN ConnID,
    LPVOID lpvBuffer,
    LPDWORD lpdwSize );

    BOOL ( WINAPI * ServerSupportFunction ) //回調(diào)函數(shù),訪問服務(wù)器的一般和特定功能
    ( HCONN hConn,
    DWORD dwHSERRequest,
    LPVOID lpvBuffer,
    LPDWORD lpdwSize,
    LPDWORD lpdwDataType );

    } EXTENSION_CONTROL_BLOCK, *LPEXTENSION_CONTROL_BLOCK;

    在上述ECB中,服務(wù)器不但提供了當(dāng)前HTTP連接的句柄和一些變量,而且提供了4個(gè)回調(diào)函數(shù)給ISA調(diào)用,從而使ISA可以獲得更詳盡的信息。

    三、ISAPI Filter

    ISAPI Filter位于服務(wù)器和客戶端之間,能夠?qū)Ψ?wù)器和客戶端之間的通信進(jìn)行預(yù)處理和后處理,比如對(duì)通信進(jìn)行加密/解密、提供對(duì)客戶進(jìn)行身份驗(yàn)證的新方法、提供自定義的日志記錄等,在CGI中沒有與ISAPI Filter直接相對(duì)應(yīng)的部分。

    ISAPI Filter與服務(wù)器之間的接口有兩個(gè):GetFilterVersion( )和HttpFilterProc( )。任何
    ISAPI Filter都必須引出這兩個(gè)函數(shù)以供服務(wù)器調(diào)用。

    1、在注冊表的如下鍵值中存放著所有ISAPI Filter的文件名,IIS服務(wù)器啟動(dòng)時(shí)從該鍵值中獲得
    Filter的文件名并加載它們。

    HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/W3SVC/Parameters/FilterDLL

    2、然后服務(wù)器調(diào)用每個(gè)Filter提供的GetFilterVersion( )函數(shù),獲得版本號(hào)以及該Filter希望處理的事件,即ISAPI Filter通過引出GetFilterVersion( )函數(shù)來告知服務(wù)器自己希望處理什么類型的事件,因?yàn)镮SAPI Filter是通過事件來激活的,當(dāng)滿足條件的事件到達(dá)時(shí),服務(wù)器就會(huì)調(diào)用Filter引出的主函數(shù)HttpFilterProc( )對(duì)該事件進(jìn)行處理。GetFilterVersion( )的原型如下:

    BOOL WINAPI GetFilterVersion(
    DWORD dwServerFilterVersion; //IN,服務(wù)器使用的版本規(guī)范
    DWORD dwFilterVersion; //OUT,過濾器使用的版本規(guī)范
    CHAR lpszFilterDesc[SF_MAX_FILTER_DESC_LEN+1]; //OUT,對(duì)該過濾器的描述字符串
    DWORD dwFlags //OUT,事件和優(yōu)先級(jí)標(biāo)志
    );

    事件和優(yōu)先級(jí)標(biāo)志dwFlasg的取值在MSDN中有詳細(xì)解釋,其中包括該Filter被調(diào)用的優(yōu)先級(jí),一般應(yīng)使用默認(rèn)的低優(yōu)先級(jí),否則可能會(huì)對(duì)系統(tǒng)的性能造成很大影響。

    3、HttpFilterProc( )是ISAPI Filter主要的入口函數(shù),它根據(jù)當(dāng)前的事件的不同作出不同的處理。服務(wù)器通過如下的參數(shù)塊和Filter進(jìn)行交互,這個(gè)參數(shù)塊的作用和ISA中的ECB類似。

    typedef struct _HTTP_FILTER_CONTEXT
    {

    DWORD cbSize; //IN,本參數(shù)塊的大小
    DWORD Revision; //IN
    PVOID ServerContext; //IN,由server使用本參數(shù)
    DWORD ulReserved; //IN,由server使用本參數(shù)
    BOOL fIsSecurePort; //IN,事件是否發(fā)生在安全端口上
    PVOID pFilterContext; //IN/OUT,與本次請求相關(guān)的上下文

    //回調(diào)函數(shù),取得關(guān)于服務(wù)器和本次連接的信息
    BOOL (WINAPI * GetServerVariable) (
    struct _HTTP_FILTER_CONTEXT * pfc,
    LPSTR lpszVariableName,
    LPVOID lpvBuffer,
    LPDWORD lpdwSize
    );

    BOOL (WINAPI * AddResponseHeaders) ( //回調(diào)函數(shù),給HTTP響應(yīng)添加一個(gè)標(biāo)頭
    struct _HTTP_FILTER_CONTEXT * pfc,
    LPSTR lpszHeaders,
    DWORD dwReserved
    );

    BOOL (WINAPI * WriteClient) ( //回調(diào)函數(shù),將原始數(shù)據(jù)發(fā)送給客戶端
    struct _HTTP_FILTER_CONTEXT * pfc,
    LPVOID Buffer,
    LPDWORD lpdwBytes,
    DWORD dwReserved
    );

    VOID * (WINAPI * AllocMem) ( //回調(diào)函數(shù),分配內(nèi)存。
    struct _HTTP_FILTER_CONTEXT * pfc,
    DWORD cbSize,
    DWORD dwReserved
    );

    BOOL (WINAPI * ServerSupportFunction) ( //回調(diào)函數(shù),訪問服務(wù)器的一般和特定功能
    struct _HTTP_FILTER_CONTEXT * pfc,
    enum SF_REQ_TYPE sfReq,
    PVOID pData,
    DWORD ul1,
    DWORD ul2
    );

    } HTTP_FILTER_CONTEXT, *PHTTP_FILTER_CONTEXT;

    四、VC++ 6.0中對(duì)ISAPI的支持

    VC++ 6.0中定義了5個(gè)相關(guān)的類以簡化ISAPI的編程工作:CHttpServer、CHttpServerContext、CHttpFilter、CHttpFilterContext、CHtmlStream,這5個(gè)類都沒有父類。其中CHttpServer和CHttpServerContext主要用來編寫ISA,CHttpFilter和CHttpFilterContext則用來編寫ISAPI Filter,而CHtmlStream則用來操作內(nèi)存中的HTML文件,為其它的4個(gè)類提供服務(wù)。CHttpServer在每個(gè)ISA中只能有一個(gè)實(shí)例,一個(gè)CHttpServer可以對(duì)應(yīng)多個(gè)CHttpServerContext實(shí)例,每個(gè)
    CHttpServerContext處理一個(gè)客戶請求,這樣可以處理并發(fā)的HTTP請求;CttpFilter和CHttpFilterContext之間的關(guān)系與此類似,在每個(gè)ISAPI Filter中只能有一個(gè)CHttpFilter實(shí)例,但是可以有多個(gè)CHttpFilterContext來處理并發(fā)的事件。CHttpServer和CHttpFilter是獨(dú)立的類,它們可以共存于一個(gè)DLL中,也可以分別在不同的DLL中。

    一個(gè)ISA可以提供多個(gè)命令,每個(gè)命令對(duì)應(yīng)于CHttpServer(或其子類)的一個(gè)成員函數(shù),客戶端可以在URL中指定命令名及其參數(shù)。在VC++ 6.0中是通過parse map來實(shí)現(xiàn)這種對(duì)應(yīng)的。

    Parse map類似MFC中的Windows消息分發(fā)機(jī)制,通過使用VC提供的DECLARE_PARSE_MAP、BEGIN_PARSE_MAP、ON_PARSE_COMMAND、ON_PARSE_COMMAND_PARAMS、DEFAULT_PARSE_COMMAND、END_PARSE_MAP等宏,可以實(shí)現(xiàn)對(duì)不同的命令的處理。每個(gè)CHttpServer中只能建立一個(gè)parse map,當(dāng)客戶端給ISA發(fā)來命令的時(shí)候,parse map可以分析HTTP請求中的命令名及其參數(shù),將該命令與相應(yīng)的成員函數(shù)關(guān)聯(lián)起來,即由該成員函數(shù)處理該命令。以MSDN中的例子程序pinball為例,該例中有下面這樣一個(gè)表單:

    <form method=get action="pinball.dll?">
    <input type="hidden" name="MfcISAPICommand" VALUE="GetImage">
    <input type="radio" name="Favorite" value="1" checked> Attack from Mars<br>
    <input type="radio" name="Favorite" value="2"> Twilight Zone<br>
    <input type="radio" name="Favorite" value="3"> The Addams Family<br>
    <input type="radio" name="Favorite" value="4"> Cirqus Voltaire<br>
    <input type="radio" name="Favorite" value="0"> I don't see it here<br>
    <br>
    <input type="submit" value="Show Me!">
    </form>

    當(dāng)客戶端選中了上面的表單中的“Attack from Mars”這一項(xiàng)并點(diǎn)擊了submit按鈕后,服務(wù)器端
    最終將得到如下的URL串:

    http://www.abc.com/pinball.dll?MfcISAPICommand=GetImage&Favorite=1

    在該URL串中,命令名是GetImage,參數(shù)Favorite的值是1,因此pinball.dll中的如下成員函數(shù)
    將被調(diào)用以處理該請求,其中參數(shù)dwChoice對(duì)應(yīng)URL中的參數(shù)Favorite:

    void CPinballExtension::GetImage(CHttpServerContext* pCtxt, long dwChoice);

    而parse map需要按照下面的形式定義:

    //CPinballExtension從CHttpServer派生而來
    BEGIN_PARSE_MAP(CPinballExtension, CHttpServer)

    //GetImage是CPinballExtension的成員函數(shù),且有一個(gè)long型的參數(shù)即dwChoice
    ON_PARSE_COMMAND(GetImage, CPinballExtension, ITS_I4)

    //該參數(shù)在URL中的名字為Favorite
    ON_PARSE_COMMAND_PARAMS("Favorite")

    END_PARSE_MAP(CPinballExtension)

    而對(duì)于ISAPI Filter,在VC中可以通過重載CHttpFilter(或其子類)的不同的成員函數(shù)來實(shí)現(xiàn)對(duì)不同事件的處理。可重載的函數(shù)如下,每一個(gè)成員函數(shù)均對(duì)應(yīng)一個(gè)或多個(gè)事件:

    OnPreprocHeaders
    OnAuthentication
    OnUrlMap
    OnSendRawData
    OnReadRawData
    OnLog
    OnEndOfNetSession

    MSDN提供了4個(gè)關(guān)于ISAPI的編程實(shí)例:counter、MFCUCASE、pinball、wwwquote,有興趣的可看看,本文主要不是介紹編程,所以不再贅述。

    參考資料:

    1、MSDN
    2、《精通CGI編程》,丁一強(qiáng)等,清華大學(xué)出版社

    posted on 2012-12-29 11:08 ** 閱讀(193) 評(píng)論(0)  編輯  收藏


    只有注冊用戶登錄后才能發(fā)表評(píng)論。


    網(wǎng)站導(dǎo)航:
     

    導(dǎo)航

    統(tǒng)計(jì)

    公告

    你好!

    常用鏈接

    留言簿(2)

    隨筆檔案

    文章分類

    文章檔案

    新聞檔案

    相冊

    收藏夾

    C#學(xué)習(xí)

    友情鏈接

    搜索

    最新評(píng)論

    閱讀排行榜

    評(píng)論排行榜

    主站蜘蛛池模板: 浮力影院第一页小视频国产在线观看免费 | 亚洲伊人久久综合影院| 亚洲最大中文字幕无码网站| 四虎免费影院ww4164h| 亚洲第一网站免费视频| 97公开免费视频| 亚洲精品资源在线| 亚洲成人免费电影| 亚洲国产美女在线观看| 久视频精品免费观看99| 久久精品国产亚洲AV蜜臀色欲| 国产精品久久永久免费| 国产成人精品日本亚洲11| 免费人成在线视频| 亚洲av中文无码字幕色不卡| 免费在线看片网站| 国产成人高清精品免费观看| 久久99国产亚洲高清观看首页| 国产成人久久AV免费| 亚洲视频手机在线| 天天摸天天碰成人免费视频| 久久精品亚洲日本波多野结衣| 波多野结衣一区二区免费视频| 日韩精品视频在线观看免费| 亚洲国产综合无码一区| 99久久99久久精品免费看蜜桃 | 亚洲av无码一区二区三区四区 | 8x8x华人永久免费视频| 亚洲一区二区三区写真| 亚洲国产成人久久一区WWW| 国产羞羞的视频在线观看免费| 亚洲精品美女久久久久9999| 国产成人免费片在线视频观看| 国产免费久久精品丫丫| 亚洲第一二三四区| 国产乱人免费视频| 四虎国产成人永久精品免费| 亚洲日韩国产一区二区三区在线| 亚洲中文字幕日产乱码高清app | 国产在线98福利播放视频免费| 国产婷婷成人久久Av免费高清|