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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏QQ音乐技术团队的专栏

Android系统线控和歌曲信息屏显的那点事

目前Android系统中主流的音乐播放器都支持线控的功能,线控设备包括有线耳机和蓝牙耳机或蓝牙车机,当不方便操作手机的时候可以通过线控来控制音乐的播...

3278
来自专栏温安适的blog

2个小bug,有点小门道

2017年的某日,小辉(我的同事)遇到了一个bug,解决了一下午还是没有找到,气的摔键盘,骂人,我看在眼里,急在心中。

4187
来自专栏Vamei实验室

安卓第七夜 雅典学院

我之前只使用了一种持续保存数据的方法,即SharedPreferences。然而,SharedPreferences只能存储少量松散的数据,并不适合大量数据的存...

1768
来自专栏纯洁的微笑

springboot(六):如何优雅的使用mybatis

这两天启动了一个新项目因为项目组成员一直都使用的是mybatis,虽然个人比较喜欢jpa这种极简的模式,但是为了项目保持统一性技术选型还是定了 mybatis。...

32912
来自专栏ASP.NET MVC5 后台权限管理系统

ASP.NET MVC5+EF6+EasyUI 后台管理系统(53)-工作流设计-我的批阅

前言:由于工作原因工作流一直没时间更新,虽然没有更新,但是批阅和申请差不多,改变一下数据的状态字段就行,有几个园友已经率先完成了 说句实话,一个工作流用文章表达...

27510
来自专栏Spark学习技巧

重要 | mr使用hcatalog读写hive表

企业中,由于领导们的要求,hive中有数据存储格式很多时候是会变的,比如为了优化将tsv,csv格式改为了parquet或者orcfile。那么这个时候假如是m...

582
来自专栏Android开发与分享

【Android】数据存储(三) 数据库(SQLite)

3377
来自专栏后端之路

junit测试之第三方组件mock

今天某个一直稳定运行的测试挂了,没有开发同学出来认领。 ? 对应模块的小伙伴询问此处依赖的环境是哪个,可以去调查失败的原因。 好吧,回顾一下关于第三方组件mo...

1945
来自专栏蜉蝣禅修之道

iOS开发之NSURLProtocol的那些坑

2568
来自专栏Spark学习技巧

hadoop系列之MR经典案例分享二

4、MapReduce的join(hive已经实现) http://database.51cto.com/art/201410/454277.htm ? 这三种...

31210

扫码关注云+社区