【小结】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 = 512;

        PCSTR pHeaderValue = (PCSTR) pHttpContext->AllocateRequestMemory( cbValue );



        for(HTTP_HEADER_ID i = (HTTP_HEADER_ID)0; i < HttpHeaderRequestMaximum; i = (HTTP_HEADER_ID)((int)i + 1))

        {

            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;

}

你可能感兴趣的:(Module)