mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-19 09:59:29 +02:00
fphttpclient: new DoDataWrite/OnDataSent event
This commit is contained in:
parent
bd814c58c3
commit
fdaa1a12d0
@ -67,11 +67,14 @@ Type
|
||||
private
|
||||
FDataRead : Int64;
|
||||
FContentLength : Int64;
|
||||
FRequestDataWritten : Int64;
|
||||
FRequestContentLength : Int64;
|
||||
FAllowRedirect: Boolean;
|
||||
FKeepConnection: Boolean;
|
||||
FMaxChunkSize: SizeUInt;
|
||||
FMaxRedirects: Byte;
|
||||
FOnDataReceived: TDataEvent;
|
||||
FOnDataSent: TDataEvent;
|
||||
FOnHeaders: TNotifyEvent;
|
||||
FOnPassword: TPasswordEvent;
|
||||
FOnRedirect: TRedirectEvent;
|
||||
@ -130,12 +133,18 @@ Type
|
||||
Function CreateProxyData : TProxyData;
|
||||
// Called whenever data is read.
|
||||
Procedure DoDataRead; virtual;
|
||||
// Called whenever data is written.
|
||||
Procedure DoDataWrite; virtual;
|
||||
// Parse response status line. Saves status text and protocol, returns numerical code. Exception if invalid line.
|
||||
Function ParseStatusLine(AStatusLine : String) : Integer;
|
||||
// Construct server URL for use in request line.
|
||||
function GetServerURL(URI: TURI): String;
|
||||
// Read 1 line of response. Fills FBuffer
|
||||
function ReadString(out S: String): Boolean;
|
||||
// Write string
|
||||
function WriteString(S: String): Boolean;
|
||||
// Write the request body
|
||||
function WriteRequestBody: Boolean;
|
||||
// Check if response code is in AllowedResponseCodes. if not, an exception is raised.
|
||||
// If AllowRedirect is true, and the result is a Redirect status code, the result is also true
|
||||
// If the OnPassword event is set, then a 401 will also result in True.
|
||||
@ -336,6 +345,8 @@ Type
|
||||
Property OnPassword : TPasswordEvent Read FOnPassword Write FOnPassword;
|
||||
// Called whenever data is read from the connection.
|
||||
Property OnDataReceived : TDataEvent Read FOnDataReceived Write FOnDataReceived;
|
||||
// Called whenever data is written to the connection.
|
||||
Property OnDataSent : TDataEvent Read FOnDataSent Write FOnDataSent;
|
||||
// Called when headers have been processed.
|
||||
Property OnHeaders : TNotifyEvent Read FOnHeaders Write FOnHeaders;
|
||||
// Called to create socket handler. If not set, or Nil is returned, a standard socket handler is created.
|
||||
@ -368,6 +379,7 @@ Type
|
||||
Property Password;
|
||||
Property OnPassword;
|
||||
Property OnDataReceived;
|
||||
Property OnDataSent;
|
||||
Property OnHeaders;
|
||||
Property OnGetSocketHandler;
|
||||
Property Proxy;
|
||||
@ -378,12 +390,12 @@ Type
|
||||
end;
|
||||
|
||||
EHTTPClient = Class(EHTTP);
|
||||
// socket stream exceptions
|
||||
EHTTPClientStream = class(EHTTPClient);
|
||||
// client socket exceptions
|
||||
EHTTPClientSocket = class(EHTTPClient);
|
||||
// reading from socket
|
||||
EHTTPClientStreamRead = Class(EHTTPClientStream);
|
||||
EHTTPClientSocketRead = Class(EHTTPClientSocket);
|
||||
// writing to socket
|
||||
EHTTPClientStreamWrite = Class(EHTTPClientStream);
|
||||
EHTTPClientSocketWrite = Class(EHTTPClientSocket);
|
||||
|
||||
Function EncodeURLElement(S : String) : String;
|
||||
Function DecodeURLElement(Const S : String) : String;
|
||||
@ -564,6 +576,12 @@ begin
|
||||
FOnDataReceived(Self,FContentLength,FDataRead);
|
||||
end;
|
||||
|
||||
procedure TFPCustomHTTPClient.DoDataWrite;
|
||||
begin
|
||||
If Assigned(FOnDataSent) Then
|
||||
FOnDataSent(Self,FRequestContentLength,FRequestDataWritten);
|
||||
end;
|
||||
|
||||
function TFPCustomHTTPClient.IndexOfHeader(const AHeader: String): Integer;
|
||||
begin
|
||||
Result:=IndexOfHeader(RequestHeaders,AHeader);
|
||||
@ -743,15 +761,15 @@ begin
|
||||
FSentCookies:=FCookies;
|
||||
FCookies:=Nil;
|
||||
S:=S+CRLF;
|
||||
try
|
||||
if not Terminated then
|
||||
FSocket.WriteBuffer(S[1],Length(S));
|
||||
If Assigned(FRequestBody) and not Terminated then
|
||||
FSocket.CopyFrom(FRequestBody,0);
|
||||
except
|
||||
on E: EWriteError do
|
||||
raise EHTTPClientStreamWrite.Create(SErrWritingSocket);
|
||||
end;
|
||||
if Assigned(FRequestBody) then
|
||||
FRequestContentLength:=FRequestBody.Size
|
||||
else
|
||||
FRequestContentLength:=0;
|
||||
FRequestDataWritten:=0;
|
||||
if not Terminated and not WriteString(S) then
|
||||
raise EHTTPClientSocketWrite.Create(SErrWritingSocket);
|
||||
if not Terminated and Assigned(FRequestBody) and not WriteRequestBody then
|
||||
raise EHTTPClientSocketWrite.Create(SErrWritingSocket);
|
||||
end;
|
||||
|
||||
function TFPCustomHTTPClient.ReadString(out S: String): Boolean;
|
||||
@ -769,7 +787,7 @@ function TFPCustomHTTPClient.ReadString(out S: String): Boolean;
|
||||
If (r=0) or Terminated Then
|
||||
Exit(False);
|
||||
If (r<0) then
|
||||
Raise EHTTPClientStreamRead.Create(SErrReadingSocket);
|
||||
Raise EHTTPClientSocketRead.Create(SErrReadingSocket);
|
||||
if (r<ReadBuflen) then
|
||||
SetLength(FBuffer,r);
|
||||
FDataRead:=FDataRead+R;
|
||||
@ -824,6 +842,68 @@ begin
|
||||
until Result or Terminated;
|
||||
end;
|
||||
|
||||
function TFPCustomHTTPClient.WriteString(S: String): Boolean;
|
||||
var
|
||||
r,t : Longint;
|
||||
|
||||
begin
|
||||
if S='' then
|
||||
Exit(True);
|
||||
|
||||
T:=0;
|
||||
Repeat
|
||||
r:=FSocket.Write(S[t+1],Length(S)-t);
|
||||
inc(t,r);
|
||||
DoDataWrite;
|
||||
Until Terminated or (t=Length(S)) or (r<=0);
|
||||
|
||||
Result := t=Length(S);
|
||||
end;
|
||||
|
||||
function TFPCustomHTTPClient.WriteRequestBody: Boolean;
|
||||
var
|
||||
Buffer: Pointer;
|
||||
BufferSize, i,t,w: LongInt;
|
||||
s, SourceSize: int64;
|
||||
|
||||
const
|
||||
MaxSize = $20000;
|
||||
begin
|
||||
if not Assigned(FRequestBody) or (FRequestBody.Size=0) then
|
||||
Exit(True);
|
||||
|
||||
FRequestBody.Position:=0; // This WILL fail for non-seekable streams...
|
||||
BufferSize:=MaxSize;
|
||||
SourceSize:=FRequestBody.Size;
|
||||
if (SourceSize<BufferSize) then
|
||||
BufferSize:=SourceSize; // do not allocate more than needed
|
||||
|
||||
s:=0;
|
||||
GetMem(Buffer,BufferSize);
|
||||
try
|
||||
repeat
|
||||
i:=FRequestBody.Read(buffer^,BufferSize);
|
||||
if i>0 then
|
||||
begin
|
||||
T:=0;
|
||||
Repeat
|
||||
w:=FSocket.Write(PByte(Buffer)[t],i-t);
|
||||
FRequestDataWritten:=FRequestDataWritten+w;
|
||||
DoDataWrite;
|
||||
inc(t,w);
|
||||
Until Terminated or (t=i) or (w<=0);
|
||||
if t<>i then
|
||||
Exit(False);
|
||||
Inc(s,i);
|
||||
end;
|
||||
until Terminated or (s=SourceSize) or (i<=0);
|
||||
finally
|
||||
FreeMem(Buffer);
|
||||
end;
|
||||
|
||||
Result:=s=SourceSize;
|
||||
end;
|
||||
|
||||
Function GetNextWord(Var S : String) : string;
|
||||
|
||||
Const
|
||||
@ -1043,7 +1123,7 @@ Function TFPCustomHTTPClient.ReadResponse(Stream: TStream;
|
||||
begin
|
||||
Result:=FSocket.Read(FBuffer[1],LB);
|
||||
If Result<0 then
|
||||
Raise EHTTPClientStreamRead.Create(SErrReadingSocket);
|
||||
Raise EHTTPClientSocketRead.Create(SErrReadingSocket);
|
||||
if (Result>0) then
|
||||
begin
|
||||
FDataRead:=FDataRead+Result;
|
||||
@ -1077,7 +1157,7 @@ Function TFPCustomHTTPClient.ReadResponse(Stream: TStream;
|
||||
SetLength(FBuffer,ReadBuflen);
|
||||
Cnt:=FSocket.Read(FBuffer[1],length(FBuffer));
|
||||
If Cnt<0 then
|
||||
Raise EHTTPClientStreamRead.Create(SErrReadingSocket);
|
||||
Raise EHTTPClientSocketRead.Create(SErrReadingSocket);
|
||||
SetLength(FBuffer,Cnt);
|
||||
BufPos:=1;
|
||||
Result:=Cnt>0;
|
||||
@ -1300,9 +1380,9 @@ begin
|
||||
break;
|
||||
T := ReadResponse(AStream,AAllowedResponseCodes,AHeadersOnly);
|
||||
except
|
||||
on E: EHTTPClientStream do
|
||||
on E: EHTTPClientSocket do
|
||||
begin
|
||||
// failed socket stream operations raise exceptions - e.g. if ReadString() fails
|
||||
// failed socket operations raise exceptions - e.g. if ReadString() fails
|
||||
// try to reconnect also in this case
|
||||
T:=False;
|
||||
end;
|
||||
|
Loading…
Reference in New Issue
Block a user