?? httpproxy.pas
字號:
{
Http proxy
Created By LLJ 2003-05-07
代理服務(wù)器工作:
1、客戶機 Socket 連接上: 在連接鏈中增加一個連接紀錄(TSessionRec)節(jié)點。
2、客戶端發(fā)送連接請求數(shù)據(jù): 根據(jù)請求數(shù)據(jù)取得客戶端要連接的目標主機的地址
和端口,并連接目標主機。
3、連接到目標主機:
4、發(fā)送客戶端數(shù)據(jù)到目標主機: 如果客戶端有數(shù)據(jù)未發(fā)送,則發(fā)送
5、將目標主機返回的數(shù)據(jù)發(fā)送到客戶端:
}
unit HttpProxy;
interface
uses Windows, SysUtils, Classes, ExtCtrls, ScktComp;
type
// 客戶端與代理服務(wù)器的會話信息。
PSessionRec = ^TSessionRec;
TSessionRec = packed record
Used: Boolean; // 是否被使用。
Lookingup: Boolean; // 遠程客戶端是否正在連接
LookupTime: Integer; // 遠程客戶端已經(jīng)在連接的時間
ClientConnected: Boolean; // 客戶端是否連接
RemoteConnected: Boolean; // 遠程客戶端是否連接
ClientSocketHandle: Integer; // 客戶端的 SocketHandle
csRemoteClient: TClientSocket; // 遠程客戶端,用來連接遠程目標主機
// KeepConnection: Boolean;
IsClientRequesting: Boolean; // 客戶端是否有請求消息要發(fā)往遠程主機
RequestString: String; // 客戶端的請求消息
end;
TProxy = class
private
FProxyServer: TServerSocket; // 代理服務(wù)器的服務(wù)器 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;
// 服務(wù)器(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 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
{
根據(jù)連接到代理服務(wù)器的客戶端的信息,創(chuàng)建會話。
}
procedure TProxy.AddSession(const ASocket: TCustomWinSocket);
var
I: Integer;
{
根據(jù)連接到代理服務(wù)器的客戶端的信息,創(chuàng)建會話。
}
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;
{
當有客戶端連接到代理服務(wù)器時,創(chuàng)建一個會話。
}
procedure TProxy.FProxyServerClientConnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
AddMessage(Socket.RemoteHost + ' Connected.' + IntToStr(Socket.SocketHandle));
AddSession(Socket);
end;
{
遠程客戶端連接到目標主機時,設(shè)置已經(jīng)連接到標志。
}
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;
{
處理客戶端發(fā)送請求。
1、客戶端的會話已經(jīng)在客戶端連接時建立,現(xiàn)在利用客戶端發(fā)送過來的信息,
創(chuàng)建遠程客戶端連接遠程目標主機。
2、如果已經(jīng)發(fā)送消息的客戶端已經(jīng)連接到遠程目標主機,則將客戶端的消息通過
遠程客戶端與遠程目標主機的連接,將客戶端的消息轉(zhuǎn)發(fā)到遠程目標主機。
}
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);
{ 從請求消息中獲取主機字符串和端口,以此創(chuàng)建遠程客戶端,以建立到遠程
主機的連接。}
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;
{
設(shè)置遠程客戶端的事件處理
}
csRemoteClient.OnConnect := FRemoteClientConnect;
csRemoteClient.OnRead := FRemoteClientRead;
csRemoteClient.OnWrite := FRemoteClientWrite;
csRemoteClient.OnDisConnect := FRemoteClientDisconnect;
csRemoteClient.OnError := FRemoteClientError;
Lookingup := True;
csRemoteClient.Active := True;
end;
end;
end;
{
處理遠程服務(wù)器返回的響應(yīng)。將消息原樣返回給客戶端。
}
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;
{
根據(jù)遠程客戶端的 Socket 句柄獲得相應(yīng)的會話。
}
function TProxy.GetSessionRemote(ASocketHandle: Integer): PSessionRec;
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -