起因
2008年的时候,有个网友问俺一个问题:他有一个web服务器,上面挂了几个网站。现在要加2个功能:
1、在每个网站的页面的下方加一个版权声明。坏消息是这些网站是其他人开发的,没有源码,开发语言也各不相同。好消息是用的IIS发布的。
2、为每个页面增加GB2312到Big5转码显示
俺的回答
写一个HTTP过滤器,在最后把HTML发布到客户端时 修改HTML的内容,实现增加版权声明和转码
实现方式
先写一个dll 实现3个函数GetFilterVersion、HttpFilterProc、TerminateFilter
function HttpFilterProc(var pfc: THTTP_FILTER_CONTEXT; Notificationtype: DWORD;
pvNotification: Pointer): DWORD; stdcall;
function GetFilterVersion(var Ver: THTTP_FILTER_VERSION): BOOL; stdcall;
function TerminateFilter(dwFlags: DWORD): BOOL; stdcall;
uses
SysUtils,
Classes,
Isapi4 in '..\Comm\Isapi4.pas',
FilterUnit in 'FilterUnit.pas',
GB2Big5 in 'Gb2Big5.pas',
CovertCode in 'CovertCode.pas';
{$R *.res}
exports
GetFilterVersion,
HttpFilterProc,
TerminateFilter;
核心处理
核心处理在 HttpFilterProc 中,主要是处理SF_NOTIFY_SEND_RESPONSE 和 SF_NOTIFY_SEND_RAW_DATA两种情况
try
case Notificationtype of
SF_NOTIFY_SEND_RESPONSE: begin
Result := OnSEND;
end;
SF_NOTIFY_SEND_RAW_DATA: begin
Result := onData;
end;
else begin
Result := SF_STATUS_REQ_NEXT_NOTIFICATION;
end;
end;
except
end;
SEND_RESPONSE的处理
在这里根据 Content-Type 进行判断,如果是'text/html' 就在HTML中插入下面的文本 stradd: string = #13#10'<div align="center"><b><font face="Arial, Helvetica, sans-serif"> <a href="http://www.renyuansoft.com"><font color="#FF0000">Please Visit http://www.renyuansoft.com</font></a></font></b></div>'#13#10#13#10;
并修改 Content-Length
function OnSEND: DWORD;
var
s: string;
size: DWORD;
clen: integer;
begin
pfc.pFilterContext := Pointer(0); //去除将有漏转换等错误
Result := SF_STATUS_REQ_NEXT_NOTIFICATION;
setlength(s, 254);
size := 255;
with THTTP_FILTER_PREPROC_HEADERS(pvNotification^) do begin
if TGetHeaderProc(GetHeader)(pfc, 'Content-type:', s[1], size) then begin
setlength(s, size);
s := trim(s);
//如果是JS文件,进行处理
if sametext(s, 'application/x-javascript') then pfc.pFilterContext := Pointer(2); //will convert
//如果是asp、html、htm文件进行处理
if sametext(s, 'text/html') then begin
TSetHeaderProc(SetHeader)(pfc, 'Content-Type:', pchar(CharSet)); //设置编码类型
setlength(s, 254);
size := 255;
if TGetHeaderProc(GetHeader)(pfc, 'Content-Length:', s[1], size) then begin
//DbgMsg(pchar(S)); //查看content-length
//DbgMsg(pchar(InfoStr));
setlength(s, size);
s := trim(s);
clen := StrToIntDef(s, 0);
if clen > 0 then begin
if Length(stradd) > 0 then begin
clen := clen + Length(stradd);
s := inttostr(clen) + #0;
TSetHeaderProc(SetHeader)(pfc, 'Content-Length:', pchar(s));
end;
pfc.pFilterContext := Pointer(1); //will convert
end;
end;
end;
end;
end;
s := '';
end;
SEND_RAW_DATA的处理
在这里进行转码
function onData: DWORD;
var
old_pvInData: Pointer;
old_cbInData: DWORD; // Number of valid data bytes
old_cbInBuffer: DWORD; // Total size of buffer
new_pvInData: Pointer;
new_cbInData: DWORD; // Number of valid data bytes
new_cbInBuffer: DWORD; // Total size of buffer
procedure newbuff;
var
p: pchar;
begin
case integer(pfc.pFilterContext) of
1: begin
//text/html,处理
//Gb2Big5_2(old_pvInData, old_cbInData); //API方式GB转BIG5
GBtoBIG5(old_pvInData, old_cbInData); //码表GB转BIG5
//BIG5toGB(old_pvInData, old_cbInData); //码表BIG5转GB
//Big52GB_2(old_pvInData, old_cbInData); //API 方式BIG5转GB
new_pvInData := old_pvInData;
new_cbInData := old_cbInData;
new_cbInBuffer := old_cbInBuffer;
if Length(stradd) > 0 then begin
new_cbInBuffer := old_cbInBuffer + Length(stradd);
new_pvInData := pfc.AllocMem(pfc, new_cbInBuffer, 0);
new_cbInData := old_cbInData + Length(stradd);
move(old_pvInData^, new_pvInData^, old_cbInData);
p := new_pvInData;
inc(p, old_cbInData);
move(stradd[1], p^, Length(stradd));
end;
end;
2: begin
//application/x-javascript,处理
//Gb2Big5_2(old_pvInData, old_cbInData); //API方式GB转BIG5
GBtoBIG5(old_pvInData, old_cbInData); //码表GB转BIG5
new_pvInData := old_pvInData;
new_cbInData := old_cbInData;
new_cbInBuffer := old_cbInBuffer;
end;
else
//不需要处理
new_pvInData := old_pvInData;
new_cbInData := old_cbInData;
new_cbInBuffer := old_cbInBuffer;
end;
end;
begin
if integer(pfc.pFilterContext) < 0 then exit;
//if integer(pfc.pFilterContext) <= 0 then exit;
with HTTP_FILTER_RAW_DATA(pvNotification^) do begin
old_pvInData := pvInData;
old_cbInData := cbInData;
old_cbInBuffer := cbInBuffer;
newbuff;
pvInData := new_pvInData;
cbInData := new_cbInData;
cbInBuffer := new_cbInBuffer;
end;
Result := SF_STATUS_REQ_NEXT_NOTIFICATION;
end;
全部代码
unit FilterUnit;
interface
uses Windows, Classes, SysUtils, Registry, StrUtils, Isapi4, CovertCode, Gb2Big5; //, dll_data;
function HttpFilterProc(var pfc: THTTP_FILTER_CONTEXT; Notificationtype: DWORD;
pvNotification: Pointer): DWORD; stdcall;
function GetFilterVersion(var Ver: THTTP_FILTER_VERSION): BOOL; stdcall;
function TerminateFilter(dwFlags: DWORD): BOOL; stdcall;
procedure DbgMsg(aStr: string);
implementation
var
stradd: string = #13#10'<div align="center"><b><font face="Arial, Helvetica, sans-serif"> <a href="http://www.renyuansoft.com"><font color="#FF0000">Please Visit http://www.renyuansoft.com</font></a></font></b></div>'#13#10#13#10;
//stradd: string = #13#10'<script language="javascript" type="text/javascript">alert(''Please visit www.renyuansoft.com'');</script>'#13#10#13#10;
//stradd: string = '';
CharSet: string = 'text/html; charset=big5'; //读取编码设置
reg: TRegistry;
LOCKDOG: string;
SerialNumber: string;
InfoStr: string = 'Demo Version. Please visit www.renyuansoft.com';
function GetFilterVersion(var Ver: THTTP_FILTER_VERSION): BOOL;
begin
//获取注册信息
reg := TRegistry.Create;
try
reg.RootKey := HKEY_LOCAL_MACHINE;
reg.OpenKey('Software\RenYuan\CodeConverFilter', TRUE);
SerialNumber := reg.readstring('SerialNumber');
finally
reg.closekey;
reg.free;
end;
Ver.dwFilterVersion := HTTP_FILTER_REVISION;
// Sets the filter description.
Ver.lpszFilterDesc := 'GBtoBIG5 ISAPI Filter .';
// Registers for the notifications.
Ver.dwFlags := (
SF_NOTIFY_SEND_RESPONSE
or
SF_NOTIFY_SEND_RAW_DATA
);
Result := TRUE;
end;
function HttpFilterProc(var pfc: THTTP_FILTER_CONTEXT; Notificationtype: DWORD;
pvNotification: Pointer): DWORD;
function OnSEND: DWORD;
var
s: string;
size: DWORD;
clen: integer;
begin
pfc.pFilterContext := Pointer(0); //去除将有漏转换等错误
Result := SF_STATUS_REQ_NEXT_NOTIFICATION;
setlength(s, 254);
size := 255;
with THTTP_FILTER_PREPROC_HEADERS(pvNotification^) do begin
if TGetHeaderProc(GetHeader)(pfc, 'Content-type:', s[1], size) then begin
setlength(s, size);
s := trim(s);
//如果是JS文件,进行处理
if sametext(s, 'application/x-javascript') then pfc.pFilterContext := Pointer(2); //will convert
//如果是asp、html、htm文件进行处理
if sametext(s, 'text/html') then begin
TSetHeaderProc(SetHeader)(pfc, 'Content-Type:', pchar(CharSet)); //设置编码类型
setlength(s, 254);
size := 255;
if TGetHeaderProc(GetHeader)(pfc, 'Content-Length:', s[1], size) then begin
//DbgMsg(pchar(S)); //查看content-length
//DbgMsg(pchar(InfoStr));
setlength(s, size);
s := trim(s);
clen := StrToIntDef(s, 0);
if clen > 0 then begin
if Length(stradd) > 0 then begin
clen := clen + Length(stradd);
s := inttostr(clen) + #0;
TSetHeaderProc(SetHeader)(pfc, 'Content-Length:', pchar(s));
end;
pfc.pFilterContext := Pointer(1); //will convert
end;
end;
end;
end;
end;
s := '';
end;
function onData: DWORD;
var
old_pvInData: Pointer;
old_cbInData: DWORD; // Number of valid data bytes
old_cbInBuffer: DWORD; // Total size of buffer
new_pvInData: Pointer;
new_cbInData: DWORD; // Number of valid data bytes
new_cbInBuffer: DWORD; // Total size of buffer
procedure newbuff;
var
p: pchar;
begin
case integer(pfc.pFilterContext) of
1: begin
//text/html,处理
//Gb2Big5_2(old_pvInData, old_cbInData); //API方式GB转BIG5
GBtoBIG5(old_pvInData, old_cbInData); //码表GB转BIG5
//BIG5toGB(old_pvInData, old_cbInData); //码表BIG5转GB
//Big52GB_2(old_pvInData, old_cbInData); //API 方式BIG5转GB
new_pvInData := old_pvInData;
new_cbInData := old_cbInData;
new_cbInBuffer := old_cbInBuffer;
if Length(stradd) > 0 then begin
new_cbInBuffer := old_cbInBuffer + Length(stradd);
new_pvInData := pfc.AllocMem(pfc, new_cbInBuffer, 0);
new_cbInData := old_cbInData + Length(stradd);
move(old_pvInData^, new_pvInData^, old_cbInData);
p := new_pvInData;
inc(p, old_cbInData);
move(stradd[1], p^, Length(stradd));
end;
end;
2: begin
//application/x-javascript,处理
//Gb2Big5_2(old_pvInData, old_cbInData); //API方式GB转BIG5
GBtoBIG5(old_pvInData, old_cbInData); //码表GB转BIG5
new_pvInData := old_pvInData;
new_cbInData := old_cbInData;
new_cbInBuffer := old_cbInBuffer;
end;
else
//不需要处理
new_pvInData := old_pvInData;
new_cbInData := old_cbInData;
new_cbInBuffer := old_cbInBuffer;
end;
end;
begin
if integer(pfc.pFilterContext) < 0 then exit;
//if integer(pfc.pFilterContext) <= 0 then exit;
with HTTP_FILTER_RAW_DATA(pvNotification^) do begin
old_pvInData := pvInData;
old_cbInData := cbInData;
old_cbInBuffer := cbInBuffer;
newbuff;
pvInData := new_pvInData;
cbInData := new_cbInData;
cbInBuffer := new_cbInBuffer;
end;
Result := SF_STATUS_REQ_NEXT_NOTIFICATION;
end;
begin
try
case Notificationtype of
SF_NOTIFY_SEND_RESPONSE: begin
Result := OnSEND;
end;
SF_NOTIFY_SEND_RAW_DATA: begin
Result := onData;
end;
else begin
Result := SF_STATUS_REQ_NEXT_NOTIFICATION;
end;
end;
except
end;
end;
function TerminateFilter(dwFlags: DWORD): BOOL;
begin
Result := TRUE;
end;
procedure DbgMsg(aStr: string);
begin
MessageBox(0, pchar(aStr), 'ISAPI Debug', MB_OK + MB_TOPMOST + MB_SERVICE_NOTIFICATION);
end;
end.