?? httpsrv.pas
字號:
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
{ Called by destructor when child component is created or destroyed. }
procedure THttpServer.Notification(
AComponent : TComponent;
Operation : TOperation);
begin
inherited Notification(AComponent, Operation);
if Operation = opRemove then begin
if AComponent = FWSocketServer then
FWSocketServer := nil;
end;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
{ Start the server. That is make FWSocketServer listening to the port. }
procedure THttpServer.Start;
begin
{ Create a new FWSocketServer if needed }
if not Assigned(FWSocketServer) then
FWSocketServer := TWSocketServer.Create(Self);
{ If already listening, then do nothing }
if FWSocketServer.State = wsListening then
Exit;
{ Pass al parameters to FWSocketServer and make it listen }
FWSocketServer.ClientClass := FClientClass;
FWSocketServer.OnClientCreate := WSocketServerClientCreate;
FWSocketServer.OnClientConnect := WSocketServerClientConnect;
FWSocketServer.OnClientDisconnect := WSocketServerClientDisconnect;
FWSocketServer.OnSessionClosed := WSocketServerSessionClosed;
FWSocketServer.OnChangeState := WSocketServerChangeState;
FWSocketServer.Banner := '';
FWSocketServer.Proto := 'tcp';
FWSocketServer.Port := FPort;
FWSocketServer.Addr := FAddr;
FWSocketServer.Listen;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure THttpServer.Stop;
var
I : Integer;
begin
if not Assigned(FWSocketServer) then
Exit;
FWSocketServer.Close;
{ Disconnect all clients }
for I := FWSocketServer.ClientCount - 1 downto 0 do begin
try
FWSocketServer.Client[I].Abort;
except
{ Ignore any exception here }
end;
end;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure THttpServer.SetPort(newValue : String);
begin
if newValue = FPort then
Exit;
FPort := newValue;
{ If server is already listening, then stop it and restart it with }
{ new port. Do not disconnect already connected clients. }
if Assigned(FWSocketServer) and
(FWSocketServer.State = wsListening) then begin
FWSocketServer.Close;
Start;
end;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure THttpServer.SetAddr(newValue : String);
begin
if newValue = FAddr then
Exit;
FAddr := newValue;
{ If server is already listening, then stop it and restart it with }
{ new Addr. Do not disconnect already connected clients. }
if Assigned(FWSocketServer) and
(FWSocketServer.State = wsListening) then begin
FWSocketServer.Close;
Start;
end;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
{ Get function for ClientCount property. Just return value from }
{ FWSocketServer. }
function THttpServer.GetClientCount;
begin
if not Assigned(FWSocketServer) then
Result := 0
else
Result := FWSocketServer.ClientCount;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
{ This event handler is triggered when state of server socket has changed. }
{ We use it to trigger our OnServerStarted event. }
procedure THttpServer.WSocketServerChangeState(
Sender : TObject;
OldState, NewState : TSocketState);
begin
if newState = wsListening then
TriggerServerStarted;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure THttpServer.WSocketServerSessionClosed(
Sender : TObject;
Error : Word);
begin
TriggerServerStopped;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
{ A new client component has been created }
procedure THttpServer.WSocketServerClientCreate(
Sender : TObject;
Client : TWSocketClient);
begin
Client.LingerOnOff := FLingerOnOff;
Client.LingerTimeout := FLingerTimeout;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
{ A new client just connected. Setup things to handle his requests. }
{ HTTP header is line oriented so we turn line mode on. We use LF as end of }
{ line character altough HTTP uses CR/LF pair as end of line, because many }
{ Unix client do not respect standards and use single LF... }
{ HTTP is not interactive, so we turn line editing to false (faster). }
procedure THttpServer.WSocketServerClientConnect(
Sender : TObject;
Client : TWSocketClient;
Error : Word);
begin
THttpConnection(Client).LineMode := TRUE;
THttpConnection(Client).LineEdit := FALSE;
THttpConnection(Client).LineEnd := #10;
THttpConnection(Client).DocDir := Self.DocDir;
THttpConnection(Client).DefaultDoc := Self.DefaultDoc;
THttpConnection(Client).OnGetDocument := TriggerGetDocument;
THttpConnection(Client).OnHeadDocument := TriggerHeadDocument;
THttpConnection(Client).OnPostDocument := TriggerPostDocument;
THttpConnection(Client).OnPostedData := TriggerPostedData;
TriggerClientConnect(Client, Error);
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
{ A client is about to disconnect. }
procedure THttpServer.WSocketServerClientDisconnect(
Sender : TObject;
Client : TWSocketClient;
Error : Word);
begin
TriggerClientDisconnect(Client, Error);
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure THttpServer.TriggerServerStarted;
begin
if Assigned(FOnServerStarted) then
FOnServerStarted(Self);
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure THttpServer.TriggerServerStopped;
begin
if Assigned(FOnServerStarted) then
FOnServerStopped(Self);
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure THttpServer.TriggerClientConnect(
Client : TObject;
Error : Word);
begin
if Assigned(FOnClientConnect) then
FOnClientConnect(Self, Client, Error);
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure THttpServer.TriggerClientDisconnect(
Client : TObject;
Error : Word);
begin
if Assigned(FOnClientDisconnect) then
FOnClientDisconnect(Self, Client, Error);
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure THttpServer.TriggerGetDocument(
Sender : TObject;
var Flags : THttpGetFlag);
begin
if Assigned(FOnGetDocument) then
FOnGetDocument(Self, Sender, Flags);
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure THttpServer.TriggerHeadDocument(
Sender : TObject;
var Flags : THttpGetFlag);
begin
if Assigned(FOnHeadDocument) then
FOnHeadDocument(Self, Sender, Flags);
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure THttpServer.TriggerPostedData(Sender : TObject;
Error : WORD);
begin
if Assigned(FOnPostedData) then
FOnPostedData(Self, Sender, Error);
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure THttpServer.TriggerPostDocument(
Sender : TObject;
var Flags : THttpGetFlag);
begin
if Assigned(FOnPostDocument) then
FOnPostDocument(Self, Sender, Flags);
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
constructor THttpConnection.Create(AOwner : TComponent);
begin
inherited Create(AOwner);
LineMode := TRUE;
LineEdit := FALSE;
LineEnd := #10;
FRequestHeader := TStringList.Create;
FState := hcRequest;
OnDataAvailable := ConnectionDataAvailable;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
destructor THttpConnection.Destroy;
begin
if Assigned(FRequestHeader) then begin
FRequestHeader.Destroy;
FRequestHeader := nil;
end;
if Assigned(FDocStream) then begin
FDocStream.Destroy;
FDocStream := nil;
end;
if Assigned(FDocBuf) then begin
FreeMem(FDocBuf);
FDocBuf := nil;
end;
inherited Destroy;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure THttpConnection.WndProc(var MsgRec: TMessage);
begin
with MsgRec do begin
{ We *MUST* handle all exception to avoid application shutdown }
try
if Msg = WM_HTTP_DONE then
WMHttpDone(MsgRec)
else
inherited WndProc(MsgRec);
except
on E:Exception do
HandleBackGroundException(E);
end;
end;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure THttpConnection.WMHttpDone(var msg: TMessage);
begin
FState := hcRequest;
if CompareText(FRequestConnection, 'Keep-Alive') <> 0 then
CloseDelayed;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
{ This procedure is called each time data is available from a client. }
{ We use FState variable to keep track of the where we are in the http }
{ protocol: request command, header line or posted data. }
procedure THttpConnection.ConnectionDataAvailable(Sender: TObject; Error : Word);
var
Len : Integer;
I : Integer;
begin
{ If we are in data state, then the application has to receive data }
if FState = hcPostedData then begin
if FAcceptPostedData and Assigned(FOnPostedData) then
FOnPostedData(Self, Error)
else
{ No one is willing data, received it and throw it away }
FRcvdLine := ReceiveStr;
Exit;
end;
{ We use line mode. We will receive complete lines }
FRcvdLine := ReceiveStr;
{ Remove trailing CR/LF }
Len := Length(FRcvdLine);
if (Len > 0) and (FRcvdLine[Len] = #10) then begin
Dec(Len);
if (Len > 0) and (FRcvdLine[Len] = #13) then
Dec(Len);
SetLength(FRcvdLine, Len);
end;
if FState = hcRequest then begin
{ We just start a new request. Initialize all header variables }
FRequestContentType := '';
FRequestContentLength := 0;
FRequestContentType := '';
FRequestAccept := '';
FRequestReferer := '';
FRequestAcceptLanguage := '';
FRequestAcceptEncoding := '';
FRequestUserAgent := '';
FRequestHost := '';
FRequestConnection := '';
{ The line we just received is HTTP command, parse it }
ParseRequest;
{ Next lines will be header lines }
FState := hcHeader;
Exit;
end;
{ We can comes here only in hcHeader state }
if FRcvdLine = '' then begin
{ Last header line is an empty line. Then we enter data state }
FState := hcPostedData;
{ We will process request before receiving data because application }
{ has to setup things to be able to receive posted data }
ProcessRequest;
Exit;
end;
{ We comes here for normal header line. Extract some interesting variables }
I := Pos(':', FRcvdLine);
if I > 0 then begin
try
repeat
Inc(I);
until (I > Length(FRcvdLine)) or (FRcvdLine[I] <> ' ');
if StrLIComp(@FRcvdLine[1], 'content-type:', 13) = 0 then
FRequestContentType := Copy(FRcvdLine, I, Length(FRcvdLine))
else if StrLIComp(@FRcvdLine[1], 'content-length:', 15) = 0 then
FRequestContentLength := StrToInt(Copy(FRcvdLine, I, Length(FRcvdLine)))
else if StrLIComp(@FRcvdLine[1], 'Accept:', 7) = 0 then
FRequestAccept:= Copy(FRcvdLine, I, Length(FRcvdLine))
else if StrLIComp(@FRcvdLine[1], 'Referer:', 8) = 0 then
FRequestReferer := Copy(FRcvdLine, I, Length(FRcvdLine))
else if StrLIComp(@FRcvdLine[1], 'Accept-Language:', 16) = 0 then
FRequestAcceptLanguage := Copy(FRcvdLine, I, Length(FRcvdLine))
else if StrLIComp(@FRcvdLine[1], 'Accept-Encoding:', 16) = 0 then
FRequestAcceptEncoding := Copy(FRcvdLine, I, Length(FRcvdLine))
else if StrLIComp(@FRcvdLine[1], 'User-Agent:', 11) = 0 then
FRequestUserAgent := Copy(FRcvdLine, I, Length(FRcvdLine))
else if StrLIComp(@FRcvdLine[1], 'Host:', 5) = 0 then
FRequestHost := Copy(FRcvdLine, I, Length(FRcvdLine))
else if StrLIComp(@FRcvdLine[1], 'Connection:', 11) = 0 then
FRequestConnection := Copy(FRcvdLine, I, Length(FRcvdLine));
except
{ Ignore any exception in parsing header line }
end;
end;
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -