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; 
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值