Browse Source

* Added Proxy support: bug ID #26270

git-svn-id: trunk@33742 -
michael 9 years ago
parent
commit
07073c09a6

+ 4 - 0
packages/fcl-web/examples/httpclient/httpget.pas

@@ -92,6 +92,10 @@ begin
       OnPassword:=@DoPassword;
       OnPassword:=@DoPassword;
       OnDataReceived:=@DoProgress;
       OnDataReceived:=@DoProgress;
       OnHeaders:=@DoHeaders;
       OnHeaders:=@DoHeaders;
+      { Set this if you want to try a proxy.
+      Proxy.Host:='195.207.46.20';
+      Proxy.Port:=8080;
+      }
       Get(ParamStr(1),ParamStr(2));
       Get(ParamStr(1),ParamStr(2));
     finally
     finally
       Free;
       Free;

+ 115 - 4
packages/fcl-web/src/base/fphttpclient.pp

@@ -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);