【小结】IIS7下的Http Native Module开发

时间:2023-03-09 19:48:55
【小结】IIS7下的Http Native Module开发

  今天接到Product Manager的通知,Exchange 2007环境下的Native Module不再需要开发(详情可见上篇),但最近几天一直在做Prototype,那就做一下小结吧,总结一下最近几天的收获。

  一. 准备工作:

  1. 开发前安装Windows Platform SDK,主要是使用其中的#include <httpserv.h>(用到的很多接口都可以在其中看到)

  2. WireShark,用来进行抓包,可以验证自己是否正确拿到http request和response的信息

  

  二. Visual Studio 2005编码:

  1. Native Module主要使用3个基本组件:

    A. HttpModule类 - HttpModule是当前模块的积累。在HttpModule类中我们将实现请求通知方法,这个方法是由IIS在相关的请求处理事件中调用的。(其中主要是定义我们的处理时间方法,例如onBeginRequest)

    B. HttpModule类工厂 - 针对每个被处理的请求,HttpModule类工厂可以创建或删除用于处理请求的模块

    C. RegisterModule类函数 - 一个Native Module只会实现一个此函数,用于导出函数,使IIS能够加载模块(我遇到一个问题,至今还没解决,就是此函数中我发现只能注册一个事件,如果多个会导致IIS ative sync pool stop掉,DLL用不起来)

  2. 其他具体编码可参见我的示例,具体开发流程可参见《IIS 7开发与管理完全参考手册》

  

  三. 安装此Native Module

  经过我的测试发现,我的Native Module能够工作,主要是做了以下几项工作:

  1. 编译后的DLL放置在C:\Windows\System32\inetsrv下

  2. 修改applicationHost.xml配置文件,C:\Windows\System32\inetsrv\config,在其中的<globalModules>中添加我们的模块

  3. IIS 7中,[Domain\User]下,Module中,右键选择Configure Native Module,然后选择Register,填入我们模块的信息。

  目前我还不确定2,3是否是重复了,但是我发现这两者都做的情况,我的Native Module是工作的,而3的Register不是修改2的配置文件,具体有待验证。

  经过以上三个步骤,我的Native Module可以工作了!目前可以拿到Http的Request Header的信息。希望这次小结,能对有开发此类需求的同学一点参考,由于此功能被PM去掉了,所以很遗憾这块我不能继续做下去,只能是小结啦。:-)

参考资料:

1. 《Professional IIS7》,Wrox出版社出版(Programmer to Programer的理念),非常详细的讲解IIS7,其中12章详细介绍了Http两类Module的开发。其中文版是《IIS 7开发与管理完全参考手册》

2. MSDN

  http://msdn.microsoft.com/en-us/library/ms690856(v=vs.90).aspx

Prototype代码附上,功能:取Http request的header信息

#define _WINSOCKAPI_
#include <windows.h>
#include <sal.h>
#include <httpserv.h>
#include "writeLog.h" // Create the module class.
class CTestNativeModule : public CHttpModule
{
//TODO
// Implement Notification Method/s
REQUEST_NOTIFICATION_STATUS
OnBeginRequest( IN IHttpContext * pHttpContext,
IN IHttpEventProvider * pProvider
)
{
WriteLog("--> CTestNativeModule, OnBeginRequest()");
// We won’t be using this, so confirm that to avoid compiler warnings
UNREFERENCED_PARAMETER( pProvider ); IHttpRequest* pHttpRequest = pHttpContext->GetRequest(); //dump request header
DumpRequestHeader(pHttpContext, pHttpRequest); WriteLog("<-- CTestNativeModule, OnBeginRequest()");
      
return RQ_NOTIFICATION_CONTINUE;
}
  void DumpRequestHeader(IHttpContext * pHttpContext, IHttpRequest* pHttpRequest)
{
WriteLog("--> CTestNativeModule, DumpRequestHeader()"); // Buffer size for returned variable values.
DWORD cbValue = ;
PCSTR pHeaderValue = (PCSTR) pHttpContext->AllocateRequestMemory( cbValue ); for(HTTP_HEADER_ID i = (HTTP_HEADER_ID); i < HttpHeaderRequestMaximum; i = (HTTP_HEADER_ID)((int)i + ))
{
pHeaderValue = pHttpRequest->GetHeader(i);
WriteLog(pHeaderValue);
} HTTP_REQUEST* rawHttpRequest = pHttpRequest->GetRawHttpRequest();
WriteLog("RawUrl", rawHttpRequest->pRawUrl); PCSTR pKey = ""; pKey = "Cmd";
pHeaderValue = pHttpRequest->GetHeader(pKey);
WriteLog(pKey, pHeaderValue); pKey = "DeviceId";
pHeaderValue = pHttpRequest->GetHeader(pKey);
WriteLog(pKey, pHeaderValue); pKey = "DeviceType";
pHeaderValue = pHttpRequest->GetHeader(pKey);
WriteLog(pKey, pHeaderValue); pKey = "AttachmentName";
pHeaderValue = pHttpRequest->GetHeader(pKey);
WriteLog(pKey, pHeaderValue); pKey = "MS-ASProtocolVersion";
pHeaderValue = pHttpRequest->GetHeader(pKey);
WriteLog(pKey, pHeaderValue); pKey = "X-EAS-Proxy";
pHeaderValue = pHttpRequest->GetHeader(pKey);
WriteLog(pKey, pHeaderValue); pKey = "User-Agent";
pHeaderValue = pHttpRequest->GetHeader(pKey);
WriteLog(pKey, pHeaderValue); /*
//Authorization
pKey = "Authorization";
pHeaderValue = pHttpRequest->GetHeader(pKey);
writeLog(pKey, pHeaderValue); //Content-Type
pKey = "Content-Type";
pHeaderValue = pHttpRequest->GetHeader(pKey);
writeLog(pKey, pHeaderValue); //Host
pKey = "Host";
pHeaderValue = pHttpRequest->GetHeader(pKey);
writeLog(pKey, pHeaderValue); //Content-Length
pKey = "Content-Length";
pHeaderValue = pHttpRequest->GetHeader(pKey);
writeLog(pKey, pHeaderValue);*/ WriteLog("<-- CTestNativeModule, DumpRequestHeader()");
} void DumpRequestContent(IHttpContext* pHttpContext, IHttpRequest* pHttpRequest)
{
// Create an HRESULT to receive return values from methods.
/*HRESULT hr;
// Allocate a 1K buffer.
DWORD cbBytesReceived = 1024;
void* pvRequestBody = pHttpContext->AllocateRequestMemory(cbBytesReceived);
hr = pHttpRequest->ReadEntityBody( pvRequestBody, cbBytesReceived, false, &cbBytesReceived, NULL);*/
}
}; // Create the module's class factory.
class CTestNativeModuleFactory : public IHttpModuleFactory
{
public:
HRESULT
GetHttpModule(
OUT CHttpModule ** ppModule,
IN IModuleAllocator * pAllocator
)
{
WriteLog("--> CTestNativeModuleFactory, GetHttpModule()"); UNREFERENCED_PARAMETER( pAllocator ); // Create a new instance.
CTestNativeModule * pModule = new CTestNativeModule; // Test for an error.
if (!pModule)
{
// Return an error if the factory cannot create the instance.
return HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
}
else
{
// Return a pointer to the module.
*ppModule = pModule;
pModule = NULL;
// Return a success status.
return S_OK;
}
WriteLog("<-- CTestNativeModuleFactory, GetHttpModule()");
} void
Terminate()
{
WriteLog("--> CTestNativeModuleFactory, Terminate()");
// Remove the class from memory.
delete this;
WriteLog("<-- CTestNativeModuleFactory, Terminate()");
}
}; // Create the module's exported registration function.
HRESULT
__stdcall
RegisterModule(
DWORD dwServerVersion,
IHttpModuleRegistrationInfo * pModuleInfo,
IHttpServer * pGlobalInfo
)
{
WriteLog("--> RegisterModule()");
HRESULT hr = S_OK; UNREFERENCED_PARAMETER( dwServerVersion );
UNREFERENCED_PARAMETER( pGlobalInfo ); // TODO
// Register for notifications
// Set notification priority CTestNativeModuleFactory* testNMFacotry = new CTestNativeModuleFactory; // Set the request notifications
// BeginRequest
hr = pModuleInfo->SetRequestNotifications(
testNMFacotry,
RQ_BEGIN_REQUEST, // Register for BeginRequest notifications
0); if( hr == S_OK ) // Do this only if there was no error
{
hr = pModuleInfo->SetPriorityForRequestNotification(
RQ_BEGIN_REQUEST, // which notification
PRIORITY_ALIAS_FIRST // what priority
);
}
WriteLog("<-- RegisterModule()");
return hr;
}