ISAPI(Internet Server Application Programming Interface)作为一种可用来替代CGI的方法,是由微软和Process软件公司联合提出的Web服务器上的API标准。ISAPI与Web服务器结合紧密,功能强大,能够获得大量的信息,因此利用ISAPI可以开发出灵活高效的Web服务器增强程序。由于ISAPI程序与Web服务器的关系,使得ISAPI接口在安全方面有一定的研究价值。本文主要讨论ISAPI在IIS和VC++ 6.0中的实现。

一、ISAPI接口和CGI接口的不同。

ISAPI程序和CGI程序完成类似的功能,但是实现方法不同。

1、ISAPI程序以DLL形式被Web服务器加载到自己的进程空间中,因此和服务器共用同一个地址空间,且在没有客户请求时可以将其从内存中卸载;而对客户端发来的每个对CGI程序的请求则需要服务器为它单独启动一个进程,这需要耗费大量的时间和内存。当并发的请求数目很大时,使用CGI在效率上不如ISAPI。

2、CGI程序通过环境块和标准输入输出与Web服务器进行通信,而ISAPI程序与服务器结合得更为紧密,与服务器共享同一个进程上下文,主要通过一个参数块与服务器进行交互,可以从服务器那里获得关于当前HTTP连接的大量信息。

ISAPI主要分为ISA和ISAPI Filter两部分。ISA方法相对而言要传统一些,利用一些特殊的链接,指向服务器的作业,供程序开发人员设计一些扩展功能;而ISAPI过滤器则倾向于构造服务器直接调用的模块,提供一种无缝链接部件用于监测直接来自于服务器的HTTP请求。

二、ISA

ISA(Internet Server Application)也可称为ISAPI DLL,其功能和CGI程序的功能直接相对应,使用方法和CGI也类似,由客户端在URL中指定其名称而激活。例如下面的请求将调用服务器的虚拟可执行目录Scripts下的function.dll(ISAPI DLL必须放在服务器的虚拟可执行目录下):
http://www.abc.com/Scripts/function.dll?

ISA和服务器之间的接口主要有两个:GetExtentionVersion( )和HttpExtentionProc( )。任何ISA都必须在其PE文件头的引出表中定义这两个引出函数,以供Web服务器在适当的时候调用。

1、当服务器刚加载ISA时,它会调用ISA提供的GetExtentionVersion( )来获得该ISA所需要的服务器版本,并与自己的版本相比较,以保证版本兼容。函数原型如下:

1BOOL WINAPI GetExtentionVersion(HSE_VERSION_INFO *version); 
2typedef struct _HSE_VERSION_INFO 
3
4DWORD dwExtensionVersion; //版本号 
5CHAR lpszExtensionDesc[HSE_MAX_EXT_DLL_NAME_LEN]; //关于ISA的描述字符串 
6} HSE_VERSION_INFO, *LPHSE_VERSION_INFO; 

2、ISA的真正入口是HttpExtentionProc( ),它相当于普通C程序的main( )函数,在这个函数中根据不同的客户请求作不同的处理。服务器和HttpExtentionProc( )之间是通过扩展控制块(Extention Control Block)来进行通信的,即ECB中存放入口参数和出口参数,包括服务器提供的几个回调函数的入口地址。函数原型如下:

1DWORD HttpExtensionProc( EXTENSION_CONTROL_BLOCK *pECB ); 

ECB的结构定义如下(IN表示入口参数,OUT表示出口参数):

 1typedef struct _EXTENSION_CONTROL_BLOCK 
 2
 3DWORD cbSize; //IN,本结构的大小,只读 
 4DWORD dwVersion //IN,版本号,高16位为主版本号,低16位为次版本号 
 5HCONN ConnID; //IN,连接句柄,由服务器分配,ISA只能读取该值 
 6DWORD dwHttpStatusCode; //OUT,当前完成的事务状态 
 7CHAR lpszLogData[HSE_LOG_BUFFER_LEN]; //OUT,需要写入到日志文件中的内容 
 8LPSTR lpszMethod; //IN,等价于CGI的环境变量REQUEST_METHOD 
 9LPSTR lpszQueryString; //IN,等价于环境变量QUERY_STRING 
10LPSTR lpszPathInfo; //IN,等价于环境变量PATH_INFO 
11LPSTR lpszPathTranslated; //IN,等价于环境变量PATH_TRANSLATED 
12DWORD cbTotalBytes; //IN,等价于环境变量CONTENT_LENGTH 
13DWORD cbAvailable; //IN,缓冲区中的可用字节数 
14LPBYTE lpbData; //IN,缓冲区指针,指向客户端发来的数据 
15LPSTR lpszContentType; //IN,等价于环境变量CONTENT_TYPE 
16
17//回调函数,用于返回服务器的连接信息或特定的服务器详细情况 
18BOOL ( WINAPI * GetServerVariable ) 
19( HCONN hConn, 
20LPSTR lpszVariableName, 
21LPVOID lpvBuffer, 
22LPDWORD lpdwSize ); 
23
24BOOL ( WINAPI * WriteClient ) //回调函数,从客户端的HTTP请求中读取数据 
25( HCONN ConnID, 
26LPVOID Buffer, 
27LPDWORD lpdwBytes, 
28DWORD dwReserved ); 
29
30BOOL ( WINAPI * ReadClient ) //回调函数,向客户端发送数据 
31( HCONN ConnID, 
32LPVOID lpvBuffer, 
33LPDWORD lpdwSize ); 
34
35BOOL ( WINAPI * ServerSupportFunction ) //回调函数,访问服务器的一般和特定功能 
36( HCONN hConn, 
37DWORD dwHSERRequest, 
38LPVOID lpvBuffer, 
39LPDWORD lpdwSize, 
40LPDWORD lpdwDataType ); 
41
42} EXTENSION_CONTROL_BLOCK, *LPEXTENSION_CONTROL_BLOCK; 

在上述ECB中,服务器不但提供了当前HTTP连接的句柄和一些变量,而且提供了4个回调函数给ISA调用,从而使ISA可以获得更详尽的信息。

三、ISAPI Filter

ISAPI Filter位于服务器和客户端之间,能够对服务器和客户端之间的通信进行预处理和后处理,比如对通信进行加密/解密、提供对客户进行身份验证的新方法、提供自定义的日志记录等,在CGI中没有与ISAPI Filter直接相对应的部分。

ISAPI Filter与服务器之间的接口有两个:GetFilterVersion( )和HttpFilterProc( )。任何
ISAPI Filter都必须引出这两个函数以供服务器调用。

1、在注册表的如下键值中存放着所有ISAPI Filter的文件名,IIS服务器启动时从该键值中获得
Filter的文件名并加载它们。

1HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/W3SVC/Parameters/FilterDLL 

2、然后服务器调用每个Filter提供的GetFilterVersion( )函数,获得版本号以及该Filter希望处理的事件,即ISAPI Filter通过引出GetFilterVersion( )函数来告知服务器自己希望处理什么类型的事件,因为ISAPI Filter是通过事件来激活的,当满足条件的事件到达时,服务器就会调用Filter引出的主函数HttpFilterProc( )对该事件进行处理。GetFilterVersion( )的原型如下:

1BOOL WINAPI GetFilterVersion( 
2DWORD dwServerFilterVersion; //IN,服务器使用的版本规范 
3DWORD dwFilterVersion; //OUT,过滤器使用的版本规范 
4CHAR lpszFilterDesc[SF_MAX_FILTER_DESC_LEN+1]; //OUT,对该过滤器的描述字符串 
5DWORD dwFlags //OUT,事件和优先级标志 
6); 

事件和优先级标志dwFlasg的取值在MSDN中有详细解释,其中包括该Filter被调用的优先级,一般应使用默认的低优先级,否则可能会对系统的性能造成很大影响。

3、HttpFilterProc( )是ISAPI Filter主要的入口函数,它根据当前的事件的不同作出不同的处理。服务器通过如下的参数块和Filter进行交互,这个参数块的作用和ISA中的ECB类似。

 1typedef struct _HTTP_FILTER_CONTEXT 
 2
 3
 4DWORD cbSize; //IN,本参数块的大小 
 5DWORD Revision; //IN 
 6PVOID ServerContext; //IN,由server使用本参数 
 7DWORD ulReserved; //IN,由server使用本参数 
 8BOOL fIsSecurePort; //IN,事件是否发生在安全端口上 
 9PVOID pFilterContext; //IN/OUT,与本次请求相关的上下文 
10
11//回调函数,取得关于服务器和本次连接的信息 
12BOOL (WINAPI * GetServerVariable) ( 
13struct _HTTP_FILTER_CONTEXT * pfc, 
14LPSTR lpszVariableName, 
15LPVOID lpvBuffer, 
16LPDWORD lpdwSize 
17); 
18
19BOOL (WINAPI * AddResponseHeaders) ( //回调函数,给HTTP响应添加一个标头 
20struct _HTTP_FILTER_CONTEXT * pfc, 
21LPSTR lpszHeaders, 
22DWORD dwReserved 
23); 
24
25BOOL (WINAPI * WriteClient) ( //回调函数,将原始数据发送给客户端 
26struct _HTTP_FILTER_CONTEXT * pfc, 
27LPVOID Buffer, 
28LPDWORD lpdwBytes, 
29DWORD dwReserved 
30); 
31
32VOID * (WINAPI * AllocMem) ( //回调函数,分配内存。 
33struct _HTTP_FILTER_CONTEXT * pfc, 
34DWORD cbSize, 
35DWORD dwReserved 
36); 
37
38BOOL (WINAPI * ServerSupportFunction) ( //回调函数,访问服务器的一般和特定功能 
39struct _HTTP_FILTER_CONTEXT * pfc, 
40enum SF_REQ_TYPE sfReq, 
41PVOID pData, 
42DWORD ul1, 
43DWORD ul2 
44); 
45
46} HTTP_FILTER_CONTEXT, *PHTTP_FILTER_CONTEXT; 

四、VC++ 6.0中对ISAPI的支持

VC++ 6.0中定义了5个相关的类以简化ISAPI的编程工作:CHttpServer、CHttpServerContext、CHttpFilter、CHttpFilterContext、CHtmlStream,这5个类都没有父类。其中CHttpServer和CHttpServerContext主要用来编写ISA,CHttpFilter和CHttpFilterContext则用来编写ISAPI Filter,而CHtmlStream则用来操作内存中的HTML文件,为其它的4个类提供服务。CHttpServer在每个ISA中只能有一个实例,一个CHttpServer可以对应多个CHttpServerContext实例,每个
CHttpServerContext处理一个客户请求,这样可以处理并发的HTTP请求;CttpFilter和CHttpFilterContext之间的关系与此类似,在每个ISAPI Filter中只能有一个CHttpFilter实例,但是可以有多个CHttpFilterContext来处理并发的事件。CHttpServer和CHttpFilter是独立的类,它们可以共存于一个DLL中,也可以分别在不同的DLL中。

一个ISA可以提供多个命令,每个命令对应于CHttpServer(或其子类)的一个成员函数,客户端可以在URL中指定命令名及其参数。在VC++ 6.0中是通过parse map来实现这种对应的。

Parse map类似MFC中的Windows消息分发机制,通过使用VC提供的DECLARE_PARSE_MAP、BEGIN_PARSE_MAP、ON_PARSE_COMMAND、ON_PARSE_COMMAND_PARAMS、DEFAULT_PARSE_COMMAND、END_PARSE_MAP等宏,可以实现对不同的命令的处理。每个CHttpServer中只能建立一个parse map,当客户端给ISA发来命令的时候,parse map可以分析HTTP请求中的命令名及其参数,将该命令与相应的成员函数关联起来,即由该成员函数处理该命令。以MSDN中的例子程序pinball为例,该例中有下面这样一个表单:

 1<form method=get action="pinball.dll?"> 
 2<input type="hidden" name="MfcISAPICommand" VALUE="GetImage"> 
 3<input type="radio" name="Favorite" value="1" checked> Attack from Mars<br> 
 4<input type="radio" name="Favorite" value="2"> Twilight Zone<br> 
 5<input type="radio" name="Favorite" value="3"> The Addams Family<br> 
 6<input type="radio" name="Favorite" value="4"> Cirqus Voltaire<br> 
 7<input type="radio" name="Favorite" value="0"> I don't see it here<br> 
 8<br> 
 9<input type="submit" value="Show Me!"> 
10</form> 

当客户端选中了上面的表单中的“Attack from Mars”这一项并点击了submit按钮后,服务器端
最终将得到如下的URL串:

1http://www.abc.com/pinball.dll?MfcISAPICommand=GetImage&Favorite=1 

在该URL串中,命令名是GetImage,参数Favorite的值是1,因此pinball.dll中的如下成员函数
将被调用以处理该请求,其中参数dwChoice对应URL中的参数Favorite:

1void CPinballExtension::GetImage(CHttpServerContext* pCtxt, long dwChoice); 

而parse map需要按照下面的形式定义:

 1//CPinballExtension从CHttpServer派生而来 
 2BEGIN_PARSE_MAP(CPinballExtension, CHttpServer) 
 3
 4//GetImage是CPinballExtension的成员函数,且有一个long型的参数即dwChoice 
 5ON_PARSE_COMMAND(GetImage, CPinballExtension, ITS_I4) 
 6
 7//该参数在URL中的名字为Favorite 
 8ON_PARSE_COMMAND_PARAMS("Favorite") 
 9
10END_PARSE_MAP(CPinballExtension) 

而对于ISAPI Filter,在VC中可以通过重载CHttpFilter(或其子类)的不同的成员函数来实现对不同事件的处理。可重载的函数如下,每一个成员函数均对应一个或多个事件:

1OnPreprocHeaders 
2OnAuthentication 
3OnUrlMap 
4OnSendRawData 
5OnReadRawData 
6OnLog 
7OnEndOfNetSession 

MSDN提供了4个关于ISAPI的编程实例:counter、MFCUCASE、pinball、wwwquote,有兴趣的可看看,本文主要不是介绍编程,所以不再赘述。

参考资料:

1、MSDN
2、《精通CGI编程》,丁一强等,清华大学出版社

转载于:https://www.cnblogs.com/shinyzhu/archive/2005/06/12/173057.html

IIS的ISAPI接口简介相关推荐

  1. Java Iterator 接口简介和简单用法.

    Iterator 的中文意思是迭代器. 单单从中文翻译也不易理解迭代器的意思啊,  其实Iterator是1个接口,  它的作用就是遍历容器的所有元素. 一, Iterator 接口简介 Iterat ...

  2. java中接口文件创建_功能接口简介–在Java 8中重新创建的概念

    java中接口文件创建 世界各地的所有Java开发人员都将至少使用以下接口之一:java.lang.Runnable,java.awt.event.ActionListener,java.util.C ...

  3. 功能接口简介–在Java 8中重新创建的概念

    世界各地的所有Java开发人员都将至少使用以下接口之一:java.lang.Runnable,java.awt.event.ActionListener,java.util.Comparator,ja ...

  4. 接口简介 java 1614100890

    接口简介 java 1614100890 生活中的接口 不同厂家的接口 家里的电器都可以使用 为什么? 因为他们是按照相同的规范设计的 不同厂家生产的电脑,USB接口也是同理 相关设置都可以直接使用 ...

  5. 以太网接口MII,RMII,SMII,GMII总线接口简介

    以太网接口MII,RMII,SMII,GMII总线接口简介 所有的这些接口都从MII而来,MII是(MediumIndependent Interface)的意思,是指不用考虑媒体是铜轴.光纤.电缆等 ...

  6. TypeScript基础入门 - 接口 - 简介

    转载地址 TypeScript基础入门 - 接口 - 简介 项目实践仓库 https://github.com/durban89/typescript_demo.git tag: 1.0.6 为了保证 ...

  7. 路由器广域网接口简介

    路由器广域网接口简介1.WAN侧FE接口WAN侧FE接口工作在网络层,可以配置IP地址,处理三层协议,提供路由功能,FE接口支持的最大速率为100Mbit/s2.WAN侧GE接口WAN侧GE接口工作在 ...

  8. *********ADO接口简介*********

    /***********************ADO接口简介*********************************/ ADO库包含三个基本接口:_ConnectionPtr接口._Com ...

  9. keil 生成三角波dac0832_弹性波,时域显式接口简介

    COMSOL Multiphysics® 软件 5.5 版本中提供了一个节省内存的物理场接口,用于模拟弹性波在固体中的传播(结构中的振动).该弹性波,时域显式接口基于时域显示时间积分方案的高阶间断伽辽 ...

  10. 调用通达信l2行情接口简介说明

    调用通达信l2行情接口简介说明. 概述 使用纯Python类似TradeX通达信市场接口的实现 因为之前TradeX采用接口Python调用扩展的方式C代码实现,性能有很多限制,比如只支持32位Pyt ...

最新文章

  1. SQLServer 2005 XML 在 T-SQL 查询中的典型应用[转]
  2. Linux MTD系统剖析【转】
  3. redhat 5.6下网卡冗余实验
  4. socket穿透代理代码(C++版)
  5. .NET 6 Preview 6 Released
  6. python 网格交易源码下载_GitHub - xiongyixiaoyang/grid-trading: 网格交易(期货) ,基于网格交易方法的交易策略...
  7. Leaf服务器框架从入门到放弃(一)认识Leaf和安装Leaf环境
  8. Linux下socket通信和epoll
  9. linux下sqlite3的应用
  10. camunda流程定义表无数据_【经验】数据可视化分析操作指南
  11. 每单配送费41元,Nuro无人车正式开始自动驾驶送货
  12. Spring框架错误之org.springframework.beans.factory.BeanCreationException
  13. 浅谈SEO翻倍提升网站流量
  14. paip.c++ qt __gxx_personality_sj0 __gxx_personality_v0问题的解决
  15. BNU29140 Taikotaiko(概率)
  16. 前端布局 flex布局
  17. 怎样在养殖订阅号文章中添加一键拨号功能
  18. MATLAB——网格图画法
  19. 《ANSYS 14.0超级学习手册》一1.2 ANSYS 14.0简介
  20. 图片裁剪上传插件—jquery.photoClip.js

热门文章

  1. CodeSys之CRC校验
  2. NAT穿透技术简介和实现方案分析
  3. java ee 结构图,javaee体系结构图
  4. Iphone版音乐计算机,iPhone网易云音乐app的离线音乐导出到电脑
  5. 3.1.4_cardView原理解析
  6. 怎么用计算机测出来体脂,怎么测体脂比较科学
  7. 网络七层协议与网络四层协议
  8. azure微软文字转语音工具​AzureTools​使用
  9. 移动开发者必须了解的10大跨平台工具
  10. 车牌识别(基于模板匹配算法)