用delphi编写ISAPI过滤器

来源:互联网 发布:我的世界java安装 编辑:程序博客网 时间:2024/04/30 08:25

======================================================
注:本文源代码点此下载
======================================================

用delphi编写isapi过滤器

实 现web 站 点 同 时 对gb 码 和big 码 的 支 持

---- 目 前 由 于 汉 字 内 码 的 不 统 一, 互 联 网 上 的 中 文 站 点 为 了 实 现 对 于 不 同 用 户 的 支 持, 一 般 采 取 建 立 两 套 主 页, 分 别 用gb 和big 码 来 编 写。 这 样 做 显 然 要 增 加 站 点 的 维 护 工 作, 更 新 主 页 时 要 同 时 更 新 两 部 分。 而 且 如 果 主 页 内 容 是 实 时 更 新 的, 采 用 手 工 维 护 两 套 主 页 的 方 法 显 然 不 行 了。 本 文 介 绍 了 用isapi 过 滤 器 来 动 态 产 生 另 外 一 套 内 码 主 页 的 方 法, 这 样 就 可 以 只 制 作 一 套 主 页 就 同 时 支 持gb 码 和big5 码。

---- 基 本 的 思 路, 编 写 一 个isapi 过 滤 器, 对 于 所 有 最 终 返 回 给 用 户 的html 文 本, 实 行 内 码 转 换。 这 样 用 户 看 到 的 将 是 他 期 望 的 编 码 方 式。 isapi 过 滤 器 可 以 作 为web server 横 向 功 能 扩 展。 当 某 个 预 先 定 义 好

---- 的 服 务 器 端 的 事 件 发 生 时,iis 就 调 用 用 户 定 义 好 的 过 程, 此 时 就 可 以 通 过 修 改iis 传 来 的 数 据 来 改 变iis 的 行 为。iis 预 定 义 的 事 件 如 下:

sf_notify_read_raw_data

---- 当iis 要 从 用 户 读 入 数 据 时 发 生。 过 滤 器 可 以 在iis 处 理 他 们 之 前 检 查 甚 至 修 改 用 户 输 入 的 原 始 数 据。

---- sf_notify_preproc_headers

---- iis 预 处 理http 请 求 包 头 后 发 生。 过 滤 器 可 以 检 查 修 改 增 加 包 头。

---- sf_notify_authentication

---- iis 试 图 验 证 用 户 身 份 时 发 生。 过 滤 器 可 以 实 现 自 己 的 验 证 方 案。

---- sf_notify_url_map

---- iis 试 图 将url 解 释 为 物 理 文 件 时。 过 滤 器 可 以 将 请 求 重 定 向 到 其 他 的 文 件。

---- sf_notify_access_denied

---- 当 身 份 验 证 失 败 时 发 生。

---- sf_notify_send_raw_data

---- 当 其 他 程 序 处 理 完,iis 准 备 将 数 据 发 回 给 用 户 时 发 生。 我 们 的 过 滤 器 就 通 过 此 事 件, 转 换 内 码。

---- sf_notify_log

---- 当iis 写 记 录 到log 文 件 时。 过 滤 器 可 以 搜 集 更 多 的 信 息 写 入 记 录 文 件 中。

---- sf_notify_end_of_request

---- 当 一 个http 请 求 结 束 时 发 生。 过 滤 器 可 以 实 现 基 于 请 求 的 处 理。 由 于 这 是 在iis 3.0 中 新 增 的,delphi 中 的isapi2.pass 单 元 中 没 有 相 应 的 定 义 可 以 手 工 加 入sf_notify_end_of_request=$80

---- sf_notify_end_of_net_session

---- 连 接 结 束 时。 注 意 如 果 浏 览 器 支 持"keep-alive", 一 次 连 接 可 能 包 含 几 个http 请 求。 过 滤 器 可 以 用 他 来 释 放 一 些 用 户 的 资 源。

---- 我 们 要 实 现 动 态 的 内 码 转 换, 只 要 过 滤 器 处 理sf_notify_send_raw_data 事 件, 将iis 处 理 好 的 数 据 转 换 成 需 要 的 内 码 就 可 以 实 现 内 码 的 动 态 转 换。 具 体 程 序 有 两 个 问 题 需 要 注 意:

过 滤 器 只 能 处 理 返 回 是html 格 式 的, 其 他 图 片 等 二 进 制 请 求 无 须 也 不 允 许 转 换。

对 于 返 回 的html, 只 处 理 实 际 数 据, 其 他http 协 议 的 包 不 应 该 处 理。

编 程

---- 每 个isapi 过 滤 器dll 必 须 输 出 两 个 供iis 使 用 的 函 数:

---- getfilterversion() 和httpfilterproc()。 下 面 分 别 讲 述。

---- getfilterversion()

---- 用 于 初 始 化 和 处 理 事 件 的 登 记。 例 程 没 有 初 始 工 作 要 做, 只 是 简 单 的 登 记 了 要 处 理 的 两 个 事 件 和 其 他 一 些 标 志。

function getfilterversion(var pver:

thttp_filter_version): bool; stdcall;

begin

//过滤器要处理的事件和其他一些标志

pver.dwflags := (

sf_notify_nonsecure_port

//过滤器只在一般端口上使用

or sf_notify_send_raw_data

//处理发送数据事件

or $80 // sf_notify_end_of_request

处理请求结束事件

or sf_notify_order_default

//过滤器使用缺省优先级

);

//过滤器使用的版本http_filter_revision

返回当前版本

pver.dwfilterversion := http_filter_revision;

//过滤器的描述

pver.lpszfilterdesc[0]:='a';pver.lpszfilterdesc[1]:=#0;

result:=true; //初始化成功

end;

httpfilterproc()

---- 由iis 回 调, 是 过 滤 器 的 实 际 处 理 部 分。

---- 其 中 参 数notificationtype 是 该 调 用 的 事 件 类 型, 如 果 过 滤 器 处 理 多 个 事 件, 可 以 检 查 该 值 来 区 分 事 件。

---- pvnotification 是 一 个 根 据 事 件 类 型 可 变 结 构 的 参 数。 对 于sf_notify_send_raw_data, 他 的 结 构 如 下:

thttp_filter_raw_data = record

pvindata: pointer;//指向数据区

cbindata: dword;//数据大小

cbinbuffer: dword;//缓冲的大小

dwreserved: dword;//保留

end;

---- 其 中 的pvindata 就 是 要 发 送 的 数 据 指 针。 其 他 的 结 构 请 参 看 有 关 资 料 这 里 不 再 详 述。

---- 第 一 个 参 数var pfc: thttp_filter_context 是 过 滤 器 的 环 境 指 针, 其 中 的pfiltercontext 是 一 个 用 户 使 用 的 指 针, 用 来 保 存 和 一 个http 连 接 相 关 的 信 息, 这 样 过 滤 器 可 以 区 分 出 正 在 处 理 的 是 否 是 以 前 曾 处 理 过 的 连 接。 因 为 一 个 请 求 将 会 产 生 多 个sf_notify_send_raw_data 事 件, 过 滤 器 必 须 能 够 区 分 他 们。

---- 程 序 的 流 程 是: 当 连 接 建 立 后,pfiltercontext 被iis 初 始 化 为nil(0), 第 一 次sf_notify_send_raw_data 调 用 时, 过 滤 器 要 检 查 返 回 的mime, 如 果 不 是html 则 将pfiltercontext 置 为pointer(2)( 将 指 针 当 作 变 量 用, 因 为 我 们 只 要 一 个 标 志), 随 后 的 发 送 事 件 调 用 将 直 接 返 回。 请 求 结 束 后, 发 生sf_notify_end_of_request 事 件, 过 滤 程 序 将pfiltercontext 复 位 为nil。

---- 如 果 是html, 则 将pfiltercontext 置 为pointer(1), 随 后 的 调 用 就 将 对 数 据 进 行 内 码 的 转 换, 然 后 将pfiltercontext 置 为pointer(3)。 如 果 还 有 后 续 的 调 用, 则 再 将pfiltercontext 置 为pointer(1), 直 到 全 部 数 据 发 送 完 成。

function httpfilterproc(var pfc: thttp_filter_context;

notificationtype: dword;pvnotification: pointer): dword; stdcall;

var

p:phttp_filter_raw_data;

i:integer;

pc:pchar;

begin

if notificationtype=$80 then

//是sf_notify_end_of_request将pfiltercontext复位

begin

pfc.pfiltercontext:=nil;

end

else

begin

p:=phttp_filter_raw_data(pvnotification);

pc:=p^.pvindata;

case integer(pfc.pfiltercontext) of

0: //第一次调用,要检查mime

begin

pfc.pfiltercontext:=pointer(2);

i:=0;

while i

----

下 面 是 完 整 的 程 序 文 件(gb2bigfiler.dpr), 其 中 的u_gb2big_tab 单 元 完 成gb 码 到big5, 码 的 转 换, 这 里 不 再 细 述, 有 兴 趣 的 读 者 可 以 到 后 文 提 到 的 笔 者 的 站 点 去 下 载 源 码。

library gb2bigfiler;

uses

sysutils,math, classes, windows,

isapi2, //delphi中isapi过滤器单元

u_gb2big_tab; //包含将gb码转换成big5码的过程gb2big

//下面两个函数的定义见上文

function httpfilterproc(...); begin ... end;

function getfilterversion(...); begin ... end;

exports

httpfilterproc index 1, getfilterversion index 2;

begin end.

---- 读 者 一 定 注 意 到 了, 这 个 过 滤 器 将 所 有 返 回 的html 都 转 换 成 了big5 码, 那 么gb 码 又 如 何 看 到 呢 ? 当 然 可 以 在 过 滤 器 中 检 查 一 些 环 境 变 量 来 决 定 用 户 所 要 求 的 是gb 还 是big5, 可 是 这 样 做 除 了 比 较 麻 烦 外, 还 存 在 效 率 问 题, 因 为 每 个 请 求 都 要 被 过 滤 器 处 理。

---- 笔 者 采 用 的 方 法 是 利 用iis4.0 中 可 以 设 置 多 个 站 点 的 功 能, 设 置 两 个 站 点。 一 个 不 含 过 滤 器, 所 以gb 内 容 高 效 直 接 的 返 回 给gb 用 户; 而 另 一 个 站 点 使 用 另 外 一 个 端 口 比 如81, 所 有 虚 拟 目 录 和 前 一 个 站 点 一 样, 将 过 滤 器 加 载 在 该 站 点 上, 这 样 所 有 向81 端 口 的 请 求, 都 将 被 过 滤 器 转 换 成big5 码 返 回 给 用 户。

---- 下 面 简 述 一 下 具 体 配 置 过 程。 首 先 在delphi 中 选 择 新 建 一 个dll, 输 入 程 序 源 码, 编 译 后 生 成gb2bigfiler.dll 文 件。 在iis4.0 的 管 理 控 制 台 中, 选" 新 建 站 点", 主 目 录 和 缺 省 站 点 一 样, 端 口 设 为81, 在isapi 过 滤 器 中 选 择" 添 加", 将gb2bigfiler.dll 加 入。

---- 设 置 好 后, 可 以 浏 览81 端 口( 例 如:http://www.yoursite.com:81/your.html), 这 时 原 来gb 码 的 内 容 就 变 成 了big5 码 了。

---- 有 兴 趣 的 读 者 可 以 访 问http://202.96.122.45/qq, 起 始 页 可 以 选 择 内 码, 随 后 浏 览 的 内 容 包 括 静 态 的html 文 本, 放 在 数 据 库 中 的《 红 楼 梦》、《 唐 诗》、 完 全 动 态 更 新 的bbs, 都 可 以 做 到 用 两 种 内 码 显 示。


======================================================
在最后,我邀请大家参加新浪APP,就是新浪免费送大家的一个空间,支持PHP+MySql,免费二级域名,免费域名绑定 这个是我邀请的地址,您通过这个链接注册即为我的好友,并获赠云豆500个,价值5元哦!短网址是http://t.cn/SXOiLh我创建的小站每天访客已经达到2000+了,每天挂广告赚50+元哦,呵呵,饭钱不愁了,\(^o^)/