首页 | 社区 | 博客 | 招聘 | 文章 | 新闻 | 下载 | 读书 | 代码
亲,您未登录哦! 登录 | 注册

使用ISAPI过滤器增强IIS的功能

打印文章

分享到:

复旦大学计算机科学系 林 海  

  作为一个WWW服务器软件,微软公司的Internet Infomation Server(IIS)简单易
学,管理方便,得到了广泛的使用。您还可以通过ISAPI过滤器,进行自己定制的处
理,来增强IIS的功能。ISAPI过滤器可以定制以下的处理:接收HTTP协议头预处理、
发送HTTP协议头预处理、发送生数据预处理、获得生数据预处理、HTTP会话结束信息
处理、自定义的安全认证机制、URL映射信息处理、日志记录处理等。灵活利用这些定
制处理,您可以完成许多看似难以实现的功能,得到意想不到的效果。但是ISAPI过滤
器使用不当也会影响服务器的性能。
ISAPI过滤器的开发非常简单,只需要完成三个接口DLL函数即可。它们是
GetFilterVersion()、HttpFilterProc()、TerminateFilter(),大家可以查看MSDN
了解详细的用法。ISAPI过滤器是DLL文件,一般用C/C++语言开发。为使ISAPI过滤器
能够运行,您需要在注册表的
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\W3SVC\Parameters下建
立一个字符串项,其名称为"Filter Dlls",值为ISAPI过滤器文件的全路径名称。若
这个字符串项已经存在,只需把它的全路径名称加入其中,不同的ISAPI过滤器文件
之间用";"分隔,您可以根据执行的优先顺序加在适当的位置。设置好后重新启动IIS
服务,您的ISAPI过滤器就发挥作用了。

下面作者举二个具体的应用例子。

一、虚拟主机WWW站点的实现

  所谓虚拟主机WWW站点,是指不同的域名占用同一个IP地址,各自拥有自己的主页。
这样您可以在同一台机器上为几个甚至几十个公司建立各自的WWW站点。IIS 3.0不
提供虚拟主机WWW站点的功能,但是我们可以通过ISAPI过滤器来实现它。其原理是
通过URL映射信息处理,将不同的域名重新映射到不同的物理文件。

下面是它的源程序。

fmulti.def:
LIBRARY fmulti
EXPORTS GetFilterVersion
HttpFilterProc
TerminateFilter

fmulti.c:
#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <httpfilt.h>

#define baseroot "C:\\InetPub\\wwwroot\\"

BOOL WINAPI GetFilterVersion(HTTP_FILTER_VERSION *pVer)
{
pVer->dwFilterVersion = HTTP_FILTER_REVISION;
strcpy(pVer->lpszFilterDesc, "fmulti");
pVer->dwFlags = SF_NOTIFY_URL_MAP | SF_NOTIFY_ORDER_HIGH;
/* 过滤的内容 */
return TRUE;
}

DWORD WINAPI HttpFilterProc(HTTP_FILTER_CONTEXT *pfc,
DWORD noteType,
VOID *pvNote)
{
DWORD namelen = 256;
char svrname[256];
char phyfile[280];

*svrname = 0;
(pfc->GetServerVariable)(pfc, "SERVER_NAME",svrname, &namelen);
_strlwr(svrname);
strcpy(phyfile,
  ((PHTTP_FILTER_URL_MAP)pvNote)->pszPhysicalPath + strlen(baseroot));
/* 以下根据域名设置需访问的物理文件 */
if (strcmp(svrname, "ca.best.net")==0)
{
  sprintf(((PHTTP_FILTER_URL_MAP)pvNote)->pszPhysicalPath,
   "C:\\InetPub\\caroot\\%s",
   phyfile);
}
else if (strcmp(svrname, "cb.best.net")==0)
{
  sprintf(((PHTTP_FILTER_URL_MAP)pvNote)->pszPhysicalPath,
   "C:\\InetPub\\cbroot\\%s",
   phyfile);
}
return SF_STATUS_REQ_NEXT_NOTIFICATION;
}

BOOL WINAPI TerminateFilter(DWORD dwFlags)
{
return TRUE;
}

二、对访问内容进行统计分析
  通常我们在需要计数的页面内放一个计数器,或者使用ASP文件来实现计数功能。
这种方法不能适用于如README.TXT等其他非HTML格式的文件。如果使用IIS的日志功
能又太占用空间而不方便。作者通过定制URL映射信息处理来跟踪感兴趣的几个文件
的计数统计,将结果记录在一个文件中。

下面是它的源程序。

fcount.def:
LIBRARY fcount
EXPORTS GetFilterVersion
HttpFilterProc
TerminateFilter

fcount.c:
#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <httpfilt.h>

#define logfile "C:\\InetPub\\fcount.log"
#define pages 5
char* urls[] = {
  "/default.htm",
  "/banner.gif",
  "/product/readme.txt",
  "/product/product1.htm",
  "/product/product2.htm"
  };
int counts[pages];

BOOL WINAPI GetFilterVersion(HTTP_FILTER_VERSION *pVer)
{
int i;

pVer->dwFilterVersion = HTTP_FILTER_REVISION;
strcpy(pVer->lpszFilterDesc, "fcount");
pVer->dwFlags = SF_NOTIFY_URL_MAP; /* 过滤的内容 */

for (i=0; i<pages; i++)
{
  /* 从文件读入初始计数值 */
  counts[i] = GetPrivateProfileInt("VisitCounter",
   urls[i],
   0,
   logfile);
}
return TRUE;
}

DWORD WINAPI HttpFilterProc(HTTP_FILTER_CONTEXT *pfc,
DWORD noteType,
VOID *pvNote)
{
int i;
char lurl[512];
char buf[16];

strcpy(lurl, ((PHTTP_FILTER_URL_MAP)pvNote)->pszURL);
_strlwr(lurl);
for (i=0; i<pages; i++)
{
  if (strcmp(lurl, urls[i])==0)
  {
   counts[i] ++; /* 计数值增加 */
   if (counts[i]%10==0)
   {
    /* 当计数值满10时记入文件,以免系统突然死掉时数据全部丢失 */
    _itoa(counts[i], buf, 10);
    WritePrivateProfileString("VisitCounter",
     urls[i],
     buf,
     logfile);
   }
   break;
  }
}
return SF_STATUS_REQ_NEXT_NOTIFICATION;
}

BOOL WINAPI TerminateFilter(DWORD dwFlags)
{
int i;
char buf[16];

for (i=0; i<pages; i++)
{
  /* 系统停止时将计数值写入文件 */
  _itoa(counts[i], buf, 10);
  WritePrivateProfileString("VisitCounter",
   urls[i],
   buf,
   logfile);
}
return TRUE;
}

以上二个例子作者使用VC 6.0编译,在WINNT 4.0 + SP3 和 IIS 3.0上调试通过。

本栏文章均来自于互联网,版权归原作者和各发布网站所有,本站收集这些文章仅供学习参考之用。任何人都不能将这些文章用于商业或者其他目的。( Pfan.cn )

编程爱好者论坛

本栏最新文章