|
@@ -42,6 +42,28 @@ Type
|
|
// Use this to set up a socket handler. UseSSL is true if protocol was https
|
|
// Use this to set up a socket handler. UseSSL is true if protocol was https
|
|
TGetSocketHandlerEvent = Procedure (Sender : TObject; Const UseSSL : Boolean; Out AHandler : TSocketHandler) of object;
|
|
TGetSocketHandlerEvent = Procedure (Sender : TObject; Const UseSSL : Boolean; Out AHandler : TSocketHandler) of object;
|
|
|
|
|
|
|
|
+ TFPCustomHTTPClient = Class;
|
|
|
|
+
|
|
|
|
+ { TProxyData }
|
|
|
|
+
|
|
|
|
+ TProxyData = Class (TPersistent)
|
|
|
|
+ private
|
|
|
|
+ FHost: string;
|
|
|
|
+ FPassword: String;
|
|
|
|
+ FPort: Word;
|
|
|
|
+ FUserName: String;
|
|
|
|
+ FHTTPClient : TFPCustomHTTPClient;
|
|
|
|
+ Protected
|
|
|
|
+ Function GetProxyHeaders : String; virtual;
|
|
|
|
+ Property HTTPClient : TFPCustomHTTPClient Read FHTTPClient;
|
|
|
|
+ Public
|
|
|
|
+ Procedure Assign(Source: TPersistent); override;
|
|
|
|
+ Property Host: string Read FHost Write FHost;
|
|
|
|
+ Property Port: Word Read FPort Write FPort;
|
|
|
|
+ Property UserName : String Read FUserName Write FUserName;
|
|
|
|
+ Property Password : String Read FPassword Write FPassword;
|
|
|
|
+ end;
|
|
|
|
+
|
|
{ TFPCustomHTTPClient }
|
|
{ TFPCustomHTTPClient }
|
|
TFPCustomHTTPClient = Class(TComponent)
|
|
TFPCustomHTTPClient = Class(TComponent)
|
|
private
|
|
private
|
|
@@ -68,14 +90,21 @@ Type
|
|
FBuffer : Ansistring;
|
|
FBuffer : Ansistring;
|
|
FUserName: String;
|
|
FUserName: String;
|
|
FOnGetSocketHandler : TGetSocketHandlerEvent;
|
|
FOnGetSocketHandler : TGetSocketHandlerEvent;
|
|
|
|
+ FProxy : TProxyData;
|
|
function CheckContentLength: Int64;
|
|
function CheckContentLength: Int64;
|
|
function CheckTransferEncoding: string;
|
|
function CheckTransferEncoding: string;
|
|
function GetCookies: TStrings;
|
|
function GetCookies: TStrings;
|
|
|
|
+ function GetProxy: TProxyData;
|
|
Procedure ResetResponse;
|
|
Procedure ResetResponse;
|
|
Procedure SetCookies(const AValue: TStrings);
|
|
Procedure SetCookies(const AValue: TStrings);
|
|
|
|
+ procedure SetProxy(AValue: TProxyData);
|
|
Procedure SetRequestHeaders(const AValue: TStrings);
|
|
Procedure SetRequestHeaders(const AValue: TStrings);
|
|
procedure SetIOTimeout(AValue: Integer);
|
|
procedure SetIOTimeout(AValue: Integer);
|
|
protected
|
|
protected
|
|
|
|
+ // True if we need to use a proxy: ProxyData Assigned and Hostname Set
|
|
|
|
+ Function ProxyActive : Boolean;
|
|
|
|
+ // Override this if you want to create a custom instance of proxy.
|
|
|
|
+ Function CreateProxyData : TProxyData;
|
|
// Called whenever data is read.
|
|
// Called whenever data is read.
|
|
Procedure DoDataRead; virtual;
|
|
Procedure DoDataRead; virtual;
|
|
// 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.
|
|
@@ -241,6 +270,8 @@ Type
|
|
// Called On redirect. Dest URL can be edited.
|
|
// Called On redirect. Dest URL can be edited.
|
|
// If The DEST url is empty on return, the method is aborted (with redirect status).
|
|
// If The DEST url is empty on return, the method is aborted (with redirect status).
|
|
Property OnRedirect : TRedirectEvent Read FOnRedirect Write FOnRedirect;
|
|
Property OnRedirect : TRedirectEvent Read FOnRedirect Write FOnRedirect;
|
|
|
|
+ // Proxy support
|
|
|
|
+ Property Proxy : TProxyData Read GetProxy Write SetProxy;
|
|
// Authentication.
|
|
// Authentication.
|
|
// When set, they override the credentials found in the URI.
|
|
// When set, they override the credentials found in the URI.
|
|
// They also override any Authenticate: header in Requestheaders.
|
|
// They also override any Authenticate: header in Requestheaders.
|
|
@@ -255,11 +286,12 @@ Type
|
|
Property OnHeaders : TNotifyEvent Read FOnHeaders Write FOnHeaders;
|
|
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.
|
|
// Called to create socket handler. If not set, or Nil is returned, a standard socket handler is created.
|
|
Property OnGetSocketHandler : TGetSocketHandlerEvent Read FOnGetSocketHandler Write FOnGetSocketHandler;
|
|
Property OnGetSocketHandler : TGetSocketHandlerEvent Read FOnGetSocketHandler Write FOnGetSocketHandler;
|
|
|
|
+
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
|
|
TFPHTTPClient = Class(TFPCustomHTTPClient)
|
|
TFPHTTPClient = Class(TFPCustomHTTPClient)
|
|
- Public
|
|
|
|
|
|
+ Published
|
|
Property IOTimeout;
|
|
Property IOTimeout;
|
|
Property RequestHeaders;
|
|
Property RequestHeaders;
|
|
Property RequestBody;
|
|
Property RequestBody;
|
|
@@ -278,6 +310,7 @@ Type
|
|
Property OnDataReceived;
|
|
Property OnDataReceived;
|
|
Property OnHeaders;
|
|
Property OnHeaders;
|
|
Property OnGetSocketHandler;
|
|
Property OnGetSocketHandler;
|
|
|
|
+ Property Proxy;
|
|
end;
|
|
end;
|
|
|
|
|
|
EHTTPClient = Class(EHTTP);
|
|
EHTTPClient = Class(EHTTP);
|
|
@@ -381,6 +414,33 @@ begin
|
|
SetLength(Result, P-Pchar(Result));
|
|
SetLength(Result, P-Pchar(Result));
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+{ TProxyData }
|
|
|
|
+
|
|
|
|
+function TProxyData.GetProxyHeaders: String;
|
|
|
|
+begin
|
|
|
|
+ Result:='';
|
|
|
|
+ if (UserName<>'') then
|
|
|
|
+ Result:='Proxy-Authorization: Basic ' + EncodeStringBase64(UserName+':'+UserName);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TProxyData.Assign(Source: TPersistent);
|
|
|
|
+
|
|
|
|
+Var
|
|
|
|
+ D : TProxyData;
|
|
|
|
+
|
|
|
|
+begin
|
|
|
|
+ if Source is TProxyData then
|
|
|
|
+ begin
|
|
|
|
+ D:=Source as TProxyData;
|
|
|
|
+ Host:=D.Host;
|
|
|
|
+ Port:=D.Port;
|
|
|
|
+ UserName:=D.UserName;
|
|
|
|
+ Password:=D.Password;
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ inherited Assign(Source);
|
|
|
|
+end;
|
|
|
|
+
|
|
{ TFPCustomHTTPClient }
|
|
{ TFPCustomHTTPClient }
|
|
|
|
|
|
procedure TFPCustomHTTPClient.SetRequestHeaders(const AValue: TStrings);
|
|
procedure TFPCustomHTTPClient.SetRequestHeaders(const AValue: TStrings);
|
|
@@ -397,6 +457,16 @@ begin
|
|
FSocket.IOTimeout:=AValue;
|
|
FSocket.IOTimeout:=AValue;
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+function TFPCustomHTTPClient.ProxyActive: Boolean;
|
|
|
|
+begin
|
|
|
|
+ Result:=Assigned(FProxy) and (FProxy.Host<>'') and (FProxy.Port>0);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TFPCustomHTTPClient.CreateProxyData: TProxyData;
|
|
|
|
+begin
|
|
|
|
+ Result:=TProxyData.Create;
|
|
|
|
+end;
|
|
|
|
+
|
|
procedure TFPCustomHTTPClient.DoDataRead;
|
|
procedure TFPCustomHTTPClient.DoDataRead;
|
|
begin
|
|
begin
|
|
If Assigned(FOnDataReceived) Then
|
|
If Assigned(FOnDataReceived) Then
|
|
@@ -437,6 +507,13 @@ begin
|
|
Result:=D+URI.Document;
|
|
Result:=D+URI.Document;
|
|
if (URI.Params<>'') then
|
|
if (URI.Params<>'') then
|
|
Result:=Result+'?'+URI.Params;
|
|
Result:=Result+'?'+URI.Params;
|
|
|
|
+ if ProxyActive then
|
|
|
|
+ begin
|
|
|
|
+ if URI.Port>0 then
|
|
|
|
+ Result:=':'+IntToStr(URI.Port)+Result;
|
|
|
|
+ Result:=URI.Protocol+'://'+URI.Host+Result;
|
|
|
|
+ end;
|
|
|
|
+ Writeln('Doing URL : ',Result);
|
|
end;
|
|
end;
|
|
|
|
|
|
function TFPCustomHTTPClient.GetSocketHandler(const UseSSL: Boolean): TSocketHandler;
|
|
function TFPCustomHTTPClient.GetSocketHandler(const UseSSL: Boolean): TSocketHandler;
|
|
@@ -494,7 +571,7 @@ end;
|
|
procedure TFPCustomHTTPClient.SendRequest(const AMethod: String; URI: TURI);
|
|
procedure TFPCustomHTTPClient.SendRequest(const AMethod: String; URI: TURI);
|
|
|
|
|
|
Var
|
|
Var
|
|
- UN,PW,S,L : String;
|
|
|
|
|
|
+ PH,UN,PW,S,L : String;
|
|
I : Integer;
|
|
I : Integer;
|
|
|
|
|
|
begin
|
|
begin
|
|
@@ -513,6 +590,12 @@ begin
|
|
If I<>-1 then
|
|
If I<>-1 then
|
|
RequestHeaders.Delete(i);
|
|
RequestHeaders.Delete(i);
|
|
end;
|
|
end;
|
|
|
|
+ if Assigned(FProxy) and (FProxy.Host<>'') then
|
|
|
|
+ begin
|
|
|
|
+ PH:=FProxy.GetProxyHeaders;
|
|
|
|
+ if (PH<>'') then
|
|
|
|
+ S:=S+PH+CRLF;
|
|
|
|
+ end;
|
|
S:=S+'Host: '+URI.Host;
|
|
S:=S+'Host: '+URI.Host;
|
|
If (URI.Port<>0) then
|
|
If (URI.Port<>0) then
|
|
S:=S+':'+IntToStr(URI.Port);
|
|
S:=S+':'+IntToStr(URI.Port);
|
|
@@ -773,12 +856,28 @@ begin
|
|
Result:=FCookies;
|
|
Result:=FCookies;
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+function TFPCustomHTTPClient.GetProxy: TProxyData;
|
|
|
|
+begin
|
|
|
|
+ If not Assigned(FProxy) then
|
|
|
|
+ begin
|
|
|
|
+ FProxy:=CreateProxyData;
|
|
|
|
+ FProxy.FHTTPClient:=Self;
|
|
|
|
+ end;
|
|
|
|
+ Result:=FProxy;
|
|
|
|
+end;
|
|
|
|
+
|
|
procedure TFPCustomHTTPClient.SetCookies(const AValue: TStrings);
|
|
procedure TFPCustomHTTPClient.SetCookies(const AValue: TStrings);
|
|
begin
|
|
begin
|
|
if GetCookies=AValue then exit;
|
|
if GetCookies=AValue then exit;
|
|
GetCookies.Assign(AValue);
|
|
GetCookies.Assign(AValue);
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+procedure TFPCustomHTTPClient.SetProxy(AValue: TProxyData);
|
|
|
|
+begin
|
|
|
|
+ if (AValue=FProxy) then exit;
|
|
|
|
+ Proxy.Assign(AValue);
|
|
|
|
+end;
|
|
|
|
+
|
|
procedure TFPCustomHTTPClient.ReadResponse(Stream: TStream;
|
|
procedure TFPCustomHTTPClient.ReadResponse(Stream: TStream;
|
|
const AllowedResponseCodes: array of Integer; HeadersOnly: Boolean);
|
|
const AllowedResponseCodes: array of Integer; HeadersOnly: Boolean);
|
|
|
|
|
|
@@ -951,7 +1050,8 @@ procedure TFPCustomHTTPClient.DoMethod(const AMethod, AURL: String;
|
|
|
|
|
|
Var
|
|
Var
|
|
URI : TURI;
|
|
URI : TURI;
|
|
- P : String;
|
|
|
|
|
|
+ P,CHost : String;
|
|
|
|
+ CPort : Word;
|
|
|
|
|
|
begin
|
|
begin
|
|
ResetResponse;
|
|
ResetResponse;
|
|
@@ -959,7 +1059,17 @@ begin
|
|
p:=LowerCase(URI.Protocol);
|
|
p:=LowerCase(URI.Protocol);
|
|
If Not ((P='http') or (P='https')) then
|
|
If Not ((P='http') or (P='https')) then
|
|
Raise EHTTPClient.CreateFmt(SErrInvalidProtocol,[URI.Protocol]);
|
|
Raise EHTTPClient.CreateFmt(SErrInvalidProtocol,[URI.Protocol]);
|
|
- ConnectToServer(URI.Host,URI.Port,P='https');
|
|
|
|
|
|
+ if ProxyActive then
|
|
|
|
+ begin
|
|
|
|
+ CHost:=Proxy.Host;
|
|
|
|
+ CPort:=Proxy.Port;
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ begin
|
|
|
|
+ CHost:=URI.Host;
|
|
|
|
+ CPort:=URI.Port;
|
|
|
|
+ end;
|
|
|
|
+ ConnectToServer(CHost,CPort,P='https');
|
|
try
|
|
try
|
|
SendRequest(AMethod,URI);
|
|
SendRequest(AMethod,URI);
|
|
ReadResponse(Stream,AllowedResponseCodes,CompareText(AMethod,'HEAD')=0);
|
|
ReadResponse(Stream,AllowedResponseCodes,CompareText(AMethod,'HEAD')=0);
|
|
@@ -981,6 +1091,7 @@ end;
|
|
|
|
|
|
destructor TFPCustomHTTPClient.Destroy;
|
|
destructor TFPCustomHTTPClient.Destroy;
|
|
begin
|
|
begin
|
|
|
|
+ FreeAndNil(FProxy);
|
|
FreeAndNil(FCookies);
|
|
FreeAndNil(FCookies);
|
|
FreeAndNil(FSentCookies);
|
|
FreeAndNil(FSentCookies);
|
|
FreeAndNil(FRequestHeaders);
|
|
FreeAndNil(FRequestHeaders);
|