mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-22 16:49:23 +02:00
* Request redirection handling implemented
git-svn-id: trunk@26675 -
This commit is contained in:
parent
a1eb9a0f99
commit
1b14ff7e8a
@ -28,12 +28,21 @@ uses
|
|||||||
Classes, SysUtils, ssockets, httpdefs, uriparser, base64;
|
Classes, SysUtils, ssockets, httpdefs, uriparser, base64;
|
||||||
|
|
||||||
Const
|
Const
|
||||||
|
// Socket Read buffer size
|
||||||
ReadBufLen = 4096;
|
ReadBufLen = 4096;
|
||||||
|
// Default for MaxRedirects Request redirection is aborted after this number of redirects.
|
||||||
|
DefMaxRedirects = 16;
|
||||||
|
|
||||||
Type
|
Type
|
||||||
|
TRedirectEvent = Procedure (Sender : TObject; Const ASrc : String; Var ADest: String) of object;
|
||||||
|
|
||||||
{ TFPCustomHTTPClient }
|
{ TFPCustomHTTPClient }
|
||||||
TFPCustomHTTPClient = Class(TComponent)
|
TFPCustomHTTPClient = Class(TComponent)
|
||||||
private
|
private
|
||||||
|
FAllowRedirect: Boolean;
|
||||||
|
FMaxRedirects: Byte;
|
||||||
|
FOnRedirect: TRedirectEvent;
|
||||||
|
FSentCookies,
|
||||||
FCookies: TStrings;
|
FCookies: TStrings;
|
||||||
FHTTPVersion: String;
|
FHTTPVersion: String;
|
||||||
FRequestBody: TStream;
|
FRequestBody: TStream;
|
||||||
@ -47,8 +56,9 @@ Type
|
|||||||
function CheckContentLength: Integer;
|
function CheckContentLength: Integer;
|
||||||
function CheckTransferEncoding: string;
|
function CheckTransferEncoding: string;
|
||||||
function GetCookies: TStrings;
|
function GetCookies: TStrings;
|
||||||
procedure SetCookies(const AValue: TStrings);
|
Procedure ResetResponse;
|
||||||
procedure SetRequestHeaders(const AValue: TStrings);
|
Procedure SetCookies(const AValue: TStrings);
|
||||||
|
Procedure SetRequestHeaders(const AValue: TStrings);
|
||||||
protected
|
protected
|
||||||
// Parse response status line. Saves status text and protocol, returns numerical code. Exception if invalid line.
|
// Parse response status line. Saves status text and protocol, returns numerical code. Exception if invalid line.
|
||||||
Function ParseStatusLine(AStatusLine : String) : Integer;
|
Function ParseStatusLine(AStatusLine : String) : Integer;
|
||||||
@ -57,22 +67,24 @@ Type
|
|||||||
// Read 1 line of response. Fills FBuffer
|
// Read 1 line of response. Fills FBuffer
|
||||||
function ReadString: String;
|
function ReadString: String;
|
||||||
// Check if response code is in AllowedResponseCodes. if not, an exception is raised.
|
// 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
|
||||||
function CheckResponseCode(ACode: Integer; const AllowedResponseCodes: array of Integer): Boolean; virtual;
|
function CheckResponseCode(ACode: Integer; const AllowedResponseCodes: array of Integer): Boolean; virtual;
|
||||||
// Read response from server, and write any document to Stream.
|
// Read response from server, and write any document to Stream.
|
||||||
procedure ReadResponse(Stream: TStream; const AllowedResponseCodes: array of Integer; HeadersOnly: Boolean = False); virtual;
|
Procedure ReadResponse(Stream: TStream; const AllowedResponseCodes: array of Integer; HeadersOnly: Boolean = False); virtual;
|
||||||
// Read server response line and headers. Returns status code.
|
// Read server response line and headers. Returns status code.
|
||||||
Function ReadResponseHeaders : integer; virtual;
|
Function ReadResponseHeaders : integer; virtual;
|
||||||
// Allow header in request ? (currently checks only if non-empty and contains : token)
|
// Allow header in request ? (currently checks only if non-empty and contains : token)
|
||||||
function AllowHeader(var AHeader: String): Boolean; virtual;
|
function AllowHeader(var AHeader: String): Boolean; virtual;
|
||||||
// Connect to the server. Must initialize FSocket.
|
// Connect to the server. Must initialize FSocket.
|
||||||
procedure ConnectToServer(const AHost: String; APort: Integer); virtual;
|
Procedure ConnectToServer(const AHost: String; APort: Integer); virtual;
|
||||||
// Disconnect from server. Must free FSocket.
|
// Disconnect from server. Must free FSocket.
|
||||||
procedure DisconnectFromServer; virtual;
|
Procedure DisconnectFromServer; virtual;
|
||||||
// Run method AMethod, using request URL AURL. Write Response to Stream, and headers in ResponseHeaders.
|
// Run method AMethod, using request URL AURL. Write Response to Stream, and headers in ResponseHeaders.
|
||||||
// If non-empty, AllowedResponseCodes contains an array of response codes considered valid responses.
|
// If non-empty, AllowedResponseCodes contains an array of response codes considered valid responses.
|
||||||
|
// If HandleRedirect is True, then Redirect status is accepted as a correct status, but request is not repeated.
|
||||||
Procedure DoMethod(Const AMethod,AURL : String; Stream : TStream; Const AllowedResponseCodes : Array of Integer); virtual;
|
Procedure DoMethod(Const AMethod,AURL : String; Stream : TStream; Const AllowedResponseCodes : Array of Integer); virtual;
|
||||||
// Send request to server: construct request line and send headers and request body.
|
// Send request to server: construct request line and send headers and request body.
|
||||||
procedure SendRequest(const AMethod: String; URI: TURI); virtual;
|
Procedure SendRequest(const AMethod: String; URI: TURI); virtual;
|
||||||
Public
|
Public
|
||||||
Constructor Create(AOwner: TComponent); override;
|
Constructor Create(AOwner: TComponent); override;
|
||||||
Destructor Destroy; override;
|
Destructor Destroy; override;
|
||||||
@ -83,61 +95,65 @@ Type
|
|||||||
Procedure AddHeader(Const AHeader,AValue : String);
|
Procedure AddHeader(Const AHeader,AValue : String);
|
||||||
// Return header value, empty if not present.
|
// Return header value, empty if not present.
|
||||||
Function GetHeader(Const AHeader : String) : String;
|
Function GetHeader(Const AHeader : String) : String;
|
||||||
// General-purpose call.
|
// General-purpose call. Handles redirect.
|
||||||
Procedure HTTPMethod(Const AMethod,AURL : String; Stream : TStream; Const AllowedResponseCodes : Array of Integer); virtual;
|
Procedure HTTPMethod(Const AMethod,AURL : String; Stream : TStream; Const AllowedResponseCodes : Array of Integer); virtual;
|
||||||
// Execute GET on server, store result in Stream, File, StringList or string
|
// Execute GET on server, store result in Stream, File, StringList or string
|
||||||
Procedure Get(Const AURL : String; Stream : TStream);
|
Procedure Get(Const AURL : String; Stream : TStream);
|
||||||
Procedure Get(Const AURL : String; const LocalFileName : String);
|
Procedure Get(Const AURL : String; const LocalFileName : String);
|
||||||
Procedure Get(Const AURL : String; Response : TStrings);
|
Procedure Get(Const AURL : String; Response : TStrings);
|
||||||
Function Get(Const AURL : String) : String;
|
Function Get(Const AURL : String) : String;
|
||||||
// Simple class methods
|
// Check if responsecode is a redirect code that this class handles (301,302,303,307,308)
|
||||||
|
Class Function IsRedirect(ACode : Integer) : Boolean; virtual;
|
||||||
|
// If the code is a redirect, then this method must return TRUE if the next request should happen with a GET (307/308)
|
||||||
|
Class Function RedirectForcesGET(ACode : Integer) : Boolean; virtual;
|
||||||
|
// Simple class methods
|
||||||
Class Procedure SimpleGet(Const AURL : String; Stream : TStream);
|
Class Procedure SimpleGet(Const AURL : String; Stream : TStream);
|
||||||
Class Procedure SimpleGet(Const AURL : String; const LocalFileName : String);
|
Class Procedure SimpleGet(Const AURL : String; const LocalFileName : String);
|
||||||
Class Procedure SimpleGet(Const AURL : String; Response : TStrings);
|
Class Procedure SimpleGet(Const AURL : String; Response : TStrings);
|
||||||
Class Function SimpleGet(Const AURL : String) : String;
|
Class Function SimpleGet(Const AURL : String) : String;
|
||||||
// Simple post
|
// Simple post
|
||||||
// Post URL, and Requestbody. Return response in Stream, File, TstringList or String;
|
// Post URL, and Requestbody. Return response in Stream, File, TstringList or String;
|
||||||
procedure Post(const URL: string; const Response: TStream);
|
Procedure Post(const URL: string; const Response: TStream);
|
||||||
procedure Post(const URL: string; Response : TStrings);
|
Procedure Post(const URL: string; Response : TStrings);
|
||||||
procedure Post(const URL: string; const LocalFileName: String);
|
Procedure Post(const URL: string; const LocalFileName: String);
|
||||||
function Post(const URL: string) : String;
|
function Post(const URL: string) : String;
|
||||||
// Simple class methods.
|
// Simple class methods.
|
||||||
Class procedure SimplePost(const URL: string; const Response: TStream);
|
Class Procedure SimplePost(const URL: string; const Response: TStream);
|
||||||
Class procedure SimplePost(const URL: string; Response : TStrings);
|
Class Procedure SimplePost(const URL: string; Response : TStrings);
|
||||||
Class procedure SimplePost(const URL: string; const LocalFileName: String);
|
Class Procedure SimplePost(const URL: string; const LocalFileName: String);
|
||||||
Class function SimplePost(const URL: string) : String;
|
Class function SimplePost(const URL: string) : String;
|
||||||
// Simple Put
|
// Simple Put
|
||||||
// Put URL, and Requestbody. Return response in Stream, File, TstringList or String;
|
// Put URL, and Requestbody. Return response in Stream, File, TstringList or String;
|
||||||
procedure Put(const URL: string; const Response: TStream);
|
Procedure Put(const URL: string; const Response: TStream);
|
||||||
procedure Put(const URL: string; Response : TStrings);
|
Procedure Put(const URL: string; Response : TStrings);
|
||||||
procedure Put(const URL: string; const LocalFileName: String);
|
Procedure Put(const URL: string; const LocalFileName: String);
|
||||||
function Put(const URL: string) : String;
|
function Put(const URL: string) : String;
|
||||||
// Simple class methods.
|
// Simple class methods.
|
||||||
Class procedure SimplePut(const URL: string; const Response: TStream);
|
Class Procedure SimplePut(const URL: string; const Response: TStream);
|
||||||
Class procedure SimplePut(const URL: string; Response : TStrings);
|
Class Procedure SimplePut(const URL: string; Response : TStrings);
|
||||||
Class procedure SimplePut(const URL: string; const LocalFileName: String);
|
Class Procedure SimplePut(const URL: string; const LocalFileName: String);
|
||||||
Class function SimplePut(const URL: string) : String;
|
Class function SimplePut(const URL: string) : String;
|
||||||
// Simple Delete
|
// Simple Delete
|
||||||
// Delete URL, and Requestbody. Return response in Stream, File, TstringList or String;
|
// Delete URL, and Requestbody. Return response in Stream, File, TstringList or String;
|
||||||
procedure Delete(const URL: string; const Response: TStream);
|
Procedure Delete(const URL: string; const Response: TStream);
|
||||||
procedure Delete(const URL: string; Response : TStrings);
|
Procedure Delete(const URL: string; Response : TStrings);
|
||||||
procedure Delete(const URL: string; const LocalFileName: String);
|
Procedure Delete(const URL: string; const LocalFileName: String);
|
||||||
function Delete(const URL: string) : String;
|
function Delete(const URL: string) : String;
|
||||||
// Simple class methods.
|
// Simple class methods.
|
||||||
Class procedure SimpleDelete(const URL: string; const Response: TStream);
|
Class Procedure SimpleDelete(const URL: string; const Response: TStream);
|
||||||
Class procedure SimpleDelete(const URL: string; Response : TStrings);
|
Class Procedure SimpleDelete(const URL: string; Response : TStrings);
|
||||||
Class procedure SimpleDelete(const URL: string; const LocalFileName: String);
|
Class Procedure SimpleDelete(const URL: string; const LocalFileName: String);
|
||||||
Class function SimpleDelete(const URL: string) : String;
|
Class function SimpleDelete(const URL: string) : String;
|
||||||
// Simple Options
|
// Simple Options
|
||||||
// Options from URL, and Requestbody. Return response in Stream, File, TstringList or String;
|
// Options from URL, and Requestbody. Return response in Stream, File, TstringList or String;
|
||||||
procedure Options(const URL: string; const Response: TStream);
|
Procedure Options(const URL: string; const Response: TStream);
|
||||||
procedure Options(const URL: string; Response : TStrings);
|
Procedure Options(const URL: string; Response : TStrings);
|
||||||
procedure Options(const URL: string; const LocalFileName: String);
|
Procedure Options(const URL: string; const LocalFileName: String);
|
||||||
function Options(const URL: string) : String;
|
function Options(const URL: string) : String;
|
||||||
// Simple class methods.
|
// Simple class methods.
|
||||||
Class procedure SimpleOptions(const URL: string; const Response: TStream);
|
Class Procedure SimpleOptions(const URL: string; const Response: TStream);
|
||||||
Class procedure SimpleOptions(const URL: string; Response : TStrings);
|
Class Procedure SimpleOptions(const URL: string; Response : TStrings);
|
||||||
Class procedure SimpleOptions(const URL: string; const LocalFileName: String);
|
Class Procedure SimpleOptions(const URL: string; const LocalFileName: String);
|
||||||
Class function SimpleOptions(const URL: string) : String;
|
Class function SimpleOptions(const URL: string) : String;
|
||||||
// Get HEAD
|
// Get HEAD
|
||||||
Class Procedure Head(AURL : String; Headers: TStrings);
|
Class Procedure Head(AURL : String; Headers: TStrings);
|
||||||
@ -182,6 +198,13 @@ Type
|
|||||||
Property ResponseStatusCode : Integer Read FResponseStatusCode;
|
Property ResponseStatusCode : Integer Read FResponseStatusCode;
|
||||||
// After request, HTTP response status text of the server.
|
// After request, HTTP response status text of the server.
|
||||||
Property ResponseStatusText : String Read FResponseStatusText;
|
Property ResponseStatusText : String Read FResponseStatusText;
|
||||||
|
// Allow redirect in HTTPMethod ?
|
||||||
|
Property AllowRedirect : Boolean Read FAllowRedirect Write FAllowRedirect;
|
||||||
|
// Maximum number of redirects. When this number is reached, an exception is raised.
|
||||||
|
Property MaxRedirects : Byte Read FMaxRedirects Write FMaxRedirects default DefMaxRedirects;
|
||||||
|
// Called On redirect. Dest URL can be edited.
|
||||||
|
// If The DEST url is empty on return, the method is aborted (with redirect status).
|
||||||
|
Property OnRedirect : TRedirectEvent Read FOnRedirect Write FOnRedirect;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
TFPHTTPClient = Class(TFPCustomHTTPClient)
|
TFPHTTPClient = Class(TFPCustomHTTPClient)
|
||||||
@ -194,6 +217,9 @@ Type
|
|||||||
Property ResponseStatusCode;
|
Property ResponseStatusCode;
|
||||||
Property ResponseStatusText;
|
Property ResponseStatusText;
|
||||||
Property Cookies;
|
Property Cookies;
|
||||||
|
Property AllowRedirect;
|
||||||
|
Property MaxRedirects;
|
||||||
|
Property OnRedirect;
|
||||||
end;
|
end;
|
||||||
EHTTPClient = Class(Exception);
|
EHTTPClient = Class(Exception);
|
||||||
|
|
||||||
@ -210,6 +236,8 @@ resourcestring
|
|||||||
SErrUnexpectedResponse = 'Unexpected response status code: %d';
|
SErrUnexpectedResponse = 'Unexpected response status code: %d';
|
||||||
SErrChunkTooBig = 'Chunk too big';
|
SErrChunkTooBig = 'Chunk too big';
|
||||||
SErrChunkLineEndMissing = 'Chunk line end missing';
|
SErrChunkLineEndMissing = 'Chunk line end missing';
|
||||||
|
SErrMaxRedirectsReached = 'Maximum allowed redirects reached : %d';
|
||||||
|
SErrRedirectAborted = 'Redirect aborted.';
|
||||||
|
|
||||||
Const
|
Const
|
||||||
CRLF = #13#10;
|
CRLF = #13#10;
|
||||||
@ -336,7 +364,7 @@ begin
|
|||||||
System.Delete(Result,1,I);
|
System.Delete(Result,1,I);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Function TFPCustomHTTPClient.GetServerURL(URI : TURI) : String;
|
function TFPCustomHTTPClient.GetServerURL(URI: TURI): String;
|
||||||
|
|
||||||
Var
|
Var
|
||||||
D : String;
|
D : String;
|
||||||
@ -354,7 +382,8 @@ begin
|
|||||||
Result:=Result+'?'+URI.Params;
|
Result:=Result+'?'+URI.Params;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TFPCustomHTTPClient.ConnectToServer(Const AHost : String; APort : Integer);
|
procedure TFPCustomHTTPClient.ConnectToServer(const AHost: String;
|
||||||
|
APort: Integer);
|
||||||
|
|
||||||
begin
|
begin
|
||||||
if Aport=0 then
|
if Aport=0 then
|
||||||
@ -368,13 +397,13 @@ begin
|
|||||||
FreeAndNil(FSocket);
|
FreeAndNil(FSocket);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TFPCustomHTTPClient.AllowHeader(Var AHeader : String) : Boolean;
|
function TFPCustomHTTPClient.AllowHeader(var AHeader: String): Boolean;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
Result:=(AHeader<>'') and (Pos(':',AHeader)<>0);
|
Result:=(AHeader<>'') and (Pos(':',AHeader)<>0);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TFPCustomHTTPClient.SendRequest(Const AMethod : String; URI : TURI);
|
procedure TFPCustomHTTPClient.SendRequest(const AMethod: String; URI: TURI);
|
||||||
|
|
||||||
Var
|
Var
|
||||||
S,L : String;
|
S,L : String;
|
||||||
@ -408,6 +437,9 @@ begin
|
|||||||
if AllowHeader(L) then
|
if AllowHeader(L) then
|
||||||
S:=S+L+CRLF;
|
S:=S+L+CRLF;
|
||||||
end;
|
end;
|
||||||
|
FreeAndNil(FSentCookies);
|
||||||
|
FSentCookies:=FCookies;
|
||||||
|
FCookies:=Nil;
|
||||||
S:=S+CRLF;
|
S:=S+CRLF;
|
||||||
FSocket.WriteBuffer(S[1],Length(S));
|
FSocket.WriteBuffer(S[1],Length(S));
|
||||||
If Assigned(FRequestBody) then
|
If Assigned(FRequestBody) then
|
||||||
@ -495,7 +527,7 @@ begin
|
|||||||
Delete(S,1,P);
|
Delete(S,1,P);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Function TFPCustomHTTPClient.ParseStatusLine(AStatusLine : String) : Integer;
|
function TFPCustomHTTPClient.ParseStatusLine(AStatusLine: String): Integer;
|
||||||
|
|
||||||
Var
|
Var
|
||||||
S : String;
|
S : String;
|
||||||
@ -513,7 +545,7 @@ begin
|
|||||||
FResponseStatusText:=AStatusLine;
|
FResponseStatusText:=AStatusLine;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Function TFPCustomHTTPClient.ReadResponseHeaders : Integer;
|
function TFPCustomHTTPClient.ReadResponseHeaders: integer;
|
||||||
|
|
||||||
Procedure DoCookies(S : String);
|
Procedure DoCookies(S : String);
|
||||||
|
|
||||||
@ -556,7 +588,8 @@ begin
|
|||||||
Until (S='');
|
Until (S='');
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Function TFPCustomHTTPClient.CheckResponseCode(ACode : Integer; Const AllowedResponseCodes : Array of Integer) : Boolean;
|
function TFPCustomHTTPClient.CheckResponseCode(ACode: Integer;
|
||||||
|
const AllowedResponseCodes: array of Integer): Boolean;
|
||||||
|
|
||||||
Var
|
Var
|
||||||
I : Integer;
|
I : Integer;
|
||||||
@ -572,9 +605,11 @@ begin
|
|||||||
Inc(I);
|
Inc(I);
|
||||||
end
|
end
|
||||||
end;
|
end;
|
||||||
|
If (Not Result) and AllowRedirect then
|
||||||
|
Result:=IsRedirect(ACode);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Function TFPCustomHTTPClient.CheckContentLength: Integer;
|
function TFPCustomHTTPClient.CheckContentLength: Integer;
|
||||||
|
|
||||||
Const CL ='content-length:';
|
Const CL ='content-length:';
|
||||||
|
|
||||||
@ -597,7 +632,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Function TFPCustomHTTPClient.CheckTransferEncoding: string;
|
function TFPCustomHTTPClient.CheckTransferEncoding: string;
|
||||||
|
|
||||||
Const CL ='transfer-encoding:';
|
Const CL ='transfer-encoding:';
|
||||||
|
|
||||||
@ -634,7 +669,8 @@ begin
|
|||||||
GetCookies.Assign(AValue);
|
GetCookies.Assign(AValue);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TFPCustomHTTPClient.ReadResponse(Stream: TStream; Const AllowedResponseCodes : Array of Integer; HeadersOnly: Boolean = False);
|
procedure TFPCustomHTTPClient.ReadResponse(Stream: TStream;
|
||||||
|
const AllowedResponseCodes: array of Integer; HeadersOnly: Boolean);
|
||||||
|
|
||||||
Function Transfer(LB : Integer) : Integer;
|
Function Transfer(LB : Integer) : Integer;
|
||||||
|
|
||||||
@ -754,7 +790,7 @@ begin
|
|||||||
FResponseStatusCode:=ReadResponseHeaders;
|
FResponseStatusCode:=ReadResponseHeaders;
|
||||||
if not CheckResponseCode(FResponseStatusCode,AllowedResponseCodes) then
|
if not CheckResponseCode(FResponseStatusCode,AllowedResponseCodes) then
|
||||||
Raise EHTTPClient.CreateFmt(SErrUnexpectedResponse,[ResponseStatusCode]);
|
Raise EHTTPClient.CreateFmt(SErrUnexpectedResponse,[ResponseStatusCode]);
|
||||||
if HeadersOnly then
|
if HeadersOnly Or (AllowRedirect and IsRedirect(FResponseStatusCode)) then
|
||||||
exit;
|
exit;
|
||||||
if CompareText(CheckTransferEncoding,'chunked')=0 then
|
if CompareText(CheckTransferEncoding,'chunked')=0 then
|
||||||
ReadChunkedResponse
|
ReadChunkedResponse
|
||||||
@ -789,13 +825,14 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TFPCustomHTTPClient.DoMethod(Const AMethod,AURL: String; Stream: TStream; Const AllowedResponseCodes : Array of Integer);
|
procedure TFPCustomHTTPClient.DoMethod(const AMethod, AURL: String;
|
||||||
|
Stream: TStream; const AllowedResponseCodes: array of Integer);
|
||||||
|
|
||||||
Var
|
Var
|
||||||
URI : TURI;
|
URI : TURI;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
FResponseHeaders.Clear;
|
ResetResponse;
|
||||||
URI:=ParseURI(AURL,False);
|
URI:=ParseURI(AURL,False);
|
||||||
If (Lowercase(URI.Protocol)<>'http') then
|
If (Lowercase(URI.Protocol)<>'http') then
|
||||||
Raise EHTTPClient.CreateFmt(SErrInvalidProtocol,[URI.Protocol]);
|
Raise EHTTPClient.CreateFmt(SErrInvalidProtocol,[URI.Protocol]);
|
||||||
@ -814,28 +851,82 @@ begin
|
|||||||
FRequestHeaders:=TStringList.Create;
|
FRequestHeaders:=TStringList.Create;
|
||||||
FResponseHeaders:=TStringList.Create;
|
FResponseHeaders:=TStringList.Create;
|
||||||
FHTTPVersion:='1.1';
|
FHTTPVersion:='1.1';
|
||||||
|
FMaxRedirects:=DefMaxRedirects;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
destructor TFPCustomHTTPClient.Destroy;
|
destructor TFPCustomHTTPClient.Destroy;
|
||||||
begin
|
begin
|
||||||
FreeAndNil(FCookies);
|
FreeAndNil(FCookies);
|
||||||
|
FreeAndNil(FSentCookies);
|
||||||
FreeAndNil(FRequestHeaders);
|
FreeAndNil(FRequestHeaders);
|
||||||
FreeAndNil(FResponseHeaders);
|
FreeAndNil(FResponseHeaders);
|
||||||
inherited Destroy;
|
inherited Destroy;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TFPCustomHTTPClient.ResetResponse;
|
||||||
|
|
||||||
|
begin
|
||||||
|
FResponseStatusCode:=0;
|
||||||
|
FResponseStatusText:='';
|
||||||
|
FResponseHeaders.Clear;
|
||||||
|
FServerHTTPVersion:='';
|
||||||
|
FBuffer:='';
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
procedure TFPCustomHTTPClient.HTTPMethod(const AMethod, AURL: String;
|
procedure TFPCustomHTTPClient.HTTPMethod(const AMethod, AURL: String;
|
||||||
Stream: TStream; const AllowedResponseCodes: array of Integer);
|
Stream: TStream; const AllowedResponseCodes: array of Integer);
|
||||||
|
|
||||||
|
Var
|
||||||
|
M,L,NL : String;
|
||||||
|
C : Char;
|
||||||
|
RC : Integer;
|
||||||
|
RR : Boolean; // Repeat request ?
|
||||||
|
|
||||||
begin
|
begin
|
||||||
DoMethod(AMethod,AURL,Stream,AllowedResponseCodes);
|
L:=AURL;
|
||||||
|
M:=AMethod;
|
||||||
|
RC:=0;
|
||||||
|
RR:=False;
|
||||||
|
Repeat
|
||||||
|
if Not AllowRedirect then
|
||||||
|
DoMethod(AMethod,L,Stream,AllowedResponseCodes)
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
DoMethod(AMethod,L,Stream,AllowedResponseCodes);
|
||||||
|
if IsRedirect(FResponseStatusCode) then
|
||||||
|
begin
|
||||||
|
Inc(RC);
|
||||||
|
if (RC>MaxRedirects) then
|
||||||
|
Raise EHTTPClient.CreateFmt(SErrMaxRedirectsReached,[RC]);
|
||||||
|
C:=FResponseHeaders.NameValueSeparator;
|
||||||
|
FResponseHeaders.NameValueSeparator:=':';
|
||||||
|
NL:=TrimLeft(FResponseHeaders.Values['Location']);
|
||||||
|
FResponseHeaders.NameValueSeparator:=C;
|
||||||
|
if Not Assigned(FOnRedirect) then
|
||||||
|
L:=NL
|
||||||
|
else
|
||||||
|
FOnRedirect(Self,L,NL);
|
||||||
|
if (RedirectForcesGET(FResponseStatusCode)) then
|
||||||
|
M:='GET';
|
||||||
|
L:=NL;
|
||||||
|
// Request has saved cookies in sentcookies.
|
||||||
|
FreeAndNil(FCookies);
|
||||||
|
FCookies:=FSentCookies;
|
||||||
|
FSentCookies:=Nil;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
RR:=AllowRedirect and IsRedirect(FResponseStatusCode) and (L<>'')
|
||||||
|
until not RR;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TFPCustomHTTPClient.Get(Const AURL: String; Stream: TStream);
|
procedure TFPCustomHTTPClient.Get(const AURL: String; Stream: TStream);
|
||||||
begin
|
begin
|
||||||
DoMethod('GET',AURL,Stream,[200]);
|
HTTPMethod('GET',AURL,Stream,[200]);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TFPCustomHTTPClient.Get(Const AURL: String; const LocalFileName: String);
|
procedure TFPCustomHTTPClient.Get(const AURL: String;
|
||||||
|
const LocalFileName: String);
|
||||||
|
|
||||||
Var
|
Var
|
||||||
F : TFileStream;
|
F : TFileStream;
|
||||||
@ -854,7 +945,7 @@ begin
|
|||||||
Response.Text:=Get(AURL);
|
Response.Text:=Get(AURL);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TFPCustomHTTPClient.Get(Const AURL: String): String;
|
function TFPCustomHTTPClient.Get(const AURL: String): String;
|
||||||
|
|
||||||
Var
|
Var
|
||||||
SS : TStringStream;
|
SS : TStringStream;
|
||||||
@ -869,8 +960,26 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
class function TFPCustomHTTPClient.IsRedirect(ACode: Integer): Boolean;
|
||||||
|
begin
|
||||||
|
Case ACode of
|
||||||
|
301,
|
||||||
|
302,
|
||||||
|
303,
|
||||||
|
307,808 : Result:=True;
|
||||||
|
else
|
||||||
|
Result:=False;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
Class Procedure TFPCustomHTTPClient.SimpleGet(Const AURL : String; Stream : TStream);
|
class function TFPCustomHTTPClient.RedirectForcesGET(ACode: Integer): Boolean;
|
||||||
|
begin
|
||||||
|
Result:=(ACode=303)
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
class procedure TFPCustomHTTPClient.SimpleGet(const AURL: String;
|
||||||
|
Stream: TStream);
|
||||||
|
|
||||||
begin
|
begin
|
||||||
With Self.Create(nil) do
|
With Self.Create(nil) do
|
||||||
@ -883,7 +992,8 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
Class Procedure TFPCustomHTTPClient.SimpleGet(Const AURL : String; const LocalFileName : String);
|
class procedure TFPCustomHTTPClient.SimpleGet(const AURL: String;
|
||||||
|
const LocalFileName: String);
|
||||||
|
|
||||||
begin
|
begin
|
||||||
With Self.Create(nil) do
|
With Self.Create(nil) do
|
||||||
@ -896,7 +1006,8 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
Class Procedure TFPCustomHTTPClient.SimpleGet(Const AURL : String; Response : TStrings);
|
class procedure TFPCustomHTTPClient.SimpleGet(const AURL: String;
|
||||||
|
Response: TStrings);
|
||||||
|
|
||||||
begin
|
begin
|
||||||
With Self.Create(nil) do
|
With Self.Create(nil) do
|
||||||
@ -909,7 +1020,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
Class Function TFPCustomHTTPClient.SimpleGet(Const AURL : String) : String;
|
class function TFPCustomHTTPClient.SimpleGet(const AURL: String): String;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
With Self.Create(nil) do
|
With Self.Create(nil) do
|
||||||
@ -923,7 +1034,7 @@ end;
|
|||||||
|
|
||||||
procedure TFPCustomHTTPClient.Post(const URL: string; const Response: TStream);
|
procedure TFPCustomHTTPClient.Post(const URL: string; const Response: TStream);
|
||||||
begin
|
begin
|
||||||
DoMethod('POST',URL,Response,[]);
|
HTTPMethod('POST',URL,Response,[]);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -963,7 +1074,8 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
Class procedure TFPCustomHTTPClient.SimplePost(const URL: string; const Response: TStream);
|
class procedure TFPCustomHTTPClient.SimplePost(const URL: string;
|
||||||
|
const Response: TStream);
|
||||||
|
|
||||||
begin
|
begin
|
||||||
With Self.Create(nil) do
|
With Self.Create(nil) do
|
||||||
@ -976,7 +1088,8 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
Class procedure TFPCustomHTTPClient.SimplePost(const URL: string; Response : TStrings);
|
class procedure TFPCustomHTTPClient.SimplePost(const URL: string;
|
||||||
|
Response: TStrings);
|
||||||
|
|
||||||
begin
|
begin
|
||||||
With Self.Create(nil) do
|
With Self.Create(nil) do
|
||||||
@ -989,7 +1102,8 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
Class procedure TFPCustomHTTPClient.SimplePost(const URL: string; const LocalFileName: String);
|
class procedure TFPCustomHTTPClient.SimplePost(const URL: string;
|
||||||
|
const LocalFileName: String);
|
||||||
|
|
||||||
begin
|
begin
|
||||||
With Self.Create(nil) do
|
With Self.Create(nil) do
|
||||||
@ -1002,7 +1116,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
Class function TFPCustomHTTPClient.SimplePost(const URL: string) : String;
|
class function TFPCustomHTTPClient.SimplePost(const URL: string): String;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
With Self.Create(nil) do
|
With Self.Create(nil) do
|
||||||
@ -1016,7 +1130,7 @@ end;
|
|||||||
|
|
||||||
procedure TFPCustomHTTPClient.Put(const URL: string; const Response: TStream);
|
procedure TFPCustomHTTPClient.Put(const URL: string; const Response: TStream);
|
||||||
begin
|
begin
|
||||||
DoMethod('PUT',URL,Response,[]);
|
HTTPMethod('PUT',URL,Response,[]);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TFPCustomHTTPClient.Put(const URL: string; Response: TStrings);
|
procedure TFPCustomHTTPClient.Put(const URL: string; Response: TStrings);
|
||||||
@ -1024,8 +1138,8 @@ begin
|
|||||||
Response.Text:=Put(URL);
|
Response.Text:=Put(URL);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TFPCustomHTTPClient.Put(const URL: string;
|
procedure TFPCustomHTTPClient.Put(const URL: string; const LocalFileName: String
|
||||||
const LocalFileName: String);
|
);
|
||||||
|
|
||||||
Var
|
Var
|
||||||
F : TFileStream;
|
F : TFileStream;
|
||||||
@ -1052,7 +1166,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Class procedure TFPCustomHTTPClient.SimplePut(const URL: string;
|
class procedure TFPCustomHTTPClient.SimplePut(const URL: string;
|
||||||
const Response: TStream);
|
const Response: TStream);
|
||||||
|
|
||||||
begin
|
begin
|
||||||
@ -1065,7 +1179,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Class procedure TFPCustomHTTPClient.SimplePut(const URL: string;
|
class procedure TFPCustomHTTPClient.SimplePut(const URL: string;
|
||||||
Response: TStrings);
|
Response: TStrings);
|
||||||
|
|
||||||
begin
|
begin
|
||||||
@ -1078,7 +1192,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Class procedure TFPCustomHTTPClient.SimplePut(const URL: string;
|
class procedure TFPCustomHTTPClient.SimplePut(const URL: string;
|
||||||
const LocalFileName: String);
|
const LocalFileName: String);
|
||||||
|
|
||||||
begin
|
begin
|
||||||
@ -1091,7 +1205,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Class function TFPCustomHTTPClient.SimplePut(const URL: string): String;
|
class function TFPCustomHTTPClient.SimplePut(const URL: string): String;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
With Self.Create(nil) do
|
With Self.Create(nil) do
|
||||||
@ -1103,9 +1217,10 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TFPCustomHTTPClient.Delete(const URL: string; const Response: TStream);
|
procedure TFPCustomHTTPClient.Delete(const URL: string; const Response: TStream
|
||||||
|
);
|
||||||
begin
|
begin
|
||||||
DoMethod('DELETE',URL,Response,[]);
|
HTTPMethod('DELETE',URL,Response,[]);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TFPCustomHTTPClient.Delete(const URL: string; Response: TStrings);
|
procedure TFPCustomHTTPClient.Delete(const URL: string; Response: TStrings);
|
||||||
@ -1141,7 +1256,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Class procedure TFPCustomHTTPClient.SimpleDelete(const URL: string;
|
class procedure TFPCustomHTTPClient.SimpleDelete(const URL: string;
|
||||||
const Response: TStream);
|
const Response: TStream);
|
||||||
|
|
||||||
begin
|
begin
|
||||||
@ -1154,7 +1269,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Class procedure TFPCustomHTTPClient.SimpleDelete(const URL: string;
|
class procedure TFPCustomHTTPClient.SimpleDelete(const URL: string;
|
||||||
Response: TStrings);
|
Response: TStrings);
|
||||||
|
|
||||||
begin
|
begin
|
||||||
@ -1167,7 +1282,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Class procedure TFPCustomHTTPClient.SimpleDelete(const URL: string;
|
class procedure TFPCustomHTTPClient.SimpleDelete(const URL: string;
|
||||||
const LocalFileName: String);
|
const LocalFileName: String);
|
||||||
|
|
||||||
begin
|
begin
|
||||||
@ -1180,7 +1295,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Class function TFPCustomHTTPClient.SimpleDelete(const URL: string): String;
|
class function TFPCustomHTTPClient.SimpleDelete(const URL: string): String;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
With Self.Create(nil) do
|
With Self.Create(nil) do
|
||||||
@ -1192,9 +1307,10 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TFPCustomHTTPClient.Options(const URL: string; const Response: TStream);
|
procedure TFPCustomHTTPClient.Options(const URL: string; const Response: TStream
|
||||||
|
);
|
||||||
begin
|
begin
|
||||||
DoMethod('OPTIONS',URL,Response,[]);
|
HTTPMethod('OPTIONS',URL,Response,[]);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TFPCustomHTTPClient.Options(const URL: string; Response: TStrings);
|
procedure TFPCustomHTTPClient.Options(const URL: string; Response: TStrings);
|
||||||
@ -1230,7 +1346,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Class procedure TFPCustomHTTPClient.SimpleOptions(const URL: string;
|
class procedure TFPCustomHTTPClient.SimpleOptions(const URL: string;
|
||||||
const Response: TStream);
|
const Response: TStream);
|
||||||
|
|
||||||
begin
|
begin
|
||||||
@ -1243,7 +1359,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Class procedure TFPCustomHTTPClient.SimpleOptions(const URL: string;
|
class procedure TFPCustomHTTPClient.SimpleOptions(const URL: string;
|
||||||
Response: TStrings);
|
Response: TStrings);
|
||||||
|
|
||||||
begin
|
begin
|
||||||
@ -1256,7 +1372,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Class procedure TFPCustomHTTPClient.SimpleOptions(const URL: string;
|
class procedure TFPCustomHTTPClient.SimpleOptions(const URL: string;
|
||||||
const LocalFileName: String);
|
const LocalFileName: String);
|
||||||
|
|
||||||
begin
|
begin
|
||||||
@ -1269,7 +1385,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Class function TFPCustomHTTPClient.SimpleOptions(const URL: string): String;
|
class function TFPCustomHTTPClient.SimpleOptions(const URL: string): String;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
With Self.Create(nil) do
|
With Self.Create(nil) do
|
||||||
@ -1281,7 +1397,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
class procedure TFPCustomHTTPClient.Head(AURL : String; Headers: TStrings);
|
class procedure TFPCustomHTTPClient.Head(AURL: String; Headers: TStrings);
|
||||||
begin
|
begin
|
||||||
With Self.Create(nil) do
|
With Self.Create(nil) do
|
||||||
try
|
try
|
||||||
@ -1351,8 +1467,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TFPCustomHTTPClient.FormPost(const URL: string; FormData: TStrings
|
function TFPCustomHTTPClient.FormPost(const URL: string; FormData: TStrings): String;
|
||||||
): String;
|
|
||||||
Var
|
Var
|
||||||
SS : TStringStream;
|
SS : TStringStream;
|
||||||
begin
|
begin
|
||||||
@ -1365,7 +1480,8 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Class Procedure TFPCustomHTTPClient.SimpleFormPost(const URL, FormData: string; const Response: TStream);
|
class procedure TFPCustomHTTPClient.SimpleFormPost(const URL, FormData: string;
|
||||||
|
const Response: TStream);
|
||||||
|
|
||||||
begin
|
begin
|
||||||
With Self.Create(nil) do
|
With Self.Create(nil) do
|
||||||
@ -1378,7 +1494,8 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
Class Procedure TFPCustomHTTPClient.SimpleFormPost(const URL : string; FormData: TStrings; const Response: TStream);
|
class procedure TFPCustomHTTPClient.SimpleFormPost(const URL: string;
|
||||||
|
FormData: TStrings; const Response: TStream);
|
||||||
|
|
||||||
begin
|
begin
|
||||||
With Self.Create(nil) do
|
With Self.Create(nil) do
|
||||||
@ -1391,7 +1508,8 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
Class Procedure TFPCustomHTTPClient.SimpleFormPost(const URL, FormData: string; const Response: TStrings);
|
class procedure TFPCustomHTTPClient.SimpleFormPost(const URL, FormData: string;
|
||||||
|
const Response: TStrings);
|
||||||
|
|
||||||
begin
|
begin
|
||||||
With Self.Create(nil) do
|
With Self.Create(nil) do
|
||||||
@ -1403,7 +1521,8 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Class Procedure TFPCustomHTTPClient.SimpleFormPost(const URL : string; FormData: TStrings; const Response: TStrings);
|
class procedure TFPCustomHTTPClient.SimpleFormPost(const URL: string;
|
||||||
|
FormData: TStrings; const Response: TStrings);
|
||||||
|
|
||||||
begin
|
begin
|
||||||
With Self.Create(nil) do
|
With Self.Create(nil) do
|
||||||
@ -1415,7 +1534,8 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Class function TFPCustomHTTPClient.SimpleFormPost(const URL, FormData: string): String;
|
class function TFPCustomHTTPClient.SimpleFormPost(const URL, FormData: string
|
||||||
|
): String;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
With Self.Create(nil) do
|
With Self.Create(nil) do
|
||||||
@ -1427,7 +1547,8 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Class function TFPCustomHTTPClient.SimpleFormPost(const URL: string; FormData : TStrings): String;
|
class function TFPCustomHTTPClient.SimpleFormPost(const URL: string;
|
||||||
|
FormData: TStrings): String;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
With Self.Create(nil) do
|
With Self.Create(nil) do
|
||||||
@ -1440,7 +1561,8 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
procedure TFPCustomHTTPClient.FileFormPost(const AURL, AFieldName, AFileName: string; const Response: TStream);
|
procedure TFPCustomHTTPClient.FileFormPost(const AURL, AFieldName,
|
||||||
|
AFileName: string; const Response: TStream);
|
||||||
|
|
||||||
Var
|
Var
|
||||||
S, Sep : string;
|
S, Sep : string;
|
||||||
@ -1473,7 +1595,8 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
Class Procedure TFPCustomHTTPClient.SimpleFileFormPost(const AURL, AFieldName, AFileName: string; const Response: TStream);
|
class procedure TFPCustomHTTPClient.SimpleFileFormPost(const AURL, AFieldName,
|
||||||
|
AFileName: string; const Response: TStream);
|
||||||
|
|
||||||
begin
|
begin
|
||||||
With Self.Create(nil) do
|
With Self.Create(nil) do
|
||||||
|
Loading…
Reference in New Issue
Block a user