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