You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@thrift.apache.org by je...@apache.org on 2019/06/07 20:27:18 UTC

[thrift] branch master updated (9369443 -> 83ff753)

This is an automated email from the ASF dual-hosted git repository.

jensg pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/thrift.git.


    from 9369443  THRIFT-4879 general performance improvements for netstd library Client: netstd Patch: Jens Geyer
     new 47f6317  THRIFT-4881 Allow TLS1.1 and TLS1.2 even when not configured as systemwide default Client: Delphi Patch: Jens Geyer
     new 83ff753  THRIFT-4882 Autodetect proxy settings with WinHTTP Client: Delphi Patch: Jens Geyer

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 lib/delphi/src/Thrift.Transport.MsxmlHTTP.pas |  17 +-
 lib/delphi/src/Thrift.Transport.WinHTTP.pas   |  57 +++-
 lib/delphi/src/Thrift.Transport.pas           |  14 +-
 lib/delphi/src/Thrift.Utils.pas               |   3 +
 lib/delphi/src/Thrift.WinHTTP.pas             | 396 +++++++++++++++++++++++++-
 lib/delphi/test/TestClient.pas                |  33 ++-
 6 files changed, 502 insertions(+), 18 deletions(-)


[thrift] 01/02: THRIFT-4881 Allow TLS1.1 and TLS1.2 even when not configured as systemwide default Client: Delphi Patch: Jens Geyer

Posted by je...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

jensg pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/thrift.git

commit 47f6317336b2d8fbd1249a1a49aa561ee052719f
Author: Jens Geyer <je...@apache.org>
AuthorDate: Thu Jun 6 22:42:58 2019 +0200

    THRIFT-4881 Allow TLS1.1 and TLS1.2 even when not configured as systemwide default
    Client: Delphi
    Patch: Jens Geyer
---
 lib/delphi/src/Thrift.Transport.MsxmlHTTP.pas |  13 ++
 lib/delphi/src/Thrift.Transport.WinHTTP.pas   |  42 ++++++
 lib/delphi/src/Thrift.Transport.pas           |  14 +-
 lib/delphi/src/Thrift.WinHTTP.pas             | 177 +++++++++++++++++++++++++-
 lib/delphi/test/TestClient.pas                |   7 +-
 5 files changed, 249 insertions(+), 4 deletions(-)

diff --git a/lib/delphi/src/Thrift.Transport.MsxmlHTTP.pas b/lib/delphi/src/Thrift.Transport.MsxmlHTTP.pas
index cdfb541..620beba 100644
--- a/lib/delphi/src/Thrift.Transport.MsxmlHTTP.pas
+++ b/lib/delphi/src/Thrift.Transport.MsxmlHTTP.pas
@@ -68,9 +68,12 @@ type
     function GetSendTimeout: Integer;
     procedure SetReadTimeout(const Value: Integer);
     function GetReadTimeout: Integer;
+    function GetSecureProtocols : TSecureProtocols;
+    procedure SetSecureProtocols( const value : TSecureProtocols);
 
     function GetCustomHeaders: IThriftDictionary<string,string>;
     procedure SendRequest;
+
     property DnsResolveTimeout: Integer read GetDnsResolveTimeout write SetDnsResolveTimeout;
     property ConnectionTimeout: Integer read GetConnectionTimeout write SetConnectionTimeout;
     property SendTimeout: Integer read GetSendTimeout write SetSendTimeout;
@@ -173,6 +176,16 @@ begin
   FReadTimeout := Value;
 end;
 
+function TMsxmlHTTPClientImpl.GetSecureProtocols : TSecureProtocols;
+begin
+  Result := [];
+end;
+
+procedure TMsxmlHTTPClientImpl.SetSecureProtocols( const value : TSecureProtocols);
+begin
+  raise TTransportExceptionBadArgs.Create('SetSecureProtocols: Not supported with '+ClassName);
+end;
+
 function TMsxmlHTTPClientImpl.GetCustomHeaders: IThriftDictionary<string,string>;
 begin
   Result := FCustomHeaders;
diff --git a/lib/delphi/src/Thrift.Transport.WinHTTP.pas b/lib/delphi/src/Thrift.Transport.WinHTTP.pas
index aac2aea..8b4a7bc 100644
--- a/lib/delphi/src/Thrift.Transport.WinHTTP.pas
+++ b/lib/delphi/src/Thrift.Transport.WinHTTP.pas
@@ -46,8 +46,10 @@ type
     FSendTimeout : Integer;
     FReadTimeout : Integer;
     FCustomHeaders : IThriftDictionary<string,string>;
+    FSecureProtocols : TSecureProtocols;
 
     function CreateRequest: IWinHTTPRequest;
+    function SecureProtocolsAsWinHTTPFlags : Cardinal;
 
   private type
       THTTPResponseStream = class( TThriftStreamImpl)
@@ -82,9 +84,12 @@ type
     function GetSendTimeout: Integer;
     procedure SetReadTimeout(const Value: Integer);
     function GetReadTimeout: Integer;
+    function GetSecureProtocols : TSecureProtocols;
+    procedure SetSecureProtocols( const value : TSecureProtocols);
 
     function GetCustomHeaders: IThriftDictionary<string,string>;
     procedure SendRequest;
+
     property DnsResolveTimeout: Integer read GetDnsResolveTimeout write SetDnsResolveTimeout;
     property ConnectionTimeout: Integer read GetConnectionTimeout write SetConnectionTimeout;
     property SendTimeout: Integer read GetSendTimeout write SetSendTimeout;
@@ -111,6 +116,8 @@ begin
   FSendTimeout       := 30 * 1000;
   FReadTimeout       := 30 * 1000;
 
+  FSecureProtocols := DEFAULT_THRIFT_SECUREPROTOCOLS;
+
   FCustomHeaders := TThriftDictionaryImpl<string,string>.Create;
   FOutputMemoryStream := TMemoryStream.Create;
 end;
@@ -133,6 +140,8 @@ begin
   url := TWinHTTPUrlImpl.Create( FUri);
 
   session := TWinHTTPSessionImpl.Create('Apache Thrift Delphi Client');
+  session.EnableSecureProtocols( SecureProtocolsAsWinHTTPFlags);
+
   connect := session.Connect( url.HostName, url.Port);
 
   sPath   := url.UrlPath + url.ExtraInfo;
@@ -148,6 +157,29 @@ begin
   end;
 end;
 
+
+function TWinHTTPClientImpl.SecureProtocolsAsWinHTTPFlags : Cardinal;
+const
+  PROTOCOL_MAPPING : array[TSecureProtocol] of Cardinal = (
+    WINHTTP_FLAG_SECURE_PROTOCOL_SSL2,
+    WINHTTP_FLAG_SECURE_PROTOCOL_SSL3,
+    WINHTTP_FLAG_SECURE_PROTOCOL_TLS1,
+    WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_1,
+    WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2
+  );
+var
+  prot : TSecureProtocol;
+  protos : TSecureProtocols;
+begin
+  result := 0;
+  protos := GetSecureProtocols;
+  for prot := Low(TSecureProtocol) to High(TSecureProtocol) do begin
+    if prot in protos
+    then result := result or PROTOCOL_MAPPING[prot];
+  end;
+end;
+
+
 function TWinHTTPClientImpl.GetDnsResolveTimeout: Integer;
 begin
   Result := FDnsResolveTimeout;
@@ -188,6 +220,16 @@ begin
   FReadTimeout := Value;
 end;
 
+function TWinHTTPClientImpl.GetSecureProtocols : TSecureProtocols;
+begin
+  Result := FSecureProtocols;
+end;
+
+procedure TWinHTTPClientImpl.SetSecureProtocols( const value : TSecureProtocols);
+begin
+  FSecureProtocols := Value;
+end;
+
 function TWinHTTPClientImpl.GetCustomHeaders: IThriftDictionary<string,string>;
 begin
   Result := FCustomHeaders;
diff --git a/lib/delphi/src/Thrift.Transport.pas b/lib/delphi/src/Thrift.Transport.pas
index 1f8fdb0..c2071df 100644
--- a/lib/delphi/src/Thrift.Transport.pas
+++ b/lib/delphi/src/Thrift.Transport.pas
@@ -118,8 +118,15 @@ type
   TTransportExceptionBadArgs = class (TTransportExceptionSpecialized);
   TTransportExceptionInterrupted = class (TTransportExceptionSpecialized);
 
+  TSecureProtocol = (
+    SSL_2, SSL_3, TLS_1,   // outdated, for compatibilty only
+    TLS_1_1, TLS_1_2       // secure (as of today)
+  );
+
+  TSecureProtocols = set of TSecureProtocol;
+
   IHTTPClient = interface( ITransport )
-    ['{BA142D12-8AE6-4B50-9E33-6B7843B21D73}']
+    ['{7BF615DD-8680-4004-A5B2-88947BA3BA3D}']
     procedure SetDnsResolveTimeout(const Value: Integer);
     function GetDnsResolveTimeout: Integer;
     procedure SetConnectionTimeout(const Value: Integer);
@@ -130,12 +137,15 @@ type
     function GetReadTimeout: Integer;
     function GetCustomHeaders: IThriftDictionary<string,string>;
     procedure SendRequest;
+    function GetSecureProtocols : TSecureProtocols;
+    procedure SetSecureProtocols( const value : TSecureProtocols);
 
     property DnsResolveTimeout: Integer read GetDnsResolveTimeout write SetDnsResolveTimeout;
     property ConnectionTimeout: Integer read GetConnectionTimeout write SetConnectionTimeout;
     property SendTimeout: Integer read GetSendTimeout write SetSendTimeout;
     property ReadTimeout: Integer read GetReadTimeout write SetReadTimeout;
     property CustomHeaders: IThriftDictionary<string,string> read GetCustomHeaders;
+    property SecureProtocols : TSecureProtocols read GetSecureProtocols write SetSecureProtocols;
   end;
 
   IServerTransport = interface
@@ -373,6 +383,8 @@ procedure TFramedTransportImpl_Initialize;
 
 const
   DEFAULT_THRIFT_TIMEOUT = 5 * 1000; // ms
+  DEFAULT_THRIFT_SECUREPROTOCOLS = [ TSecureProtocol.TLS_1_1, TSecureProtocol.TLS_1_2];
+
 
 
 implementation
diff --git a/lib/delphi/src/Thrift.WinHTTP.pas b/lib/delphi/src/Thrift.WinHTTP.pas
index 6ad8400..4b98f69 100644
--- a/lib/delphi/src/Thrift.WinHTTP.pas
+++ b/lib/delphi/src/Thrift.WinHTTP.pas
@@ -84,6 +84,16 @@ function WinHttpOpenRequest( const hConnect : HINTERNET;
                              const dwFlags : DWORD
                              ) : HINTERNET;  stdcall;
 
+function WinHttpQueryOption( const hInternet : HINTERNET;
+                             const dwOption : DWORD;
+                             const pBuffer : Pointer;
+                             var dwBufferLength : DWORD) : BOOL;  stdcall;
+
+function WinHttpSetOption( const hInternet : HINTERNET;
+                           const dwOption : DWORD;
+                           const pBuffer : Pointer;
+                           const dwBufferLength : DWORD) : BOOL;  stdcall;
+
 function WinHttpSetTimeouts( const hRequestOrSession : HINTERNET;
                              const aResolveTimeout, aConnectTimeout, aSendTimeout, aReceiveTimeout : Int32
                              ) : BOOL;  stdcall;
@@ -193,6 +203,157 @@ const
   INTERNET_SCHEME_HTTP  = INTERNET_SCHEME(1);
   INTERNET_SCHEME_HTTPS = INTERNET_SCHEME(2);
 
+  WINHTTP_NO_CLIENT_CERT_CONTEXT = nil;
+
+  // options manifests for WinHttp{Query|Set}Option
+  WINHTTP_OPTION_CALLBACK = 1;
+  WINHTTP_OPTION_RESOLVE_TIMEOUT = 2;
+  WINHTTP_OPTION_CONNECT_TIMEOUT = 3;
+  WINHTTP_OPTION_CONNECT_RETRIES = 4;
+  WINHTTP_OPTION_SEND_TIMEOUT = 5;
+  WINHTTP_OPTION_RECEIVE_TIMEOUT = 6;
+  WINHTTP_OPTION_RECEIVE_RESPONSE_TIMEOUT = 7;
+  WINHTTP_OPTION_HANDLE_TYPE = 9;
+  WINHTTP_OPTION_READ_BUFFER_SIZE = 12;
+  WINHTTP_OPTION_WRITE_BUFFER_SIZE = 13;
+  WINHTTP_OPTION_PARENT_HANDLE = 21;
+  WINHTTP_OPTION_EXTENDED_ERROR = 24;
+  WINHTTP_OPTION_SECURITY_FLAGS = 31;
+  WINHTTP_OPTION_SECURITY_CERTIFICATE_STRUCT = 32;
+  WINHTTP_OPTION_URL = 34;
+  WINHTTP_OPTION_SECURITY_KEY_BITNESS = 36;
+  WINHTTP_OPTION_PROXY = 38;
+  WINHTTP_OPTION_USER_AGENT = 41;
+  WINHTTP_OPTION_CONTEXT_VALUE = 45;
+  WINHTTP_OPTION_CLIENT_CERT_CONTEXT = 47;
+  WINHTTP_OPTION_REQUEST_PRIORITY = 58;
+  WINHTTP_OPTION_HTTP_VERSION = 59;
+  WINHTTP_OPTION_DISABLE_FEATURE = 63;
+  WINHTTP_OPTION_CODEPAGE = 68;
+  WINHTTP_OPTION_MAX_CONNS_PER_SERVER = 73;
+  WINHTTP_OPTION_MAX_CONNS_PER_1_0_SERVER = 74;
+  WINHTTP_OPTION_AUTOLOGON_POLICY = 77;
+  WINHTTP_OPTION_SERVER_CERT_CONTEXT = 78;
+  WINHTTP_OPTION_ENABLE_FEATURE = 79;
+  WINHTTP_OPTION_WORKER_THREAD_COUNT = 80;
+  WINHTTP_OPTION_PASSPORT_COBRANDING_TEXT = 81;
+  WINHTTP_OPTION_PASSPORT_COBRANDING_URL = 82;
+  WINHTTP_OPTION_CONFIGURE_PASSPORT_AUTH = 83;
+  WINHTTP_OPTION_SECURE_PROTOCOLS = 84;
+  WINHTTP_OPTION_ENABLETRACING = 85;
+  WINHTTP_OPTION_PASSPORT_SIGN_OUT = 86;
+  WINHTTP_OPTION_PASSPORT_RETURN_URL = 87;
+  WINHTTP_OPTION_REDIRECT_POLICY = 88;
+  WINHTTP_OPTION_MAX_HTTP_AUTOMATIC_REDIRECTS = 89;
+  WINHTTP_OPTION_MAX_HTTP_STATUS_CONTINUE = 90;
+  WINHTTP_OPTION_MAX_RESPONSE_HEADER_SIZE = 91;
+  WINHTTP_OPTION_MAX_RESPONSE_DRAIN_SIZE = 92;
+  WINHTTP_OPTION_CONNECTION_INFO = 93;
+  WINHTTP_OPTION_CLIENT_CERT_ISSUER_LIST = 94;
+  WINHTTP_OPTION_SPN = 96;
+  WINHTTP_OPTION_GLOBAL_PROXY_CREDS = 97;
+  WINHTTP_OPTION_GLOBAL_SERVER_CREDS = 98;
+  WINHTTP_OPTION_UNLOAD_NOTIFY_EVENT = 99;
+  WINHTTP_OPTION_REJECT_USERPWD_IN_URL = 100;
+  WINHTTP_OPTION_USE_GLOBAL_SERVER_CREDENTIALS = 101;
+  WINHTTP_OPTION_RECEIVE_PROXY_CONNECT_RESPONSE = 103;
+  WINHTTP_OPTION_IS_PROXY_CONNECT_RESPONSE = 104;
+  WINHTTP_OPTION_SERVER_SPN_USED = 106;
+  WINHTTP_OPTION_PROXY_SPN_USED = 107;
+  WINHTTP_OPTION_SERVER_CBT = 108;
+  //
+  WINHTTP_FIRST_OPTION = WINHTTP_OPTION_CALLBACK;
+  WINHTTP_LAST_OPTION = WINHTTP_OPTION_SERVER_CBT;
+
+  WINHTTP_OPTION_USERNAME = $1000;
+  WINHTTP_OPTION_PASSWORD = $1001;
+  WINHTTP_OPTION_PROXY_USERNAME = $1002;
+  WINHTTP_OPTION_PROXY_PASSWORD = $1003;
+
+  // manifest value for WINHTTP_OPTION_MAX_CONNS_PER_SERVER and WINHTTP_OPTION_MAX_CONNS_PER_1_0_SERVER
+  WINHTTP_CONNS_PER_SERVER_UNLIMITED    = $FFFFFFFF;
+
+  // values for WINHTTP_OPTION_AUTOLOGON_POLICY
+  WINHTTP_AUTOLOGON_SECURITY_LEVEL_MEDIUM  = 0;
+  WINHTTP_AUTOLOGON_SECURITY_LEVEL_LOW     = 1;
+  WINHTTP_AUTOLOGON_SECURITY_LEVEL_HIGH    = 2;
+
+  WINHTTP_AUTOLOGON_SECURITY_LEVEL_DEFAULT = WINHTTP_AUTOLOGON_SECURITY_LEVEL_MEDIUM;
+
+  // values for WINHTTP_OPTION_REDIRECT_POLICY
+  WINHTTP_OPTION_REDIRECT_POLICY_NEVER                  = 0;
+  WINHTTP_OPTION_REDIRECT_POLICY_DISALLOW_HTTPS_TO_HTTP = 1;
+  WINHTTP_OPTION_REDIRECT_POLICY_ALWAYS                 = 2;
+
+  WINHTTP_OPTION_REDIRECT_POLICY_LAST      = WINHTTP_OPTION_REDIRECT_POLICY_ALWAYS;
+  WINHTTP_OPTION_REDIRECT_POLICY_DEFAULT   = WINHTTP_OPTION_REDIRECT_POLICY_DISALLOW_HTTPS_TO_HTTP;
+
+  WINHTTP_DISABLE_PASSPORT_AUTH      = $00000000;
+  WINHTTP_ENABLE_PASSPORT_AUTH       = $10000000;
+  WINHTTP_DISABLE_PASSPORT_KEYRING   = $20000000;
+  WINHTTP_ENABLE_PASSPORT_KEYRING    = $40000000;
+
+  // values for WINHTTP_OPTION_DISABLE_FEATURE
+  WINHTTP_DISABLE_COOKIES            = $00000001;
+  WINHTTP_DISABLE_REDIRECTS          = $00000002;
+  WINHTTP_DISABLE_AUTHENTICATION     = $00000004;
+  WINHTTP_DISABLE_KEEP_ALIVE         = $00000008;
+
+  // values for WINHTTP_OPTION_ENABLE_FEATURE
+  WINHTTP_ENABLE_SSL_REVOCATION            = $00000001;
+  WINHTTP_ENABLE_SSL_REVERT_IMPERSONATION  = $00000002;
+
+  // values for WINHTTP_OPTION_SPN
+  WINHTTP_DISABLE_SPN_SERVER_PORT    = $00000000;
+  WINHTTP_ENABLE_SPN_SERVER_PORT     = $00000001;
+  WINHTTP_OPTION_SPN_MASK            = WINHTTP_ENABLE_SPN_SERVER_PORT;
+
+  // winhttp handle types
+  WINHTTP_HANDLE_TYPE_SESSION  = 1;
+  WINHTTP_HANDLE_TYPE_CONNECT  = 2;
+  WINHTTP_HANDLE_TYPE_REQUEST  = 3;
+
+  // values for auth schemes
+  WINHTTP_AUTH_SCHEME_BASIC      = $00000001;
+  WINHTTP_AUTH_SCHEME_NTLM       = $00000002;
+  WINHTTP_AUTH_SCHEME_PASSPORT   = $00000004;
+  WINHTTP_AUTH_SCHEME_DIGEST     = $00000008;
+  WINHTTP_AUTH_SCHEME_NEGOTIATE  = $00000010;
+
+  // WinHttp supported Authentication Targets
+  WINHTTP_AUTH_TARGET_SERVER     = $00000000;
+  WINHTTP_AUTH_TARGET_PROXY      = $00000001;
+
+  // values for WINHTTP_OPTION_SECURITY_FLAGS
+
+  // query only
+  SECURITY_FLAG_SECURE           = $00000001; // can query only
+  SECURITY_FLAG_STRENGTH_WEAK    = $10000000;
+  SECURITY_FLAG_STRENGTH_MEDIUM  = $40000000;
+  SECURITY_FLAG_STRENGTH_STRONG  = $20000000;
+
+  // Secure connection error status flags
+  WINHTTP_CALLBACK_STATUS_FLAG_CERT_REV_FAILED         = $00000001;
+  WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CERT            = $00000002;
+  WINHTTP_CALLBACK_STATUS_FLAG_CERT_REVOKED            = $00000004;
+  WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA              = $00000008;
+  WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID         = $00000010;
+  WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID       = $00000020;
+  WINHTTP_CALLBACK_STATUS_FLAG_CERT_WRONG_USAGE        = $00000040;
+  WINHTTP_CALLBACK_STATUS_FLAG_SECURITY_CHANNEL_ERROR  = $80000000;
+
+  WINHTTP_FLAG_SECURE_PROTOCOL_SSL2   = $00000008;
+  WINHTTP_FLAG_SECURE_PROTOCOL_SSL3   = $00000020;
+  WINHTTP_FLAG_SECURE_PROTOCOL_TLS1   = $00000080;
+  WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_1 = $00000200;
+  WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2 = $00000800;
+
+  // Note: SECURE_PROTOCOL_ALL does not include TLS1.1 and higher!
+  WINHTTP_FLAG_SECURE_PROTOCOL_ALL    = WINHTTP_FLAG_SECURE_PROTOCOL_SSL2
+                                     or WINHTTP_FLAG_SECURE_PROTOCOL_SSL3
+                                     or WINHTTP_FLAG_SECURE_PROTOCOL_TLS1;
+
+
 const
   WINHTTP_ERROR_BASE                      = 12000;
   ERROR_WINHTTP_OUT_OF_HANDLES            = WINHTTP_ERROR_BASE + 1;
@@ -254,6 +415,7 @@ const
                          or WINHTTP_FLAG_ESCAPE_DISABLE;
 
 
+
 type
   IWinHTTPRequest = interface
     ['{35C6D9D4-FDCE-42C6-B84C-9294E6FB904C}']
@@ -274,10 +436,11 @@ type
   end;
 
   IWinHTTPSession = interface
-    ['{B6F8BD98-0605-4A9E-B671-4CB191D74A5E}']
+    ['{261ADCB7-5465-4407-8840-468C17F009F0}']
     function  Handle : HINTERNET;
     function  Connect( const aHostName : UnicodeString; const aPort : INTERNET_PORT = INTERNET_DEFAULT_PORT) : IWinHTTPConnection;
     function  SetTimeouts( const aResolveTimeout, aConnectTimeout, aSendTimeout, aReceiveTimeout : Int32) : Boolean;
+    function  EnableSecureProtocols( const aFlagSet : DWORD) : Boolean;
   end;
 
   IWinHTTPUrl = interface
@@ -339,7 +502,7 @@ type
     // IWinHTTPSession
     function  Connect( const aHostName : UnicodeString; const aPort : INTERNET_PORT = INTERNET_DEFAULT_PORT) : IWinHTTPConnection;
     function  SetTimeouts( const aResolveTimeout, aConnectTimeout, aSendTimeout, aReceiveTimeout : Int32) : Boolean;
-
+    function  EnableSecureProtocols( const aFlagSet : DWORD) : Boolean;
   public
     constructor Create( const aAgent : UnicodeString;
                         const aAccessType : DWORD          = WINHTTP_ACCESS_TYPE_DEFAULT_PROXY;
@@ -444,6 +607,8 @@ function WinHttpConnect;  stdcall; external WINHTTP_DLL;
 function WinHttpOpenRequest; stdcall; external WINHTTP_DLL;
 function WinHttpSendRequest; stdcall; external WINHTTP_DLL;
 function WinHttpSetTimeouts; stdcall; external WINHTTP_DLL;
+function WinHttpQueryOption; stdcall; external WINHTTP_DLL;
+function WinHttpSetOption; stdcall; external WINHTTP_DLL;
 function WinHttpAddRequestHeaders; stdcall; external WINHTTP_DLL;
 function WinHttpWriteData; stdcall; external WINHTTP_DLL;
 function WinHttpReceiveResponse; stdcall; external WINHTTP_DLL;
@@ -521,6 +686,14 @@ begin
 end;
 
 
+function TWinHTTPSessionImpl.EnableSecureProtocols( const aFlagSet : DWORD) : Boolean;
+var dwSize : DWORD;
+begin
+  dwSize := SizeOf(aFlagSet);
+  result := WinHttpSetOption( Handle, WINHTTP_OPTION_SECURE_PROTOCOLS, @aFlagset, dwSize);
+end;
+
+
 { TWinHTTPConnectionImpl }
 
 constructor TWinHTTPConnectionImpl.Create( const aSession : IWinHTTPSession; const aHostName : UnicodeString; const aPort : INTERNET_PORT);
diff --git a/lib/delphi/test/TestClient.pas b/lib/delphi/test/TestClient.pas
index 55bf92b..ebda7c6 100644
--- a/lib/delphi/test/TestClient.pas
+++ b/lib/delphi/test/TestClient.pas
@@ -29,6 +29,8 @@ unit TestClient;
 {$DEFINE SupportsAsync}
 {$ifend}
 
+{$WARN SYMBOL_PLATFORM OFF}  // Win32Check
+
 interface
 
 uses
@@ -1354,6 +1356,7 @@ end;
 
 procedure TClientThread.InitializeProtocolTransportStack;
 var streamtrans : IStreamTransport;
+    canSSL : Boolean;
 const
   DEBUG_TIMEOUT   = 30 * 1000;
   RELEASE_TIMEOUT = DEFAULT_THRIFT_TIMEOUT;
@@ -1363,6 +1366,7 @@ begin
   // needed for HTTP clients as they utilize the MSXML COM components
   OleCheck( CoInitialize( nil));
 
+  canSSL := FALSE;
   case FSetup.endpoint of
     trns_Sockets: begin
       Console.WriteLine('Using sockets ('+FSetup.host+' port '+IntToStr(FSetup.port)+')');
@@ -1374,6 +1378,7 @@ begin
     trns_WinHttp: begin
       Console.WriteLine('Using HTTPClient');
       FTransport := InitializeHttpTransport( HTTP_TIMEOUTS);
+      canSSL := TRUE;
     end;
 
     trns_EvHttp: begin
@@ -1403,7 +1408,7 @@ begin
     FTransport := TBufferedTransportImpl.Create( streamtrans, 32);  // small buffer to test read()
   end;
 
-  if FSetup.useSSL then begin
+  if FSetup.useSSL and not canSSL then begin
     raise Exception.Create('SSL/TLS not implemented');
   end;
 


[thrift] 02/02: THRIFT-4882 Autodetect proxy settings with WinHTTP Client: Delphi Patch: Jens Geyer

Posted by je...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

jensg pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/thrift.git

commit 83ff75377706eee2033f8de0208be2a61de5fbc6
Author: Jens Geyer <je...@apache.org>
AuthorDate: Thu Jun 6 22:46:03 2019 +0200

    THRIFT-4882 Autodetect proxy settings with WinHTTP
    Client: Delphi
    Patch: Jens Geyer
---
 lib/delphi/src/Thrift.Transport.MsxmlHTTP.pas |   4 +-
 lib/delphi/src/Thrift.Transport.WinHTTP.pas   |  15 +-
 lib/delphi/src/Thrift.Utils.pas               |   3 +
 lib/delphi/src/Thrift.WinHTTP.pas             | 219 +++++++++++++++++++++++++-
 lib/delphi/test/TestClient.pas                |  26 ++-
 5 files changed, 253 insertions(+), 14 deletions(-)

diff --git a/lib/delphi/src/Thrift.Transport.MsxmlHTTP.pas b/lib/delphi/src/Thrift.Transport.MsxmlHTTP.pas
index 620beba..c666e7f 100644
--- a/lib/delphi/src/Thrift.Transport.MsxmlHTTP.pas
+++ b/lib/delphi/src/Thrift.Transport.MsxmlHTTP.pas
@@ -121,8 +121,8 @@ begin
   then srvHttp.setTimeouts( DnsResolveTimeout, ConnectionTimeout, SendTimeout, ReadTimeout);
 
   Result.open('POST', FUri, False, '', '');
-  Result.setRequestHeader( 'Content-Type', 'application/x-thrift');
-  Result.setRequestHeader( 'Accept', 'application/x-thrift');
+  Result.setRequestHeader( 'Content-Type', THRIFT_MIMETYPE);
+  Result.setRequestHeader( 'Accept', THRIFT_MIMETYPE);
   Result.setRequestHeader( 'User-Agent', 'Delphi/IHTTPClient');
 
   for pair in FCustomHeaders do begin
diff --git a/lib/delphi/src/Thrift.Transport.WinHTTP.pas b/lib/delphi/src/Thrift.Transport.WinHTTP.pas
index 8b4a7bc..48b74a6 100644
--- a/lib/delphi/src/Thrift.Transport.WinHTTP.pas
+++ b/lib/delphi/src/Thrift.Transport.WinHTTP.pas
@@ -139,22 +139,25 @@ var
 begin
   url := TWinHTTPUrlImpl.Create( FUri);
 
-  session := TWinHTTPSessionImpl.Create('Apache Thrift Delphi Client');
+  session := TWinHTTPSessionImpl.Create('Apache Thrift Delphi WinHTTP');
   session.EnableSecureProtocols( SecureProtocolsAsWinHTTPFlags);
 
   connect := session.Connect( url.HostName, url.Port);
 
   sPath   := url.UrlPath + url.ExtraInfo;
-  result  := connect.OpenRequest( (url.Scheme = 'https'), 'POST', sPath, 'application/x-thrift');
+  result  := connect.OpenRequest( (url.Scheme = 'https'), 'POST', sPath, THRIFT_MIMETYPE);
 
   // setting a timeout value to 0 (zero) means "no timeout" for that setting
   result.SetTimeouts( DnsResolveTimeout, ConnectionTimeout, SendTimeout, ReadTimeout);
 
-  result.AddRequestHeader( 'Content-Type: application/x-thrift', WINHTTP_ADDREQ_FLAG_ADD);
-
+  // headers
+  result.AddRequestHeader( 'Content-Type: '+THRIFT_MIMETYPE, WINHTTP_ADDREQ_FLAG_ADD);
   for pair in FCustomHeaders do begin
     Result.AddRequestHeader( pair.Key +': '+ pair.Value, WINHTTP_ADDREQ_FLAG_ADD);
   end;
+
+  // AutoProxy support
+  result.TryAutoProxy( FUri);
 end;
 
 
@@ -290,11 +293,11 @@ begin
 
   // send all data immediately, since we have it in memory
   if not http.SendRequest( pData, len, 0)
-  then raise TTransportExceptionUnknown.Create('send request error');
+  then raise TTransportExceptionUnknown.Create('send request error '+IntToStr(GetLastError));
 
   // end request and start receiving
   if not http.FlushAndReceiveResponse
-  then raise TTransportExceptionInterrupted.Create('flush/receive error');
+  then raise TTransportExceptionInterrupted.Create('flush/receive error '+IntToStr(GetLastError));
 
   FInputStream := THTTPResponseStream.Create(http);
 end;
diff --git a/lib/delphi/src/Thrift.Utils.pas b/lib/delphi/src/Thrift.Utils.pas
index 11c4f3e..ede2656 100644
--- a/lib/delphi/src/Thrift.Utils.pas
+++ b/lib/delphi/src/Thrift.Utils.pas
@@ -93,6 +93,9 @@ type
   end;
 
 
+const
+  THRIFT_MIMETYPE = 'application/x-thrift';
+
 {$IFDEF Win64}
 function InterlockedExchangeAdd64( var Addend : Int64; Value : Int64) : Int64;  
 {$ENDIF}
diff --git a/lib/delphi/src/Thrift.WinHTTP.pas b/lib/delphi/src/Thrift.WinHTTP.pas
index 4b98f69..b26f6ba 100644
--- a/lib/delphi/src/Thrift.WinHTTP.pas
+++ b/lib/delphi/src/Thrift.WinHTTP.pas
@@ -63,6 +63,40 @@ type
   LPURL_COMPONENTSW = LPURL_COMPONENTS;
 
 
+  // When retrieving proxy data, an application must free the lpszProxy and
+  // lpszProxyBypass strings contained in this structure (if they are non-NULL)
+  // using the GlobalFree function.
+  LPWINHTTP_PROXY_INFO = ^WINHTTP_PROXY_INFO;
+  WINHTTP_PROXY_INFO = record
+    dwAccessType    : DWORD;      // see WINHTTP_ACCESS_* types below
+    lpszProxy       : LPWSTR;     // proxy server list
+    lpszProxyBypass : LPWSTR;     // proxy bypass list
+  end;
+
+  LPWINHTTP_PROXY_INFOW = ^WINHTTP_PROXY_INFOW;
+  WINHTTP_PROXY_INFOW   = WINHTTP_PROXY_INFO;
+
+
+  WINHTTP_AUTOPROXY_OPTIONS = record
+    dwFlags                : DWORD;
+    dwAutoDetectFlags      : DWORD;
+    lpszAutoConfigUrl      : LPCWSTR;
+    lpvReserved            : LPVOID;
+    dwReserved             : DWORD;
+    fAutoLogonIfChallenged : BOOL;
+  end;
+
+
+  WINHTTP_CURRENT_USER_IE_PROXY_CONFIG = record
+    fAutoDetect       : BOOL;
+    lpszAutoConfigUrl : LPWSTR;
+    lpszProxy         : LPWSTR;
+    lpszProxyBypass   : LPWSTR;
+  end;
+
+
+
+
 function WinHttpCloseHandle( aHandle : HINTERNET) : BOOL;  stdcall;
 
 function WinHttpOpen( const pszAgentW       : LPCWSTR;
@@ -104,6 +138,16 @@ function WinHttpAddRequestHeaders( const hRequest : HINTERNET;
                                    const dwModifiers : DWORD
                                    ) : BOOL;  stdcall;
 
+function WinHttpGetProxyForUrl( const hSession  : HINTERNET;
+                                const lpcwszUrl : LPCWSTR;
+                                const options   : WINHTTP_AUTOPROXY_OPTIONS;
+                                const info      : WINHTTP_PROXY_INFO
+                                ) : BOOL;  stdcall;
+
+function WinHttpGetIEProxyConfigForCurrentUser( var config : WINHTTP_CURRENT_USER_IE_PROXY_CONFIG
+                                                ) : BOOL;  stdcall;
+
+
 function WinHttpSendRequest( const hRequest : HINTERNET;
                              const lpszHeaders : LPCWSTR;
                              const dwHeadersLength : DWORD;
@@ -353,6 +397,17 @@ const
                                      or WINHTTP_FLAG_SECURE_PROTOCOL_SSL3
                                      or WINHTTP_FLAG_SECURE_PROTOCOL_TLS1;
 
+  // AutoProxy
+  WINHTTP_AUTOPROXY_AUTO_DETECT           = $00000001;
+  WINHTTP_AUTOPROXY_CONFIG_URL            = $00000002;
+  WINHTTP_AUTOPROXY_HOST_KEEPCASE         = $00000004;
+  WINHTTP_AUTOPROXY_HOST_LOWERCASE        = $00000008;
+  WINHTTP_AUTOPROXY_RUN_INPROCESS         = $00010000;
+  WINHTTP_AUTOPROXY_RUN_OUTPROCESS_ONLY   = $00020000;
+
+  // Flags for dwAutoDetectFlags
+  WINHTTP_AUTO_DETECT_TYPE_DHCP           = $00000001;
+  WINHTTP_AUTO_DETECT_TYPE_DNS_A          = $00000002;
 
 const
   WINHTTP_ERROR_BASE                      = 12000;
@@ -417,11 +472,16 @@ const
 
 
 type
+  IWinHTTPSession = interface;
+  IWinHTTPConnection = interface;
+
   IWinHTTPRequest = interface
-    ['{35C6D9D4-FDCE-42C6-B84C-9294E6FB904C}']
+    ['{0B7D095E-BB3D-4444-8686-5536E7D6437B}']
     function  Handle : HINTERNET;
+    function  Connection : IWinHTTPConnection;
     function  AddRequestHeader( const aHeader : string; const addflag : DWORD = WINHTTP_ADDREQ_FLAG_ADD) : Boolean;
     function  SetTimeouts( const aResolveTimeout, aConnectTimeout, aSendTimeout, aReceiveTimeout : Int32) : Boolean;
+    procedure TryAutoProxy( const aUrl : string);
     function  SendRequest( const pBuf : Pointer; const dwBytes : DWORD; const dwExtra : DWORD = 0) : Boolean;
     function  WriteExtraData( const pBuf : Pointer; const dwBytes : DWORD) : DWORD;
     function  FlushAndReceiveResponse : Boolean;
@@ -430,8 +490,9 @@ type
   end;
 
   IWinHTTPConnection = interface
-    ['{1C4F78B5-1525-4788-B638-A0E41BCF4D43}']
+    ['{ED5BCA49-84D6-4CFE-BF18-3238B1FF2AFB}']
     function  Handle : HINTERNET;
+    function  Session : IWinHTTPSession;
     function  OpenRequest( const secure : Boolean; const aVerb, aObjName, aAcceptTypes : UnicodeString) : IWinHTTPRequest;
   end;
 
@@ -519,6 +580,7 @@ type
 
     // IWinHTTPConnection
     function  OpenRequest( const secure : Boolean; const aVerb, aObjName, aAcceptTypes : UnicodeString) : IWinHTTPRequest;
+    function  Session : IWinHTTPSession;
 
   public
     constructor Create( const aSession : IWinHTTPSession; const aHostName : UnicodeString; const aPort : INTERNET_PORT);
@@ -533,8 +595,10 @@ type
     FConnection : IWinHTTPConnection;
 
     // IWinHTTPRequest
+    function  Connection : IWinHTTPConnection;
     function  AddRequestHeader( const aHeader : string; const addflag : DWORD = WINHTTP_ADDREQ_FLAG_ADD) : Boolean;
     function  SetTimeouts( const aResolveTimeout, aConnectTimeout, aSendTimeout, aReceiveTimeout : Int32) : Boolean;
+    procedure TryAutoProxy( const aUrl : string);
     function  SendRequest( const pBuf : Pointer; const dwBytes : DWORD; const dwExtra : DWORD = 0) : Boolean;
     function  WriteExtraData( const pBuf : Pointer; const dwBytes : DWORD) : DWORD;
     function  FlushAndReceiveResponse : Boolean;
@@ -595,6 +659,18 @@ type
   end;
 
 
+  WINHTTP_PROXY_INFO_Helper = record helper for WINHTTP_PROXY_INFO
+    procedure Initialize;
+    procedure FreeAllocatedResources;
+  end;
+
+
+  WINHTTP_CURRENT_USER_IE_PROXY_CONFIG_Helper = record helper for WINHTTP_CURRENT_USER_IE_PROXY_CONFIG
+    procedure Initialize;
+    procedure FreeAllocatedResources;
+  end;
+
+
   EWinHTTPException = class(Exception);
 
 implementation
@@ -610,6 +686,8 @@ function WinHttpSetTimeouts; stdcall; external WINHTTP_DLL;
 function WinHttpQueryOption; stdcall; external WINHTTP_DLL;
 function WinHttpSetOption; stdcall; external WINHTTP_DLL;
 function WinHttpAddRequestHeaders; stdcall; external WINHTTP_DLL;
+function WinHttpGetProxyForUrl; stdcall; external WINHTTP_DLL;
+function WinHttpGetIEProxyConfigForCurrentUser; stdcall; external WINHTTP_DLL;
 function WinHttpWriteData; stdcall; external WINHTTP_DLL;
 function WinHttpReceiveResponse; stdcall; external WINHTTP_DLL;
 function WinHttpQueryHeaders; stdcall; external WINHTTP_DLL;
@@ -619,6 +697,51 @@ function WinHttpCrackUrl; stdcall; external WINHTTP_DLL;
 function WinHttpCreateUrl; stdcall; external WINHTTP_DLL;
 
 
+{ misc. record helper }
+
+
+procedure GlobalFreeAndNil( var p : LPWSTR);
+begin
+  if p <> nil then begin
+    GlobalFree( HGLOBAL( p));
+    p := nil;
+  end;
+end;
+
+
+procedure WINHTTP_PROXY_INFO_Helper.Initialize;
+begin
+  FillChar( Self, SizeOf(Self), 0);
+end;
+
+
+procedure WINHTTP_PROXY_INFO_Helper.FreeAllocatedResources;
+// The caller must free the lpszProxy and lpszProxyBypass strings
+// if they are non-NULL. Use GlobalFree to free the strings.
+begin
+  GlobalFreeAndNil( lpszProxy);
+  GlobalFreeAndNil( lpszProxyBypass);
+  Initialize;
+end;
+
+
+procedure WINHTTP_CURRENT_USER_IE_PROXY_CONFIG_Helper.Initialize;
+begin
+  FillChar( Self, SizeOf(Self), 0);
+end;
+
+
+procedure WINHTTP_CURRENT_USER_IE_PROXY_CONFIG_Helper.FreeAllocatedResources;
+// The caller must free the lpszProxy, lpszProxyBypass and lpszAutoConfigUrl strings
+// if they are non-NULL. Use GlobalFree to free the strings.
+begin
+  GlobalFreeAndNil( lpszProxy);
+  GlobalFreeAndNil( lpszProxyBypass);
+  GlobalFreeAndNil( lpszAutoConfigUrl);
+  Initialize;
+end;
+
+
 { TWinHTTPHandleObjectImpl }
 
 constructor TWinHTTPHandleObjectImpl.Create( const aHandle : HINTERNET);
@@ -713,6 +836,12 @@ begin
 end;
 
 
+function TWinHTTPConnectionImpl.Session : IWinHTTPSession;
+begin
+  result := FSession;
+end;
+
+
 function TWinHTTPConnectionImpl.OpenRequest( const secure : Boolean; const aVerb, aObjName, aAcceptTypes : UnicodeString) : IWinHTTPRequest;
 var dwFlags : DWORD;
 begin
@@ -759,6 +888,12 @@ begin
 end;
 
 
+function TWinHTTPRequestImpl.Connection : IWinHTTPConnection;
+begin
+  result := FConnection;
+end;
+
+
 function TWinHTTPRequestImpl.SetTimeouts( const aResolveTimeout, aConnectTimeout, aSendTimeout, aReceiveTimeout : Int32) : Boolean;
 begin
   result := WinHttpSetTimeouts( FHandle, aResolveTimeout, aConnectTimeout, aSendTimeout, aReceiveTimeout);
@@ -771,6 +906,85 @@ begin
 end;
 
 
+procedure TWinHTTPRequestImpl.TryAutoProxy( const aUrl : string);
+// From MSDN:
+//    AutoProxy support is not fully integrated into the HTTP stack in WinHTTP.
+//    Before sending a request, the application must call WinHttpGetProxyForUrl
+//    to obtain the name of a proxy server and then call WinHttpSetOption using
+//    WINHTTP_OPTION_PROXY to set the proxy configuration on the WinHTTP request
+//    handle created by WinHttpOpenRequest.
+//    See https://docs.microsoft.com/en-us/windows/desktop/winhttp/winhttp-autoproxy-api
+var
+  options : WINHTTP_AUTOPROXY_OPTIONS;
+  proxy   : WINHTTP_PROXY_INFO;
+  ieProxy : WINHTTP_CURRENT_USER_IE_PROXY_CONFIG;
+  dwSize  : DWORD;
+begin
+  // try AutoProxy via PAC first
+  proxy.Initialize;
+  try
+    FillChar( options, SizeOf(options), 0);
+    options.dwFlags                := WINHTTP_AUTOPROXY_AUTO_DETECT;
+    options.dwAutoDetectFlags      := WINHTTP_AUTO_DETECT_TYPE_DHCP or WINHTTP_AUTO_DETECT_TYPE_DNS_A;
+    options.fAutoLogonIfChallenged := TRUE;
+    if WinHttpGetProxyForUrl( FConnection.Session.Handle, PChar(aUrl), options, proxy) then begin
+      dwSize  := SizeOf(proxy);
+      WinHttpSetOption( Handle, WINHTTP_OPTION_PROXY, @proxy, dwSize);
+      Exit;
+    end;
+
+  finally
+    proxy.FreeAllocatedResources;
+  end;
+
+  // Use IE settings as a fallback, useful in client (i.e. non-server) environments
+  ieProxy.Initialize;
+  try
+    if WinHttpGetIEProxyConfigForCurrentUser( ieProxy)
+    then begin
+
+      // lpszAutoConfigUrl = "Use automatic proxy configuration"
+      if ieProxy.lpszAutoConfigUrl <> nil then begin
+        options.lpszAutoConfigUrl := ieProxy.lpszAutoConfigUrl;
+        options.dwFlags := options.dwFlags or WINHTTP_AUTOPROXY_CONFIG_URL;
+
+        proxy.Initialize;
+        try
+          if WinHttpGetProxyForUrl( FConnection.Session.Handle, PChar(aUrl), options, proxy) then begin
+            dwSize := SizeOf(proxy);
+            WinHttpSetOption( Handle, WINHTTP_OPTION_PROXY, @proxy, dwSize);
+            Exit;
+          end;
+        finally
+          proxy.FreeAllocatedResources;
+        end;
+      end;
+
+      // lpszProxy = "use a proxy server"
+      if ieProxy.lpszProxy <> nil then begin
+        proxy.Initialize;
+        try
+          proxy.dwAccessType    := WINHTTP_ACCESS_TYPE_NAMED_PROXY;
+          proxy.lpszProxy       := ieProxy.lpszProxy;
+          proxy.lpszProxyBypass := ieProxy.lpszProxyBypass;
+          dwSize := SizeOf(proxy);
+          WinHttpSetOption( Handle, WINHTTP_OPTION_PROXY, @proxy, dwSize);
+          Exit;
+        finally
+          proxy.Initialize; // not FreeAllocatedResources, we only hold pointer copies!
+        end;
+      end;
+
+    end;
+
+  finally
+    ieProxy.FreeAllocatedResources;
+  end;
+end;
+
+
+
+
 function TWinHTTPRequestImpl.SendRequest( const pBuf : Pointer; const dwBytes, dwExtra : DWORD) : Boolean;
 begin
   result := WinHttpSendRequest( FHandle,
@@ -979,3 +1193,4 @@ end;
 
 end.
 
+
diff --git a/lib/delphi/test/TestClient.pas b/lib/delphi/test/TestClient.pas
index ebda7c6..677d416 100644
--- a/lib/delphi/test/TestClient.pas
+++ b/lib/delphi/test/TestClient.pas
@@ -50,6 +50,7 @@ uses
   Thrift.Transport,
   Thrift.Stream,
   Thrift.Test,
+  Thrift.WinHTTP,
   Thrift.Utils,
   Thrift.Collections;
 
@@ -1322,7 +1323,9 @@ end;
 
 
 function TClientThread.InitializeHttpTransport( const aTimeoutSetting : Integer) : IHTTPClient;
-var sUrl : string;
+var sUrl    : string;
+    comps   : URL_COMPONENTS;
+    dwChars : DWORD;
 begin
   ASSERT( FSetup.endpoint in [trns_MsxmlHttp, trns_WinHttp]);
 
@@ -1332,12 +1335,27 @@ begin
 
   sUrl := sUrl + FSetup.host;
 
+  // add the port number if necessary and at the right place
+  FillChar( comps, SizeOf(comps), 0);
+  comps.dwStructSize := SizeOf(comps);
+  comps.dwSchemeLength    := MAXINT;
+  comps.dwHostNameLength  := MAXINT;
+  comps.dwUserNameLength  := MAXINT;
+  comps.dwPasswordLength  := MAXINT;
+  comps.dwUrlPathLength   := MAXINT;
+  comps.dwExtraInfoLength := MAXINT;
+  Win32Check( WinHttpCrackUrl( PChar(sUrl), Length(sUrl), 0, comps));
   case FSetup.port of
-    80  : if FSetup.useSSL then sUrl := sUrl + ':'+ IntToStr(FSetup.port);
-    443 : if not FSetup.useSSL then sUrl := sUrl + ':'+ IntToStr(FSetup.port);
+    80  : if FSetup.useSSL then comps.nPort := FSetup.port;
+    443 : if not FSetup.useSSL then comps.nPort := FSetup.port;
   else
-    if FSetup.port > 0 then sUrl := sUrl + ':'+ IntToStr(FSetup.port);
+    if FSetup.port > 0 then comps.nPort := FSetup.port;
   end;
+  dwChars := Length(sUrl) + 64;
+  SetLength( sUrl, dwChars);
+  Win32Check( WinHttpCreateUrl( comps, 0, @sUrl[1], dwChars));
+  SetLength( sUrl, dwChars);
+
 
   Console.WriteLine('Target URL: '+sUrl);
   case FSetup.endpoint of