123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304 |
- {
- HTTPClient: HTTP client component
- Copyright (C) 2000-2003 by Sebastian Guenther ([email protected])
- See the file COPYING.FPC, included in this distribution,
- for details about the copyright.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- }
- unit HTTPClient;
- interface
- uses Classes, HTTPBase, fpSock, fpAsync;
- type
- TCustomHTTPClient = class(TCustomTCPClient)
- protected
- SendBuffer: TAsyncWriteStream;
- FOnPrepareSending: TNotifyEvent;
- FOnHeaderSent: TNotifyEvent;
- FOnStreamSent: TNotifyEvent;
- FOnPrepareReceiving: TNotifyEvent;
- FOnHeaderReceived: TNotifyEvent;
- FOnStreamReceived: TNotifyEvent;
- FOnDestroy: TNotifyEvent;
- RecvSize: Integer; // How many bytes are still to be read. -1 if unknown.
- DataAvailableNotifyHandle: Pointer;
- ReceivedHTTPVersion: String;
- procedure HeaderToSendCompleted(Sender: TObject);
- procedure StreamToSendCompleted(Sender: TObject);
- procedure ReceivedHeaderCompleted(Sender: TObject);
- procedure ReceivedHeaderEOF(Sender: TObject);
- procedure DataAvailable(Sender: TObject);
- procedure ReceivedStreamCompleted(Sender: TObject);
- property OnPrepareSending: TNotifyEvent read FOnPrepareSending write FOnPrepareSending;
- property OnHeaderSent: TNotifyEvent read FOnHeaderSent write FOnHeaderSent;
- property OnStreamSent: TNotifyEvent read FOnStreamSent write FOnStreamSent;
- property OnPrepareReceiving: TNotifyEvent read FOnPrepareReceiving write FOnPrepareReceiving;
- property OnHeaderReceived: TNotifyEvent read FOnHeaderReceived write FOnHeaderReceived;
- property OnStreamReceived: TNotifyEvent read FOnStreamReceived write FOnStreamReceived;
- property OnDestroy: TNotifyEvent read FOnDestroy write FOnDestroy;
- public
- HeaderToSend: THttpHeader;
- StreamToSend: TStream;
- ReceivedHeader: THttpHeader;
- ReceivedStream: TStream;
- DoDestroy: Boolean;
- destructor Destroy; override;
- procedure Receive;
- procedure Send;
- end;
- THttpClient = class(TCustomHttpClient)
- public
- property OnPrepareSending;
- property OnHeaderSent;
- property OnStreamSent;
- property OnPrepareReceiving;
- property OnHeaderReceived;
- property OnStreamReceived;
- property OnDestroy;
- end;
- {TCustomHTTPClient = class
- protected
- FEventLoop: TEventLoop;
- FSocket: TInetSocket;
- SendBuffer: TAsyncWriteStream;
- FOnPrepareSending: TNotifyEvent;
- FOnHeaderSent: TNotifyEvent;
- FOnStreamSent: TNotifyEvent;
- FOnPrepareReceiving: TNotifyEvent;
- FOnHeaderReceived: TNotifyEvent;
- FOnStreamReceived: TNotifyEvent;
- FOnDestroy: TNotifyEvent;
- RecvSize: Integer; // How many bytes are still to be read. -1 if unknown.
- DataAvailableNotifyHandle: Pointer;
- ReceivedHTTPVersion: String;
- procedure HeaderToSendCompleted(Sender: TObject);
- procedure StreamToSendCompleted(Sender: TObject);
- procedure ReceivedHeaderCompleted(Sender: TObject);
- procedure ReceivedHeaderEOF(Sender: TObject);
- procedure DataAvailable(Sender: TObject);
- procedure ReceivedStreamCompleted(Sender: TObject);
- property OnPrepareSending: TNotifyEvent read FOnPrepareSending write FOnPrepareSending;
- property OnHeaderSent: TNotifyEvent read FOnHeaderSent write FOnHeaderSent;
- property OnStreamSent: TNotifyEvent read FOnStreamSent write FOnStreamSent;
- property OnPrepareReceiving: TNotifyEvent read FOnPrepareReceiving write FOnPrepareReceiving;
- property OnHeaderReceived: TNotifyEvent read FOnHeaderReceived write FOnHeaderReceived;
- property OnStreamReceived: TNotifyEvent read FOnStreamReceived write FOnStreamReceived;
- property OnDestroy: TNotifyEvent read FOnDestroy write FOnDestroy;
- public
- HeaderToSend: THttpHeader;
- StreamToSend: TStream;
- ReceivedHeader: THttpHeader;
- ReceivedStream: TStream;
- DoDestroy: Boolean;
- constructor Create(AEventLoop: TEventLoop; ASocket: TInetSocket);
- destructor Destroy; override;
- procedure Receive;
- procedure Send;
- end;}
- implementation
- uses SysUtils;
- procedure TCustomHttpClient.HeaderToSendCompleted(Sender: TObject);
- begin
- // WriteLn('TCustomHttpClient.HeaderToSendCompleted');
- if Assigned(FOnHeaderSent) then
- FOnHeaderSent(Self);
- if Assigned(StreamToSend) then
- begin
- SendBuffer := TAsyncWriteStream.Create(EventLoop, Stream);
- SendBuffer.CopyFrom(StreamToSend, StreamToSend.Size);
- SendBuffer.OnBufferSent := @StreamToSendCompleted;
- end else
- begin
- StreamToSendCompleted(nil);
- if DoDestroy then
- Self.Free;
- end;
- end;
- procedure TCustomHttpClient.StreamToSendCompleted(Sender: TObject);
- begin
- // WriteLn('TCustomHttpClient.StreamToSendCompleted');
- if Assigned(FOnStreamSent) then
- FOnStreamSent(Self);
- FreeAndNil(SendBuffer);
- if DoDestroy then
- Self.Free
- else
- Receive;
- end;
- procedure TCustomHttpClient.ReceivedHeaderCompleted(Sender: TObject);
- var
- BytesInBuffer: Integer;
- NeedMoreData: Boolean;
- begin
- // WriteLn('TCustomHttpClient.ReceivedHeaderCompleted');
- ReceivedHeader.DataReceived := False;
- ReceivedHTTPVersion := ReceivedHeader.HttpVersion;
- BytesInBuffer := ReceivedHeader.Reader.BytesInBuffer;
- //WriteLn('BytesInBuffer: ', BytesInBuffer, ', Content length: ', ReceivedHeader.ContentLength);
- if Assigned(FOnHeaderReceived) then
- FOnHeaderReceived(Self);
- RecvSize := ReceivedHeader.ContentLength;
- if Assigned(ReceivedStream) then
- begin
- if BytesInBuffer = 0 then
- NeedMoreData := True
- else
- begin
- ReceivedStream.Write(ReceivedHeader.Reader.Buffer^, BytesInBuffer);
- if RecvSize > 0 then
- Dec(RecvSize, BytesInBuffer);
- if BytesInBuffer = ReceivedHeader.ContentLength then
- NeedMoreData := False
- else
- NeedMoreData := (not ReceivedHeader.InheritsFrom(THttpRequestHeader)) or
- (THttpRequestHeader(ReceivedHeader).Command <> 'GET');
- end;
- end else
- NeedMoreData := False;
- if NeedMoreData then
- DataAvailableNotifyHandle :=
- EventLoop.SetDataAvailableNotify(Stream.Handle, @DataAvailable, Stream)
- else
- ReceivedStreamCompleted(nil);
- if DoDestroy then
- Self.Free;
- end;
- procedure TCustomHttpClient.ReceivedHeaderEOF(Sender: TObject);
- begin
- Self.Free;
- end;
- procedure TCustomHttpClient.DataAvailable(Sender: TObject);
- var
- FirstRun: Boolean;
- ReadNow, BytesRead: Integer;
- buf: array[0..1023] of Byte;
- begin
- FirstRun := True;
- while True do
- begin
- if RecvSize >= 0 then
- begin
- ReadNow := RecvSize;
- if ReadNow > 1024 then
- ReadNow := 1024;
- end else
- ReadNow := 1024;
- BytesRead := Stream.Read(buf, ReadNow);
- // WriteLn('TCustomHttpClient.DataAvailable: Read ', BytesRead, ' bytes; RecvSize=', RecvSize);
- if BytesRead <= 0 then
- begin
- if FirstRun then
- ReceivedStreamCompleted(nil);
- break;
- end;
- FirstRun := False;
- ReceivedStream.Write(buf, BytesRead);
- if RecvSize > 0 then
- Dec(RecvSize, BytesRead);
- if RecvSize = 0 then
- begin
- ReceivedStreamCompleted(nil);
- break;
- end;
- end;
- if DoDestroy then
- Self.Free;
- end;
- procedure TCustomHttpClient.ReceivedStreamCompleted(Sender: TObject);
- begin
- // WriteLn('TCustomHttpClient.ReceivedStreamCompleted');
- if Assigned(DataAvailableNotifyHandle) then
- begin
- EventLoop.ClearDataAvailableNotify(DataAvailableNotifyHandle);
- DataAvailableNotifyHandle := nil;
- end;
- if Assigned(FOnStreamReceived) then
- FOnStreamReceived(Self);
- if DoDestroy then
- Self.Free
- else
- Send;
- end;
- {constructor TCustomHttpClient.Create(AManager: TEventLoop; ASocket: TInetSocket);
- begin
- inherited Create;
- EventLoop := AManager;
- Stream := ASocket;
- end;}
- destructor TCustomHttpClient.Destroy;
- begin
- if Assigned(DataAvailableNotifyHandle) then
- EventLoop.ClearDataAvailableNotify(DataAvailableNotifyHandle);
- if Assigned(OnDestroy) then
- OnDestroy(Self);
- FreeAndNil(SendBuffer);
- inherited Destroy;
- end;
- procedure TCustomHttpClient.Receive;
- begin
- // Start receiver
- ReceivedHttpVersion := '';
- if Assigned(OnPrepareReceiving) then
- OnPrepareReceiving(Self);
- if Assigned(ReceivedHeader) then
- begin
- ReceivedHeader.OnCompleted := @ReceivedHeaderCompleted;
- ReceivedHeader.OnEOF := @ReceivedHeaderEOF;
- ReceivedHeader.AsyncReceive(EventLoop, Stream);
- end;
- end;
- procedure TCustomHttpClient.Send;
- begin
- // Start sender
- if Assigned(OnPrepareSending) then
- OnPrepareSending(Self);
- if Assigned(HeaderToSend) then
- begin
- if ReceivedHttpVersion <> '' then
- begin
- HeaderToSend.HttpVersion := ReceivedHttpVersion;
- ReceivedHttpVersion := '';
- end;
- HeaderToSend.OnCompleted := @HeaderToSendCompleted;
- HeaderToSend.AsyncSend(EventLoop, Stream);
- end;
- end;
- end.
|