IIS-擴展接口ISAPI-Filter分析

ISAPI 篩選器(ISAPI filter)導出函數

1、BOOL WINAPI GetFilterVersion( PHTTP_FILTER_VERSION pVer);
該函數是DLL篩選器第一次被加載到站點處理進程時被調用。
2、DWORD WINAPI HttpFilterProc(PHTTP_FILTER_CONTEXT pfc,DWORD notificationType,LPVOID pvNotification);
該函數用於響應註冊在 GetFilterVersion 的形參PHTTP_FILTER_VERSION 中的dwFlags通知事件。根據所註冊的通知事件進行相應的篩選處理。
3、BOOL WINAPI TerminateFilter(DWORD dwFlags);
該函數是DLL篩選器被站點處理進程卸載時時所調用的處理。

源代碼如下所示

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <httpfilt.h>
#include <httpext.h>
#define _CRT_SECURE_NO_WARNINGS
/*
BOOL GetFilterVersion(HTTP_FILTER_VERSION *pVer)
{
pVer->dwFlags = (SF_NOTIFY_PREPROC_HEADERS | SF_NOTIFY_AUTHENTICATION |
SF_NOTIFY_URL_MAP | SF_NOTIFY_SEND_RAW_DATA | SF_NOTIFY_LOG | SF_NOTIFY_END_OF_NET_SESSION );
pVer->dwFilterVersion = HTTP_FILTER_REVISION;
strcpy(pVer->lpszFilterDesc, "UMFilter ISAPI");
return TRUE;
}

DWORD WINAPI __stdcall HttpFilterProc(HTTP_FILTER_CONTEXT *pfc, DWORD NotificationType, VOID *pvData)
{
CFile myFile("G:\\mylist.html", CFile::modeWrite);
myFile.SeekToEnd();
switch (NotificationType) {
case SF_NOTIFY_URL_MAP :
myFile.Write("SF_NOTIFY_URL_MAP",strlen("SF_NOTIFY_URL_MAP>"));
break;
case SF_NOTIFY_PREPROC_HEADERS :
myFile.Write("SF_NOTIFY_PREPROC_HEADERS",strlen("SF_NOTIFY_PREPROC_HEADERS"));
break;
default :
break;
}
myFile.Close();
return SF_STATUS_REQ_NEXT_NOTIFICATION;
}
*/

DWORD DoSendResponse(HTTP_FILTER_CONTEXT * pfc,HTTP_FILTER_SEND_RESPONSE * pResponse); 
//當ISAPI過濾器加載初始化時 GetFilterVersion 只調用一次
//IIS加載初始化ISAPI過濾器時,創建和填充部分HTTP_FILTER_VERSION結構。然後調用過濾器的GetFilterVersion函數,傳遞一個指針到新結構作爲一個參數
//ISAPI過濾器使用版本信息和描述令牌填充HTTP_FILTER_VERSION結構。更重要的是。可以使用HTTP_FILTER_VERSION接收指定通知事件和聲明過濾器通常優先級
BOOL WINAPI __stdcall GetFilterVersion(HTTP_FILTER_VERSION *pVer) 
{ 
const char *name = "UMFilter ISAPI"; 
size_t len = strlen(name) + 1; 
//SF_NOTIFY_ORDER_LOW:低優先級
//SF_NOTIFY_SEND_RESPONSE:在IIS處理請求之後,但在將任何標頭髮送回客戶端之前發生
//dwFlags:包含一些標誌,這些標誌指示應通知過濾器的通知事件類型以及過濾器的優先級。下表列出了有效的位掩碼。
//dwFilterVersion:ISAPI篩選器使用的ISAPI的版本號。可以使用httpfilt.h頭文件中的HTTP_FILTER_REVISION定義來設置過濾器使用的版本。
pVer->dwFlags = ( SF_NOTIFY_ORDER_LOW | SF_NOTIFY_SEND_RESPONSE ); 
//dwFilterVersion:ISAPI篩選器使用的ISAPI的版本號。可以使用httpfilt.h頭文件中的HTTP_FILTER_REVISION定義來設置過濾器使用的版本。
pVer->dwFilterVersion = HTTP_FILTER_REVISION; 
//lpszFilterDesc:指向以空值結尾的字符串,該字符串提供了ISAPI篩選器的簡短描述
//errno_t strncpy_s(
//   char *strDest,
//   size_t numberOfElements,
//   const char *strSource,
//   size_t count
//);
strncpy_s(pVer->lpszFilterDesc, len, "UMFilter ISAPI", len); 
return TRUE; 
} 
#pragma warning(suppress: 28251) 
//該GetExtensionVersion中的功能是在IIS中的第一入口點函數。此功能允許您的ISAPI擴展在IIS中註冊其版本信息。
BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO *pVer) 
{ 
//dwExtensionVersion:擴展的版本
//typedef struct _HSE_VERSION_INFO {
//    DWORD  dwExtensionVersion;
//    CHAR   lpszExtensionDesc[HSE_MAX_EXT_DLL_NAME_LEN];
//} HSE_VERSION_INFO, *LPHSE_VERSION_INFO;
pVer->dwExtensionVersion = HSE_VERSION; 
//_TRUNCATE 或 (size – 1): 表示截斷
strncpy_s(pVer->lpszExtensionDesc, HSE_MAX_EXT_DLL_NAME_LEN, 
"UMFilter ISAPI Extension", _TRUNCATE); 
return TRUE; 
} 
//每當發生已爲其註冊過濾器的通知事件時,IIS就會調用HttpFilterProc入口點函數。IIS使用此功能將信息和控制傳遞給ISAPI篩選器。
DWORD WINAPI __stdcall HttpFilterProc(HTTP_FILTER_CONTEXT *pfc, DWORD NotificationType, VOID *pvData) 
{ 
//pfc指向與當前活動的HTTP事務關聯,HTTP_FILTER_PROC使用此結構來獲取有關當前請求的信息
//notificationType:指向一個位掩碼,該位掩碼指示正在處理的通知事件的類型。以下是有效的事件類型以及可能發生的情況:
//SF_NOTIFY_SEND_RESPONSE:在IIS處理請求之後,但在將任何標頭髮送回客戶端之前發生
switch (NotificationType) 
{ 
case SF_NOTIFY_SEND_RESPONSE : 
//ISAPI篩選器在將標頭髮送到客戶端之前立即收到此通知
//在爲SF_NOTIFY_SEND_RESPONSE事件註冊了過濾器後,HttpFilterProc的pvNotification參數將指向此結構
return DoSendResponse(pfc, (HTTP_FILTER_SEND_RESPONSE *) pvData); 
default : 
break; 
} 
//使用SF_STATUS_REQ_NEXT_NOTIFICATION返回值告訴服務器,過濾器已成功地完成使命
return SF_STATUS_REQ_NEXT_NOTIFICATION; 
} 
//設置返回的內容
DWORD DoSendResponse(HTTP_FILTER_CONTEXT * pfc,HTTP_FILTER_SEND_RESPONSE * pResponse) 
{ 
BOOL fServer = TRUE; 
DWORD dwServerError; 
//SetHeader:指向SetHeader函數,該函數更改或刪除標頭的值。該功能可用於更改請求行中包含的特殊值
//所述SetHeader可以回調函數用於通過ISAPI濾波器更改或刪除的報頭的值。該功能可用於更改請求行中包含的特殊值。
//參數
//pfc 指向與當前活動的HTTP事務關聯的HTTP_FILTER_CONTEXT結構。
//lpszName指向要更改或刪除的標頭的名稱。
//lpszValue指向標題的新字符串,或指向“ \ 0”(刪除標題)
fServer = pResponse->SetHeader(pfc, "UMFilter:", "Enabled"); 
if ( !fServer ) 
{ 
dwServerError = GetLastError(); 
//pFilterContext:指向過濾器要與此請求關聯的任何上下文信息
//HttpStatus:當前的HTTP狀態代碼
pfc->pFilterContext = (LPVOID)(DWORD64)pResponse->HttpStatus; 
} 
return SF_STATUS_REQ_NEXT_NOTIFICATION; 
} 
void WriteContext(EXTENSION_CONTROL_BLOCK *pECB, char *pszFormat, ...) 
{ 
char szBuffer[1024]; 
//聲明一個變量來轉換參數列表   
va_list arg_ptr; 
//va_start,函數名稱,讀取可變參數的過程其實就是在堆棧中,使用指針,遍歷堆棧段中的參數列表,從低地址到高地址一個一個地把參數內容讀出來的過程·
va_start(arg_ptr, pszFormat); 
//sprintf_s(szInfo, sizeof(szInfo), szFormat, argPtr);
vsprintf_s(szBuffer, 1024, pszFormat, arg_ptr); 
//結束變量列表,和va_start成對使用   
va_end(arg_ptr); 
DWORD dwSize = strlen(szBuffer); 
//WriteClient函數將給定緩衝區中存在的數據發送到發出請求的客戶端
//參數
//指定響應數據應發送到的客戶端的連接標識符,HTTP服務器分配的唯一編號;此數字不應修改
//指向要發送的數據
//lpdwSizeofBuffer:指向DWORD,該DWORD包含來自緩衝區的字節數,該字節數將在進行調用時寫入客戶端。
//dwSync:指定一個DWORD,該DWORD包含指示如何處理I / O操作的標誌
pECB->WriteClient(pECB->ConnID, szBuffer, &dwSize, 0); 
} 
BOOL ReadContext(EXTENSION_CONTROL_BLOCK *pECB, LPVOID buffer, DWORD bufferSize, LPDWORD length) 
{ 
BOOL result; 
*length = bufferSize; 
//ReadClient函數從客戶端的HTTP請求的主體讀取數據。
result = pECB->ReadClient(pECB->ConnID, buffer, length); 
WCHAR num[12]; 
// converts number to string
//_itow_s(connectionId, num, sizeof(num), 10);
//將無符號長整數轉換爲字符串
//errno_t _ultow_s(
//    unsigned long value, 將轉換的數字
//    wchar_t *str, 字符串結果
//    size_t sizeOfstr, str 的大小 (以字節爲單位)
//    int radix Base of value. 
//);
_ultow_s(*length, num, 12, 10); 
//OutputDebugString(TEXT("ISAPI: "));
//OutputDebugString(num);
//OutputDebugString(TEXT(" bytes read\n"));
return result; 
} 
void StartContext(EXTENSION_CONTROL_BLOCK *pECB) 
{ 
WriteContext(pECB, "<html>\r\n<body>\r\n"); 
} 
void EndContext(EXTENSION_CONTROL_BLOCK *pECB) 
{ 
WriteContext(pECB, "</body>\r\n</html>"); 
} 
#pragma warning(suppress: 28251) 
//該HttpExtensionProc功能是通過IIS稱爲ISAPI擴展的主要切入點。它公開了IIS用於訪問擴展程序公開的功能的方法。lpECB:指向與當前活動請求關聯的EXTENSION_CONTROL_BLOCK數據結構
DWORD WINAPI HttpExtensionProc(EXTENSION_CONTROL_BLOCK *pECB) 
{ 
StartContext(pECB); 
WriteContext(pECB, "<pre>"); 
WriteContext(pECB, "%s", pECB->lpbData); 
//cbAvailable:字節可用數量(總數的cbTotalBytes)
//字節可用數量(總數的cbTotalBytes)在緩衝由指向lpbData。如果cbTotalBytes與cbAvailable相同,則lpbData變量將指向一個緩衝區,該緩衝區包含客戶端發送的所有數據。否則,cbTotalBytes將包含接收到的數據的字節總數。然後,ISAPI擴展將需要使用回調函數ReadClient來讀取其餘數據(從cbAvailable的偏移量開始)
if (pECB->cbAvailable > pECB->cbTotalBytes) { 
// TODO REad buffer
//pECB->ReadClient
} 
WriteContext(pECB, "</pre>"); 
EndContext(pECB); 
//該擴展程序已完成處理,服務器應斷開客戶端連接並釋放分配的資源
return HSE_STATUS_SUCCESS; 
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章