⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 httpproxy.pas

📁 灰鸽子VIP1.2经典源代码
💻 PAS
📖 第 1 页 / 共 2 页
字号:
{
  Http proxy
  Created By LLJ 2003-05-07

  代理服务器工作:
    1、客户机 Socket 连接上:   在连接链中增加一个连接纪录(TSessionRec)节点。
    2、客户端发送连接请求数据: 根据请求数据取得客户端要连接的目标主机的地址
                                和端口,并连接目标主机。
    3、连接到目标主机:
    4、发送客户端数据到目标主机:     如果客户端有数据未发送,则发送
    5、将目标主机返回的数据发送到客户端:
}

unit HttpProxy;

interface

uses Windows, SysUtils, Classes, ExtCtrls, ScktComp;

type
  // 客户端与代理服务器的会话信息。
  PSessionRec = ^TSessionRec;
  TSessionRec = packed record
    Used: Boolean;                    // 是否被使用。
    Lookingup: Boolean;               // 远程客户端是否正在连接
    LookupTime: Integer;              // 远程客户端已经在连接的时间
    ClientConnected: Boolean;         // 客户端是否连接
    RemoteConnected: Boolean;         // 远程客户端是否连接
    ClientSocketHandle: Integer;      // 客户端的 SocketHandle
    csRemoteClient: TClientSocket;    // 远程客户端,用来连接远程目标主机
    // KeepConnection: Boolean;
    IsClientRequesting: Boolean;      // 客户端是否有请求消息要发往远程主机
    RequestString: String;            // 客户端的请求消息
  end;

  TProxy = class
  private
    FProxyServer: TServerSocket;      // 代理服务器的服务器 Socket
    FLookupTimer: TTimer;             // 连接时间控制计时器
    FOutPut: TStrings;
    FPort: Integer;
    FLookupTimeLimite: Integer;
    FLookupTimeLimited: Boolean;

    procedure AddMessage(const Msg: String);
    procedure AddSession(const ASocket: TCustomWinSocket);
    function GetClientFromHandle(const ASocketHandle: Integer): TCustomWinSocket;
    function GetSessionRemote(
      ASocketHandle: Integer): PSessionRec;
    procedure EndSessionClient(const ASocket: TCustomWinSocket);
    procedure EndSessionRemote(const ASocket: TCustomWinSocket);
    function GetSessionClient(const ASocket: TCustomWinSocket): PSessionRec;

    // 服务器(ServerSocket) 的事件,客户端连接,断开,读
    procedure FProxyServerClientConnect(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure FProxyServerClientDisconnect(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure FProxyServerClientRead(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure FProxyServerListen(Sender: TObject;
      Socket: TCustomWinSocket);

    // 远程客户端(ClientSocket) 的事件
    procedure FRemoteClientConnect(Sender: TObject; Socket: TCustomWinSocket);
    procedure FRemoteClientRead(Sender: TObject; Socket: TCustomWinSocket);
    procedure FRemoteClientWrite(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure FRemoteClientDisconnect(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure FRemoteClientError(Sender: TObject; Socket: TCustomWinSocket;
      ErrorEvent: TErrorEvent; var ErrorCode: Integer);
    procedure FLookupTimerTimer(Sender: TObject);
    procedure SetPort(const Value: Integer);
    procedure SetLookupTimeLimit(const Value: Integer);
    procedure SetLookupTimeLimited(const Value: Boolean);
    { Private declarations }
  public
    constructor Create;
    destructor Destroy; override;
    procedure StopServer;
    procedure StartServer;

    property Output: TStrings write FOutput;
    property LookupTimeLimit: Integer read FLookupTimeLimite write SetLookupTimeLimit;
    property LookupTimeLimited: Boolean read FLookupTimeLimited write SetLookupTimeLimited;
    property Port: Integer read FPort write SetPort;
    { Public declarations }
  end;

var
  SessionRecs: array of TSessionRec;
  SessionCount: Integer;

implementation

{
  根据连接到代理服务器的客户端的信息,创建会话。
}
procedure TProxy.AddSession(const ASocket: TCustomWinSocket);
var
  I: Integer;

  {
    根据连接到代理服务器的客户端的信息,创建会话。
  }
  procedure NewSession(ASessionRec: PSessionRec);
  begin
    with ASessionRec^ do
    begin
      Used := True;
      ClientConnected := True;
      Lookingup := False;
      RemoteConnected := False;
      ClientSocketHandle := ASocket.SocketHandle;
      IsClientRequesting := False;
    end;
  end;
begin
  // if SessionCount >= MAX_CLIENTS then Exit;
  {
    看看有没有空闲的会话可以使用。
  }
  for I := 0 to SessionCount - 1 do with SessionRecs[I] do
  begin
    if not Used then
    begin
      NewSession(@SessionRecs[I]);
      Exit;
    end;
  end;

  {
    新增一个会话。
  }
  Inc(SessionCount);
  SetLength(SessionRecs, SessionCount);
  NewSession(@SessionRecs[SessionCount - 1]);
end;

{
  当有客户端连接到代理服务器时,创建一个会话。
}
procedure TProxy.FProxyServerClientConnect(Sender: TObject;
  Socket: TCustomWinSocket);
begin
  AddMessage(Socket.RemoteHost + ' Connected.' + IntToStr(Socket.SocketHandle));
  AddSession(Socket);
end;

{
  远程客户端连接到目标主机时,设置已经连接到标志。
}
procedure TProxy.FRemoteClientConnect(Sender: TObject;
  Socket: TCustomWinSocket);
begin
  AddMessage('Connected to Remote Host.' + IntToStr(Socket.SocketHandle));
  with GetSessionRemote(Socket.SocketHandle)^ do
  begin
    Lookingup := False;
    csRemoteClient.Tag := Socket.SocketHandle;
  end;
end;

{
  处理客户端发送请求。
  1、客户端的会话已经在客户端连接时建立,现在利用客户端发送过来的信息,
    创建远程客户端连接远程目标主机。
  2、如果已经发送消息的客户端已经连接到远程目标主机,则将客户端的消息通过
    远程客户端与远程目标主机的连接,将客户端的消息转发到远程目标主机。
}
procedure TProxy.FProxyServerClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
var
  strTemp: String;
  idx: Integer;
begin
  with GetSessionClient(Socket)^ do
  begin
    RequestString := Socket.ReceiveText;
    IsClientRequesting := True;

    if RemoteConnected then
      csRemoteClient.Socket.SendText(RequestString)
    else begin
      if Assigned(csRemoteClient) then csRemoteClient.Free;
      csRemoteClient := TClientSocket.Create(nil);

      { 从请求消息中获取主机字符串和端口,以此创建远程客户端,以建立到远程
        主机的连接。}
      strTemp := RequestString;
      while strTemp <> '' do
      begin
        idx := Pos('Host', strTemp);
        if idx = 1 then
        begin
          Delete(strTemp, 1, idx + 5);
          idx := Pos(#13#10, strTemp);
          strTemp := Copy(strTemp, 1, idx - 1);
          idx := Pos(':', strTemp);
          if idx > 0 then
          begin
            csRemoteClient.Host := Copy(strTemp, 1, idx - 1);
            Delete(strTemp, 1, idx);
            try
              csRemoteClient.Port := StrToInt(strTemp);
            except
              csRemoteClient.Port := 80;
            end;
          end else
          begin
            csRemoteClient.Host := strTemp;
            csRemoteClient.Port := 80;
          end;
          Break;
        end;
        Delete(strTemp, 1, Pos(#13#10, strTemp) + 1);
      end;

      {
        设置远程客户端的事件处理
      }
      csRemoteClient.OnConnect := FRemoteClientConnect;
      csRemoteClient.OnRead := FRemoteClientRead;
      csRemoteClient.OnWrite := FRemoteClientWrite;
      csRemoteClient.OnDisConnect := FRemoteClientDisconnect;
      csRemoteClient.OnError := FRemoteClientError;
      Lookingup := True;
      csRemoteClient.Active := True;
    end;
  end;
end;

{
  处理远程服务器返回的响应。将消息原样返回给客户端。
}
procedure TProxy.FRemoteClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
var
  Buf: array[0..2047] of Byte;
  RecvLen: Integer;
begin
  AddMessage('Receive message from remote' + IntToStr(Socket.SocketHandle));
  with GetSessionRemote(Socket.SocketHandle)^ do
  begin
    RecvLen := Socket.ReceiveBuf(Buf, 2048);

    // LLJ 2003-05-13
    // 判断客户端是否连接,否则断开远程客户端的连接。
    if ClientConnected then
      GetClientFromHandle(ClientSocketHandle).SendBuf(Buf, RecvLen)
    else csRemoteClient.Active := False;
  end;
end;

{
  根据远程客户端的 Socket 句柄获得相应的会话。
}
function TProxy.GetSessionRemote(ASocketHandle: Integer): PSessionRec;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -