动漫av纯肉无码国产av-动漫av永久无码精品每日更新-动漫av专区-动漫h精品无码一区二区三区-动漫成人-动漫成人无码精品一区二区三区

LOGO OA教程 ERP教程 模切知識(shí)交流 PMS教程 CRM教程 開發(fā)文檔 其他文檔  
 
網(wǎng)站管理員

[點(diǎn)晴永久免費(fèi)OA]使用ISAPI過濾器開發(fā)來增強(qiáng)Windows Server服務(wù)器IIS的功能

admin
2024年7月5日 18:45 本文熱度 1634

作為一個(gè)WWW服務(wù)器(WEB)軟件,微軟公司的Internet Infomation Server(IIS)簡(jiǎn)單易學(xué),管理方便,得到了廣泛的使用。您還可以通過ISAPI過濾器,進(jìn)行自己定制的處理,來增強(qiáng)IIS的功能。ISAPI過濾器可以定制以下的處理:接收HTTP協(xié)議頭預(yù)處理、發(fā)送HTTP協(xié)議頭預(yù)處理、發(fā)送生數(shù)據(jù)預(yù)處理、獲得生數(shù)據(jù)預(yù)處理、HTTP會(huì)話結(jié)束信息處理、自定義的安全認(rèn)證機(jī)制、URL映射信息處理、日志記錄處理等。靈活利用這些定制處理,您可以完成許多看似難以實(shí)現(xiàn)的功能,得到意想不到的效果。但是ISAPI過濾器使用不當(dāng)也會(huì)影響服務(wù)器的性能。

ISAPI開發(fā)概述

ISAPI可以完成很多功能,asp.net的實(shí)現(xiàn)底層也是通過isapi來解析asp.net的代碼的。
通過開發(fā)isapi,然后在iis中配置后可以解析不同的文件。
比如java,perl的代碼也可以通過加載isapi的方式在iis中進(jìn)行訪問

ISAPI兩種開發(fā)方式:擴(kuò)展(如:aspnet_isapi.dll)和過濾(如:aspnet_filter.dll)

過濾可以實(shí)現(xiàn)許多功能,比如將簡(jiǎn)體轉(zhuǎn)成繁體,大小寫轉(zhuǎn)換等, 參見UpCase

引用: 

在 Microsoft Visual Studio 2005, 中創(chuàng)建新項(xiàng)目時(shí)在 新建項(xiàng)目 對(duì)話框中沒有找到 VisualC++ 下 MFC ISAPI Extension DLL 模板。

因?yàn)?nbsp;Microsoft 已刪除 MFC ISAPI Extension DLL 模板為 Visual Studio 2005 發(fā)生此行為。

用于新 ISAPI 篩選或擴(kuò)展開發(fā), 我們建議您使用 MicrosoftInternet 信息服務(wù) (IIS) 軟件開發(fā)工具包 (SDK) 中 ISAPI 入口 - Point 函數(shù)代替 MFC ISAPI 類。 Microsoft Windows Server 2003 Service Pack 1 (SP 1) 平臺(tái) SDK 包括許多 ISAPI 示例。 請(qǐng)以獲取 PlatformSDK, 訪問以下 MicrosoftWeb 站點(diǎn):

http://www.microsoft.com/downloads/details.aspx?FamilyID=eba0128f-a770-45f1-86f3-7ab010b398a3&DisplayLang=en (http://www.microsoft.com/downloads/details.aspx?FamilyID=eba0128f-a770-45f1-86f3-7ab010b398a3&DisplayLang=en)

注意 時(shí)間少, 必須安裝 Microsoft Windows 核心 SDK 和 IIS SDK。 

默認(rèn)情況下, 從 SDK ISAPI 示例位于以下文件夾:

程序 Files\Microsoft 平臺(tái) SDK\Samples\Web\iis

有關(guān)如何創(chuàng)建 ISAPI 篩選器和擴(kuò)展, 請(qǐng)?jiān)L問以下 Microsoft Developer Network (MSDN) 網(wǎng)站:

最主要的代碼如下:

  1  DWORD WINAPI __stdcall HttpFilterProc(HTTP_FILTER_CONTEXT  * pfc, DWORD NotificationType, VOID  * pvData)
  2  {
  3    CHAR *pchIn, *pPhysPath;
  4    DWORD    cbBuffer,    cbtemp;
  5    PHTTP_FILTER_URL_MAP pURLMap;
  6    PHTTP_FILTER_RAW_DATA    pRawData;
  7
  8    switch (NotificationType)    {
  9
 10        case SF_NOTIFY_URL_MAP :
 11
 12            /* Check the URL for a subdirectory in the form of /UC/ or /uc/ */
 13
 14            pURLMap    =    (PHTTP_FILTER_URL_MAP)pvData;
 15
 16            pPhysPath    =    pURLMap->pszPhysicalPath;
 17
 18            pfc->pFilterContext    =    0;
 19
 20            for (  *pPhysPath; pPhysPath++) 
 21            {
 22                /* Ensure that there are at least 4 characters (checking for "\UC\") left in the URL before checking */
 23
 24                if (strlen(pPhysPath) > 3) 
 25                {
 26                    if (*pPhysPath == '\\' && (*(pPhysPath + 1) == 'u' || *(pPhysPath + 1) == 'U') && (*(pPhysPath + 2) == 'c' || *(pPhysPath + 2) == 'C') && *(pPhysPath + 3) ==    '\\')
 27                    {
 28                        /* Now that we've found it, remove it by collapsing everything down */
 29
 30                        for (  *(pPhysPath + 3)  pPhysPath++)
 31                            *pPhysPath = *(pPhysPath + 3);
 32
 33                        /* NULL terminate the string */
 34
 35                        *pPhysPath = '\0'; 
 36
 37                        /* And set the flag to let the SF_NOTIFY_SEND_RAW_DATA handler know to uppercase the content */
 38
 39                        pfc->pFilterContext    =    (VOID    *)1;
 40
 41                        /* Break us out of the loop - note that this will only find the first instance of /UC/ in the URL */
 42
 43                        break;
 44                    }

 45                }

 46            }

 47
 48            break;
 49
 50        case SF_NOTIFY_SEND_RAW_DATA :
 51
 52            if (pfc->pFilterContext)
 53            {
 54                pRawData = (PHTTP_FILTER_RAW_DATA)pvData;
 55
 56                pchIn    =    (BYTE    *)pRawData->pvInData;
 57
 58                cbBuffer = 0;
 59
 60                if (pfc->pFilterContext    == (VOID *)1)
 61                {
 62                    /* 
 63                    As this is the first block, scan through it until 2 CRLFs are seen, to pass
 64                    all of the headers.
 65                    */

 66
 67                    for (  cbBuffer < pRawData->cbInData - 2; cbBuffer++)
 68                    {
 69                        if (pchIn[cbBuffer]    == '\n' && pchIn[cbBuffer + 2]    == '\n')
 70                        {
 71                            cbBuffer += 3;
 72
 73                            break;
 74                        }

 75
 76                        cbBuffer++;
 77                    }

 78
 79                    for (cbtemp = 0; cbtemp < (cbBuffer - 3); cbtemp++) 
 80                    {
 81                        if (pchIn[cbtemp] == '/' && pchIn[cbtemp + 1] == 'h' && pchIn[cbtemp + 2] == 't' && pchIn[cbtemp + 3] == 'm')
 82                        {
 83                            pfc->pFilterContext    =    (VOID    *)2;
 84
 85                            break;
 86                        }

 87                    }

 88
 89                    if (cbtemp ==    cbBuffer)
 90                        pfc->pFilterContext    =    0; /* not an    html file */
 91                }

 92
 93                /* Now uppercase everything */
 94
 95                if (pfc->pFilterContext)
 96                    for (  cbBuffer < pRawData->cbInData; cbBuffer++)
 97                        pchIn[cbBuffer] = (pchIn[cbBuffer] >= 'a' && pchIn[cbBuffer] <= 'z') ? (pchIn[cbBuffer] - 'a' + 'A') : pchIn[cbBuffer];
 98            }

 99
100            break;
101
102        default :
103
104            break;                
105    }

106    
107    return SF_STATUS_REQ_NEXT_NOTIFICATION;
108}

ISAPI過濾器的開發(fā)非常簡(jiǎn)單,只需要完成三個(gè)接口DLL函數(shù)即可。它們是GetFilterVersion()、HttpFilterProc()、TerminateFilter(),大家可以查看MSDN了解詳細(xì)的用法。ISAPI過濾器是DLL文件,一般用C/C++語言開發(fā)。為使ISAPI過濾器能夠運(yùn)行,您需要在注冊(cè)表的HKEY_LOCAL_MACHINESystemCurrentControlSet
ServicesW3SVCParameters下建立一個(gè)字符串項(xiàng),其名稱為"Filter Dlls",值為ISAPI過濾器文件的全路徑名稱。若這個(gè)字符串項(xiàng)已經(jīng)存在,只需把它的全路徑名稱加入其中,不同的ISAPI過濾器文件之間用""分隔,您可以根據(jù)執(zhí)行的優(yōu)先順序加在適當(dāng)?shù)奈恢谩TO(shè)置好后重新啟動(dòng)IIS服務(wù),您的ISAPI過濾器就發(fā)揮作用了。

下面作者舉一個(gè)具體的應(yīng)用例子。

對(duì)訪問內(nèi)容進(jìn)行統(tǒng)計(jì)分析: 
通常我們?cè)谛枰?jì)數(shù)的頁面內(nèi)放一個(gè)計(jì)數(shù)器,或者使用ASP文件來實(shí)現(xiàn)計(jì)數(shù)功能。這種方法不能適用于如README.TXT等其他非HTML格式的文件。如果使用IIS的日志功能又太占用空間而不方便。作者通過定制URL映射信息處理來跟蹤感興趣的幾個(gè)文件的計(jì)數(shù)統(tǒng)計(jì),將結(jié)果記錄在一個(gè)文件中。

下面是它的源程序。

fcount.def:
LIBRARY fcount
EXPORTS GetFilterVersion
 HttpFilterProc
 TerminateFilter

fcount.c:
#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <httpfilt.h>

#define logfile "C:\InetPub\fcount.log"
#define pages 5
char* urls[] = {
  "/default.htm",
  "/banner.gif",
  "/product/readme.txt",
  "/product/product1.htm",
  "/product/product2.htm"
 };
int counts[pages];

BOOL WINAPI GetFilterVersion
(HTTP_FILTER_VERSION *pVer)
{
int i;

 pVer->dwFilterVersion = HTTP_FILTER_REVISION;
strcpy(pVer->lpszFilterDesc, "fcount");
 pVer->dwFlags = SF_NOTIFY_URL_MAP;

 for (i=0; i<pages; i++) {
counts[i] = GetPrivateProfileInt("VisitCounter", 
urls[i], 
0, logfile);
}

 return TRUE;
}

DWORD WINAPI HttpFilterProc
(HTTP_FILTER_CONTEXT *pfc,
 DWORD noteType, VOID *pvNote)
{
 int i;
 char lurl[512];
 char buf[16];

 strcpy(lurl, ((PHTTP_FILTER_URL_MAP)pvNote)
->pszURL);
 _strlwr(lurl);
 for (i=0; i<pages; i++) {
 if (strcmp(lurl, urls[i])==0) {
  counts[i] ++; 
  if (counts[i]%10==0) {

  _itoa(counts[i], buf, 10);
  WritePrivateProfileString("VisitCounter",
 urls[i], buf, logfile);
 }
  break;
 }
 }
 return SF_STATUS_REQ_NEXT_NOTIFICATION;
}

BOOL WINAPI TerminateFilter(DWORD dwFlags)
{
 int i;
 char buf[16];

 for (i=0; i<pages; i++) {
    
 _itoa(counts[i], buf, 10);
 WritePrivateProfileString("VisitCounter", 
 urls[i], buf, logfile);
 }
 return TRUE;
}

以上二個(gè)例子作者使用VC 6.0編譯,在WINNT2000 + SP3 和 IIS 5.0上調(diào)試通過。

iis 非法信息過濾器

  描述:

    該程序主要作用是過濾來自客戶端的get,post提交,如果包含我們既定的關(guān)鍵字就拒絕本次訪問,并返回給客戶端錯(cuò)誤信息.以此達(dá)到提交信息過濾功能。

采用開發(fā)工具:

    vc 6.0

詳細(xì)說明:

    iis本身是不具有信息過濾的功能的,我們只有自己寫 ISAPI 程序來實(shí)現(xiàn)。

    ISAPI說明:

        ISAPI是iis 提供的編程接口,可以通過寫ISAPI dll來增強(qiáng)iis 的功能,達(dá)到用戶需求。寫ISAPI一般都是用vc 和 Delphi 開發(fā),他們都提供了

        編寫ISAPI程序的庫函數(shù)和結(jié)構(gòu)體,我們調(diào)用實(shí)現(xiàn)就行了。另外一點(diǎn)(ISAPI程序?qū)嶋H上是加載到iis 進(jìn)程里面和iis一起運(yùn)行的,所以調(diào)試起來比較費(fèi)勁)

        具體關(guān)于ISAPI的詳細(xì)說明,網(wǎng)上鋪天蓋地,這里我就不說了。

程序?qū)崿F(xiàn): 

    由于程序要支持iis 6.0,而MSDN上說IIS5.1和IIS6.0好像不支持OnReadRawData方法了(用來截獲客戶端的post請(qǐng)求信息的方法),所以沒辦法獲取客戶端傳過來的原始數(shù)據(jù)。

    這個(gè)問題網(wǎng)上也很多問的。iis6.0中我們可以采用通配符應(yīng)用程序映射實(shí)現(xiàn)截獲客戶端得post信息。

    實(shí)現(xiàn):

      1. vc 6.0 新建ISAPI 擴(kuò)展工程

        

2. 選擇服務(wù)器擴(kuò)展對(duì)象。

        

      3.完成,vc會(huì)生成基本的ISAPI程序代碼。

      而我們主要是對(duì)DWORD WINAPI HttpExtensionProc(EXTENSION_CONTROL_BLOCK *pecb)函數(shù)進(jìn)行編寫

      //用戶和iis服務(wù)器之間進(jìn)行通信,通信通過EXTENSION_CONTROL_BLOCK
      DWORD WINAPI HttpExtensionProc(EXTENSION_CONTROL_BLOCK *pecb)
      {
        char *p = NULL;
        DWORD dwStatus=HSE_STATUS_ERROR;
       BOOL rc;
       HSE_EXEC_URL_INFO ExecUrlInfo={0};
       HSE_EXEC_URL_ENTITY_INFO *pEntity=NULL;
        char *lpszTemp=NULL, *lpszContent=NULL;
        DWORD cbQuery;
        char *lpszQuery = NULL;
         BOOL Success=FALSE;
        BOOL MethodGet=TRUE;//get
         if (!stricmp(pecb->lpszMethod, "get"))
        {
          lpszQuery = pecb->lpszQueryString;
        }
       else//post
       {
          MethodGet = FALSE;
         if(pecb->cbTotalBytes > 0)
        {
         if(!(lpszTemp = (CHAR *)LocalAlloc(LPTR, pecb->cbTotalBytes)))
            {
              return HSE_STATUS_ERROR;
            }
         strcpy(lpszTemp,(const char *)pecb->lpbData);
         if((cbQuery = pecb->cbTotalBytes - pecb->cbAvailable) > 0)
         pecb->ReadClient(pecb->ConnID, (LPVOID) (lpszTemp pecb->cbAvailable), &cbQuery);
lpszQuery = lpszTemp;
        }
       }
        if (strlen(lpszQuery) !=0)
        {
          char * mem_name=NULL;  

           CString memname=""
           CString fileData;
CString translateData;
for (int i=0;i < strarray.GetSize();i )
          {
            GB2312ToUTF_8(fileData,strarray[i].GetBuffer(strarray[i].GetLength()),strarray[i].GetLength());
            fileData=URLEncode(fileData);
            //如何進(jìn)入的為gb2312字碼,就將文件數(shù)據(jù)轉(zhuǎn)化為gb2312字碼
             if (strstr(lpszQuery,fileData) || strstr(lpszQuery,strarray[i]))
            {
              goto Mark;
            }
           }
          ExecUrlInfo.dwExecUrlFlags = HSE_EXEC_URL_IGNORE_CURRENT_INTERCEPTOR;
          rc=pecb->ServerSupportFunction(pecb->ConnID, HSE_REQ_IO_COMPLETION, HseIoCompletionProc, NULL,(LPDWORD)pEntity);
           if(!rc) goto Failed;
          rc=pecb->ServerSupportFunction(pecb->ConnID, HSE_REQ_EXEC_URL, &ExecUrlInfo, NULL, NULL);
          if(!rc) goto Failed;
          return HSE_STATUS_PENDING;
        }
         //正常網(wǎng)頁求情數(shù)據(jù)傳輸
        else
        {
          ExecUrlInfo.dwExecUrlFlags = HSE_EXEC_URL_IGNORE_CURRENT_INTERCEPTOR;
          rc=pecb->ServerSupportFunction(pecb->ConnID, HSE_REQ_IO_COMPLETION,HseIoCompletionProc, NULL, (LPDWORD)pEntity);
           if(!rc) goto Failed;
           rc=pecb->ServerSupportFunction(pecb->ConnID, HSE_REQ_EXEC_URL, &ExecUrlInfo, NULL, NULL);
           if(!rc) goto Failed;
          return HSE_STATUS_PENDING;
        }

        Failed:
       if(dwStatus!=HSE_STATUS_PENDING)
         {
          if(NULL!=pEntity)
         {
          LocalFree(pEntity);
          pEntity=NULL;
         }
         }
        Mark:
          char * message= "您提交的信息中含有非法字符,請(qǐng)求被終止"
          DWORD dwSize = strlen(message);
          pecb->WriteClient(pecb->ConnID,message, &dwSize, 0);
         return dwStatus;
    }

用VS2008開發(fā)ISAPI程序

因?yàn)镮SAPI擴(kuò)展和調(diào)用它的進(jìn)程(IIS)在同一的進(jìn)程地址空間中,這樣它們就可以互相直接聯(lián)系。這種方式一個(gè)最大的隱患就是會(huì)導(dǎo)致整個(gè)IIS當(dāng)機(jī),而且在有些時(shí)候是整個(gè)網(wǎng)站當(dāng)?shù)簟?匆幌孪旅娴膱D:

你看到,如果ISAPI擴(kuò)展程序遇到問題且處理不當(dāng),將會(huì)影響整個(gè)網(wǎng)站的服務(wù)進(jìn)程。就像上圖所示,ISAPI擴(kuò)展和IIS的通訊是通過一個(gè)ECB(Extension Control Block)結(jié)構(gòu)的指針,其結(jié)構(gòu)然如下:

typedef struct _EXTENSION_CONTROL_BLOCK

{

   DWORD     cbSize;                 // size of this struct.

   DWORD     dwVersion;              // version info of this spec

   HCONN     ConnID;                 // Context number not to be modified!

   DWORD     dwHttpStatusCode;       // HTTP Status code

   CHAR      lpszLogData[HSE_LOG_BUFFER_LEN];// null terminated log info

   LPSTR     lpszMethod;             // REQUEST_METHOD

   LPSTR     lpszQueryString;        // QUERY_STRING

   LPSTR     lpszPathInfo;           // PATH_INFO

   LPSTR     lpszPathTranslated;     // PATH_TRANSLATED

   DWORD     cbTotalBytes;           // Total bytes indicated from client

   DWORD     cbAvailable;            // Available number of bytes

   LPBYTE    lpbData;                // pointer to cbAvailable bytes

   LPSTR     lpszContentType;        // Content type of client data

   BOOL (WINAPI * GetServerVariable) (HCONN hConn,

   LPSTR      lpszVariableName,

   LPVOID     lpvBuffer,

   LPDWORD    lpdwSize );

   BOOL (WINAPI * WriteClient)  (HCONN ConnID,

   LPVOID     Buffer,

   LPDWORD    lpdwBytes,

   DWORD      dwReserved );

   BOOL (WINAPI * ReadClient)  (HCONN ConnID,

   LPVOID     lpvBuffer,

   LPDWORD    lpdwSize );

   BOOL (WINAPI * ServerSupportFunction)( HCONN hConn,

   DWORD      dwHSERequest,

   LPVOID     lpvBuffer,

   LPDWORD    lpdwSize,

   LPDWORD    lpdwDataType );

}EXTENSION_CONTROL_BLOCK, *LPEXTENSION_CONTROL_BLOCK;

無論是調(diào)用進(jìn)程還是ISAPI擴(kuò)展,它們之間的任何信息都是通過EBC來要傳遞給對(duì)方的。我們已簡(jiǎn)單的看了一下ECB結(jié)構(gòu)。現(xiàn)在,我們來看看IIS是如何通過與ISAPI擴(kuò)展進(jìn)行通訊,來為網(wǎng)站訪問者服務(wù)的。

當(dāng)一個(gè)ISAPI擴(kuò)展被訪問(比如:http://www.mydomain.com/script/example.dll? ID=p05874 & Tx=870250AZT6)時(shí),IIS會(huì)檢查example.dll是否已經(jīng)被加載進(jìn)內(nèi)存中。如果沒有加載,IIS會(huì)加載。一旦DLL被加載進(jìn)內(nèi)存,一個(gè)工作線程便開始運(yùn)行我們的ISAPI擴(kuò)展程序(example.dll)。先是DLL的入口函數(shù)DllMain被調(diào)用。調(diào)用完成后,IIS開始調(diào)用GetExtensionVersion函數(shù),這個(gè)函數(shù)主要實(shí)現(xiàn)了下面兩個(gè)功能:

  1. 報(bào)告ISAPI可以實(shí)現(xiàn)的擴(kuò)展服務(wù)

  2. 取得一個(gè)簡(jiǎn)短的描述擴(kuò)展的字符串。

然后IIS開始調(diào)用HttpExtensionProc函數(shù)。這個(gè)函數(shù)會(huì)傳遞一個(gè)ECB指針給ISAPI擴(kuò)展以開始真正的調(diào)用。通過這個(gè)函數(shù)ISAPI可以向客戶端(如瀏覽器)回寫數(shù)據(jù)。過會(huì)兒我們會(huì)檢查。

第三個(gè)也是最后一個(gè)ISAPI擴(kuò)展的入口函數(shù)是TerminateExtension函數(shù)。它在當(dāng)ISAPI擴(kuò)展從內(nèi)存中卸載的時(shí)候調(diào)用。所有的清除代碼可以在這個(gè)函數(shù)中實(shí)現(xiàn)。

簡(jiǎn)言之,一個(gè)ISAPI擴(kuò)展是一個(gè)導(dǎo)出三個(gè)函數(shù)的非常規(guī)范的DLL。

  1. GetExtensionVersion

  2. HttpExtensionProc

  3. TerminateExtension (可選)

手頭有了這些資料,我們開始DllMain的代碼編寫。它是所有的DLL的入口點(diǎn)函數(shù)。

DLLMain——入口點(diǎn)函數(shù)

就像微軟說的,DllMain是每個(gè)DLL的入口函數(shù),它是可選的。如DLL中定義了DllMain,在進(jìn)程或線程初始化/中止時(shí),或者當(dāng)使用LoadLibrary加載和FreeLibrary卸載時(shí)調(diào)用這個(gè)入口點(diǎn)函數(shù)。這個(gè)如何函數(shù)原型如下:

BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwCallReason, LPVOID lpReserved);

如果你的ISAPI擴(kuò)展程序中提供這個(gè)過程,那么它將在初始化和結(jié)束時(shí)被被調(diào)用。dwCallReason參數(shù)可以是下面預(yù)定義值之一:

  • DLL_PROCESS_ATTACHED

  • DLL_THREAD_ATTACH

  • DLL_THREAD_DETACH

  • DLL_PROCESS_DETACH

對(duì)每個(gè)參數(shù)的詳細(xì)描述超出了本文討論范圍,有興趣的讀者可以到MSDN上了解更多關(guān)于本函數(shù)的信息。

再有,我們可以保存hMoudle參數(shù)以便以后的使用。最后只是簡(jiǎn)單的返回一個(gè)TURE值。我們?cè)陂_發(fā)擴(kuò)展程序時(shí),通常在這個(gè)函數(shù)中不做什么事。

GetExtensionVersion——真正的入口函數(shù)

這個(gè)函數(shù)是IIS調(diào)用的第一個(gè)入口函數(shù),是ISAPI擴(kuò)展用來向IIS提供信息用的。為了進(jìn)一步的了解這個(gè)函數(shù),我們來看一下這個(gè)函數(shù)的原型:

BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO *pVer);

在這個(gè)函數(shù)的調(diào)用時(shí),我們假定使用pver參數(shù)來填寫擴(kuò)展信息,HSE_VERSION_INFO結(jié)構(gòu)如下:

typedef struct _HSE_VERSION_INFO

{

   DWORD dwExtensionVersion;

   CHAR lpszExtensionDesc[HSE_MAX_EXT_DLL_NAME_LEN];

}HSE_VERSION_INFO, *LPHSE_VERSION_INFO;

dwExtensionVersion是擴(kuò)展的版本號(hào),lpszExtensionDescription是擴(kuò)展的描述。如果返回TRUE便表示我們告訴IIS我們的擴(kuò)展程序準(zhǔn)備好了,可以使用了;而返回FALSE則表示IIS不可以使用本擴(kuò)展。

HttpExtensionProc——主要入口函數(shù)

一個(gè)ISAPI擴(kuò)展的令人著迷部分是HttpExtensionProc。目前你所能想到的是這個(gè)函數(shù)可以用來向客戶端回寫數(shù)據(jù)。為了看明白這是怎么發(fā)生的,我們來一下這個(gè)函數(shù)原型:

DWORD WINAPI HttpExtensionProc(EXTENSION_CONTROL_BLOCK *pECB);

這里pECB是一個(gè)擴(kuò)展控制塊(ECB)的指針。這個(gè)結(jié)構(gòu)用來解決IIS和ISAPI擴(kuò)展之間的通訊問題。在這個(gè)函數(shù)中,你可以決定你的網(wǎng)頁中包含什么內(nèi)容,如何返回給用戶,怎樣做?還想起來這個(gè)結(jié)構(gòu)的成員了?ECB成員中包含了一個(gè)方法,原型如下:

BOOL WriteClient(HCONN ConnID, LPVOID Buffer, LPDWORD lpdwBytes, DWORD dwSync);

使用這個(gè)函數(shù),你可以將數(shù)據(jù)放入緩沖區(qū)中,呈現(xiàn)給用ConnId標(biāo)識(shí)的客戶端。比如說,要想發(fā)送 “A BIG RED ROSE”這幾個(gè)字給客戶,你可以簡(jiǎn)單地進(jìn)行下面的調(diào)用:

char szBigRedRos[] =

  "<font color='#FF0000' size='3'><b>A BIG RED ROSE</b></font>"

DWORD dwSize = strlen(szBigRedRos);

pECB->WriteClient(pECB->ConnID, szBigRedRose, dwSize, 0);

哈哈,到此為止。我想你已經(jīng)擁有最基礎(chǔ)的知識(shí)來開發(fā)你自己的第一個(gè)ISAPI擴(kuò)展程序了。讓我們開始吧。。。

項(xiàng)目需求

1.              一點(diǎn)點(diǎn)耐性

2.              一個(gè)MSVC++6編譯器

3.              一個(gè)裝有IIS地MS WINDOWS2000的操作系統(tǒng)

4.              一個(gè)網(wǎng)頁瀏覽器

目標(biāo)

我們決定不用MFC而用WIN32 API來開發(fā)開發(fā)一個(gè)ISAPI擴(kuò)展程序。這個(gè)程序的功能是檢查Master Card (萬事達(dá))卡號(hào)是否有效。我們給這個(gè)ISAPI擴(kuò)展DLL命名為Validate.dll。在這個(gè)擴(kuò)展程序中將簡(jiǎn)單地往客戶端寫一串字符以告訴客戶:你所提供的卡號(hào)是否有效。當(dāng)然,我們一定會(huì)檢查,如果用戶使用下面的URL地址:

http://mydomain/script/validate.dll?some%20string

http://mydomain/script/validate.dll?

或者相似的無效URL地址的情況(當(dāng)然,所謂“無效”是從我們程序員的角度來看的,使用者可不這么想)。

當(dāng)上面這種無效URL地址的情況發(fā)生時(shí),我們將簡(jiǎn)單地回復(fù)下面一段文字到客戶端:What you have entered is an invalid Master Card #.

上面就是我們的ISAPI擴(kuò)展所能做的一切。

1、打開Visual Studio 2008

2、打開解決方案資源管理器視圖->選擇項(xiàng)目->添加新建項(xiàng)->C++文件(.cpp)

3、根據(jù)第二步,再添加一個(gè)模塊定義文件(.def)

6、打開解決方案資源管理器視圖->選擇項(xiàng)目->屬性->配置->所有配置->平臺(tái)->所有平臺(tái)

  • 常規(guī)->輸出目錄:$(SolutionDir)$(PlatformName)\$(ConfigurationName)

  • 常規(guī)->中間目錄:$(PlatformName)\$(ConfigurationName)

  • 常規(guī)->配置類型:動(dòng)態(tài)庫(.dll)

  • 常規(guī)->MFC使用:使用標(biāo)準(zhǔn) Windows 庫

  • 常規(guī)->字符集:未設(shè)置

  • 常規(guī)->全程序優(yōu)化:使用鏈接時(shí)間代碼生成

  • C/C++->常規(guī)->調(diào)試信息格式:程序數(shù)據(jù)庫(/Zi)

  • (如果需要編譯64位的ISAPI)C/C++->常規(guī)->檢測(cè)64位可移植性問題:是(/Wp64)

代碼:

1 #include <windows.h>
 2 #include <stdio.h>
 3 #include <stdlib.h>
 4  // #include <httpfilt.h>
 5 #include <httpext.h> //ISAPI擴(kuò)展的頭文件
 6 
 7  void WriteContext(EXTENSION_CONTROL_BLOCK *pECB,  char *pszFormat,  );
 8  void StartContext(EXTENSION_CONTROL_BLOCK *pECB);
 9  void EndContext(EXTENSION_CONTROL_BLOCK *pECB);
10 
11 BOOL APIENTRY DLLMain(HANDLE hModule, DWORD dwCallReason, LPVOID lpReserved)
12 {
13      return TRUE;
14 }
15 
16 BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO *pVer)
17 {
18     pVer->dwExtensionVersion = HSE_VERSION;
19     strncpy(pVer->lpszExtensionDesc,  " My first ISAPI program ", HSE_MAX_EXT_DLL_NAME_LEN);
20      return TRUE;
21 }
22 
23 DWORD WINAPI HttpExtensionProc(EXTENSION_CONTROL_BLOCK *pECB)
24 {
25     StartContext(pECB);
26     WriteContext(pECB,  " <p>this is my first ISAPI program!!hello money!!</p> ");
27     EndContext(pECB);
28      return HSE_STATUS_SUCCESS;
29 }
30 
31 BOOL WINAPI TerminateExtension(DWORD dwFlags)
32 {
33      return TRUE;
34 }
35 
36  void WriteContext(EXTENSION_CONTROL_BLOCK *pECB,  char *pszFormat,  )
37 {
38      char szBuffer[ 1024];
39     va_list arg_ptr;
40     va_start(arg_ptr, pszFormat);
41     vsprintf(szBuffer, pszFormat, arg_ptr);
42     va_end(arg_ptr);
43 
44     DWORD dwSize = strlen(szBuffer);
45     pECB->WriteClient(pECB->ConnID, szBuffer, &dwSize,  0);
46 }
47 
48  void StartContext(EXTENSION_CONTROL_BLOCK *pECB)
49 {
50    WriteContext(pECB,  " <html>\r\n<body>\r\n ");
51 }
52  
53  void EndContext(EXTENSION_CONTROL_BLOCK *pECB)
54 {
55    WriteContext(pECB,  " </body>\r\n</html> ");

56 } 

其中EXTENSION_CONTROL_BLOCK結(jié)構(gòu)用來和IIS通信

【知識(shí)點(diǎn)開發(fā)和總結(jié)】

ISAPI是Internet Server Application Programming Interface 的簡(jiǎn)稱,ISAPI過濾器是IIS進(jìn)程內(nèi)的DLL(進(jìn)程名為inetinfo),它在web服務(wù)啟動(dòng)時(shí)被加載,服務(wù)停止時(shí)退出。
  IASPI過濾器可以用來定制認(rèn)證過程、壓縮、加密、流量分析、請(qǐng)求分析、請(qǐng)求過濾等等,從某種意義上來說,ISAPI過濾器可以被看作是對(duì)IIS進(jìn)行定制和優(yōu)化的工具。
  ISAPI過濾器的基本工作原理是基于事件觸發(fā)的單線程過濾器,一個(gè)標(biāo)準(zhǔn)的ISAPI過濾器由以下幾個(gè)部分組成:
  1、過濾器初始化
  2、消息接收過濾
  3、事件處理
  4、退出處理 
  
  過濾器初始化一般是設(shè)置版本信息、優(yōu)先級(jí)、消息過濾器,這些工作在GetFilterVersion中完成,例如:
 BOOL WINAPI GetFilterVersion(PHTTP_FILTER_VERSION pVer)
 {
  pVer->dwFilterVersion = HTTP_FILTER_REVISION;
  lstrcpy(pVer->lpszFilterDesc, "Filter Shotgun");
  pVer->dwFlags = SF_NOTIFY_ORDER_DEFAULT | SF_NOTIFY_URL_MAP;
  return TRUE;
 }
  上面這段程序設(shè)置版本信息為"Filter Shotgun",程序的優(yōu)先級(jí)為默認(rèn)(SF_NOTIFY_ORDER_DEFAULT),過濾器程序在映射文件物理地址時(shí)工作( SF_NOTIFY_URL_MAP)
  其中,消息過濾允許關(guān)注以下的事件:
  SF_NOTIFY_READ_RAW_DATA 讀取數(shù)據(jù)
  SF_NOTIFY_SEND_RAW_DATA 發(fā)送數(shù)據(jù)
  SF_NOTIFY_END_OF_REQUEST 結(jié)束請(qǐng)求
  SF_NOTIFY_PREPROC_HEADERS  任何一個(gè)HTTP頭都會(huì)觸發(fā)這個(gè)事件
  SF_NOTIFY_URL_MAP   這個(gè)事件在IIS將web路徑映射為物理路徑時(shí)發(fā)生
  SF_NOTIFY_AUTHENTICATION 開始認(rèn)證
  SF_NOTIFY_AUTH_COMPLETE  認(rèn)證結(jié)束
  SF_NOTIFY_SEND_RESPONSE  發(fā)送回應(yīng)
  SF_NOTIFY_LOG   產(chǎn)生日志
  SF_NOTIFY_END_OF_NET_SESSION 結(jié)束會(huì)話
 
  事件之間用 | 連接,當(dāng)系統(tǒng)發(fā)生了ISAPI過濾器程序所關(guān)注的事件時(shí),IIS會(huì)傳送一個(gè)NotificationType的變量給HttpFilterProc函數(shù),由該函數(shù)判斷事件的類型并調(diào)用響應(yīng)的處理函數(shù)。
 DWORD WINAPI __stdcall HttpFilterProc( HTTP_FILTER_CONTEXT * pfc,DWORD NotificationType, VOID * pvData )
 {
     switch ( NotificationType )
     {
      case SF_NOTIFY_PREPROC_HEADERS:
           return OnPreprocHeaders(pfc, (PHTTP_FILTER_PREPROC_HEADERS)pvData);
  case SF_NOTIFY_URL_MAP:
   return OnUrlMap(pfc, (PHTTP_FILTER_URL_MAP)pvData );
     }
  return SF_STATUS_REQ_NEXT_NOTIFICATION;
 }
  事件處理函數(shù)可以通過服務(wù)器支持的函數(shù)調(diào)用對(duì)url, header, path等參數(shù)進(jìn)行處理,例如,我們需要截獲所有的值為Shotgun.com的HOST頭并替換為Shotgun.net,就可以通過GetHeader和SetHeader函數(shù)來實(shí)現(xiàn):
  DWORD inline OnPreprocHeaders(PHTTP_FILTER_CONTEXT pfc, PHTTP_FILTER_PREPROC_HEADERS pvData)
 { char Host[1024];
  DWORD cb;
  cb=sizeof(Host);
  pvData->GetHeader(pfc,"Host:",Host,&cb);
  if(!_strnicmp(Host,"Shotgun.com",5)) 
   pvData->SetHeader(pfc,"Host","Shotgun.net");
  return SF_STATUS_REQ_NEXT_NOTIFICATION;
 }
 
  事件處理函數(shù)可以返回以下的值:
  SF_STATUS_REQ_FINISHED 過濾器接管了HTTP請(qǐng)求,服務(wù)器可以斷開會(huì)話。
  SF_STATUS_REQ_FINISHED_KEEP_CONN 過濾器接管了HTTP請(qǐng)求。但是服務(wù)器需要保持TCP會(huì)話。
  SF_STATUS_REQ_NEXT_NOTIFICATION 正常的返回,IIS將調(diào)用消息隊(duì)列中的下一個(gè)過濾器。
  SF_STATUS_REQ_HANDLED_NOTIFICATION 過濾器接管了這個(gè)消息,這種事件不需要再通知其他的句柄。
  SF_STATUS_REQ_ERROR 錯(cuò)誤返回,服務(wù)器應(yīng)該調(diào)用GetLastError,并且將錯(cuò)誤信息返回給客戶端。
  SF_STATUS_REQ_READ_NEXT 過濾器是不透明的流過濾器(加密/壓縮HTTP請(qǐng)求)會(huì)話參數(shù)已經(jīng)通過。這個(gè)返回僅當(dāng)使用RAW-READ事件處理時(shí)有效,這個(gè)消息指出請(qǐng)求并沒有全部完成,服務(wù)器需要繼續(xù)進(jìn)行讀操作并再次通知過濾器。
  服務(wù)器支持的函數(shù)通過一個(gè)HTTP_FILTER_CONTEXT或者HTTP_FILTER_PREPROC_HEADERS 結(jié)構(gòu)調(diào)用:
  1、GetHeader  取得HTTP頭
  2、SetHeader  設(shè)置HTTP頭
  3、AddHeader   增加HTTP頭
  4、AddResponseHeaders  增加返回給用戶的HTTP頭
  5、AllocMem   分配內(nèi)存
  6、GetServerVariable  取得服務(wù)器變量
  7、WriteClient   直接往客戶端寫數(shù)據(jù)
  8、ServerSupportFunction  支持以下多種靈活的功能:
   SF_REQ_ADD_HEADERS_ON_DENIAL  這個(gè)功能允許過濾器在服務(wù)器產(chǎn)生拒絕訪問的
      事件時(shí)增加特定的HTTP頭,此函數(shù)一般用于認(rèn)證過濾器
   SF_REQ_DISABLE_NOTIFICATIONS   禁止某個(gè)事件消息
   SF_REQ_GET_CONNID   這個(gè)功能在IIS4.0以后的版本已不再支持
   SF_REQ_GET_PROPERTY    取得IIS屬性
   SF_REQ_NORMALIZE_URL   規(guī)整URL
   SF_REQ_SEND_RESPONSE_HEADER  發(fā)送回應(yīng)HTTP頭
   SF_REQ_SET_NEXT_READ_SIZE   設(shè)置下次數(shù)據(jù)讀尺寸
   SF_REQ_SET_PROXY_INFO   設(shè)置代理信息
 
  當(dāng)ISAPI過濾器卸載時(shí),TerminateFilter將會(huì)被調(diào)用,在這個(gè)函數(shù)中,你需要釋放過濾器申請(qǐng)的所有資源,值得注意的是。微軟推薦關(guān)注SF_NOTIFY_END_OF_NET_SESSION事件,以便在每次網(wǎng)絡(luò)會(huì)話結(jié)束時(shí)就釋放資源,這樣可以減輕服務(wù)器的負(fù)荷。


該文章在 2024/7/5 18:45:21 編輯過
關(guān)鍵字查詢
相關(guān)文章
正在查詢...
點(diǎn)晴ERP是一款針對(duì)中小制造業(yè)的專業(yè)生產(chǎn)管理軟件系統(tǒng),系統(tǒng)成熟度和易用性得到了國(guó)內(nèi)大量中小企業(yè)的青睞。
點(diǎn)晴PMS碼頭管理系統(tǒng)主要針對(duì)港口碼頭集裝箱與散貨日常運(yùn)作、調(diào)度、堆場(chǎng)、車隊(duì)、財(cái)務(wù)費(fèi)用、相關(guān)報(bào)表等業(yè)務(wù)管理,結(jié)合碼頭的業(yè)務(wù)特點(diǎn),圍繞調(diào)度、堆場(chǎng)作業(yè)而開發(fā)的。集技術(shù)的先進(jìn)性、管理的有效性于一體,是物流碼頭及其他港口類企業(yè)的高效ERP管理信息系統(tǒng)。
點(diǎn)晴WMS倉儲(chǔ)管理系統(tǒng)提供了貨物產(chǎn)品管理,銷售管理,采購管理,倉儲(chǔ)管理,倉庫管理,保質(zhì)期管理,貨位管理,庫位管理,生產(chǎn)管理,WMS管理系統(tǒng),標(biāo)簽打印,條形碼,二維碼管理,批號(hào)管理軟件。
點(diǎn)晴免費(fèi)OA是一款軟件和通用服務(wù)都免費(fèi),不限功能、不限時(shí)間、不限用戶的免費(fèi)OA協(xié)同辦公管理系統(tǒng)。
Copyright 2010-2025 ClickSun All Rights Reserved

主站蜘蛛池模板: 被拖进小树林C了好爽H出租车 | 成人片黄网站A片免费 | 亚洲国产一区二区在线观看 | 免费看的久久久久 | 国产熟妇精品伦一区二区三区 | 无码专区一ⅴa亚洲v专区在线 | 免费无码又爽又刺激高潮视频日本 | 无码人妻精品一区二区三区蜜桃 | 日夜夜天天人人综合网 | 亚洲乱码伦小说区 | 国产麻豆VIDEOXXXX实拍 | 国产三级不卡在线播放 | 国产亚洲一区二区手机在线观看 | 色婷婷亚洲婷婷7月 | 日韩精品无码一区二区三区 | 99久久精品国产一区二区野战 | 国产a一级无码毛片一区二区三区 | 国产一级特黄高清免费大片dvd | 亚洲国产天堂久久综合 | 美女h动态图 | 久久久久久九九99精品午夜福利91 | 精品久久无码AV片银杏 | 岛国岛国免费V片在线观看 调教日本美女 | 久久精品无码一区二区软件 | 久久久久人妻精品一区蜜桃网站 | 青青热久久国产久精品 | a级国产乱理论片在线播放 a级国产乱理论片在线观看 | 国产成人精品午夜在线播放 | 国产人妻人伦精品一区二区 | 色婷婷天天综合在线 | 久艳妇荡女欲乱 | 无码人妻一区二区三区免费n鬼沢 | 国产中文字幕乱码免在线观看 | 熟女视频一区二区在线观看 | 完美世界动漫在线视频免费观看 | 欧洲精品专区永久免费区 | 欧美精品亚洲精品日韩专区 | 国产亚洲第一伦理第一区 | 欧美体验区 | 国产精品无码一本二本三本色 | 亚洲欧洲日韩国产一区二区三区 |