一种Html的处理

发布于:2024-12-22 ⋅ 阅读:(11) ⋅ 点赞:(0)

起因

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.