【小結】IIS7下的Http Native Module開發

  今天接到Product Manager的通知,Exchange 2007環境下的Native Module再也不須要開發(詳情可見上篇),但最近幾天一直在作Prototype,那就作一下小結吧,總結一下最近幾天的收穫。windows

  一. 準備工做:app

  1. 開發前安裝Windows Platform SDK,主要是使用其中的#include <httpserv.h>(用到的不少接口均可以在其中看到)ide

  2. WireShark,用來進行抓包,能夠驗證本身是否正確拿到http request和response的信息函數

  

  二. Visual Studio 2005編碼:測試

  1. Native Module主要使用3個基本組件:this

    A. HttpModule類 - HttpModule是當前模塊的積累。在HttpModule類中咱們將實現請求通知方法,這個方法是由IIS在相關的請求處理事件中調用的。(其中主要是定義咱們的處理時間方法,例如onBeginRequest)編碼

    B. HttpModule類工廠 - 針對每一個被處理的請求,HttpModule類工廠能夠建立或刪除用於處理請求的模塊spa

    C. RegisterModule類函數 - 一個Native Module只會實現一個此函數,用於導出函數,使IIS可以加載模塊(我遇到一個問題,至今還沒解決,就是此函數中我發現只能註冊一個事件,若是多個會致使IIS ative sync pool stop掉,DLL用不起來)code

  2. 其餘具體編碼可參見個人示例,具體開發流程可參見《IIS 7開發與管理徹底參考手冊》orm

  

  三. 安裝此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;
}
相關文章
相關標籤/搜索