THRIFT-4841 THTTPTransport relies on activeX component
Client: Delphi
Patch: Jens Geyer
This closes #1778
diff --git a/lib/delphi/src/Thrift.Transport.MsxmlHTTP.pas b/lib/delphi/src/Thrift.Transport.MsxmlHTTP.pas
new file mode 100644
index 0000000..cdfb541
--- /dev/null
+++ b/lib/delphi/src/Thrift.Transport.MsxmlHTTP.pas
@@ -0,0 +1,255 @@
+(*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *)
+unit Thrift.Transport.MsxmlHTTP;
+
+{$I Thrift.Defines.inc}
+{$SCOPEDENUMS ON}
+
+interface
+
+uses
+ Classes,
+ SysUtils,
+ Math,
+ Generics.Collections,
+ {$IFDEF OLD_UNIT_NAMES}
+ ActiveX, msxml,
+ {$ELSE}
+ Winapi.ActiveX, Winapi.msxml,
+ {$ENDIF}
+ Thrift.Collections,
+ Thrift.Transport,
+ Thrift.Exception,
+ Thrift.Utils,
+ Thrift.Stream;
+
+type
+ TMsxmlHTTPClientImpl = class( TTransportImpl, IHTTPClient)
+ private
+ FUri : string;
+ FInputStream : IThriftStream;
+ FOutputStream : IThriftStream;
+ FDnsResolveTimeout : Integer;
+ FConnectionTimeout : Integer;
+ FSendTimeout : Integer;
+ FReadTimeout : Integer;
+ FCustomHeaders : IThriftDictionary<string,string>;
+
+ function CreateRequest: IXMLHTTPRequest;
+ protected
+ function GetIsOpen: Boolean; override;
+ procedure Open(); override;
+ procedure Close(); override;
+ function Read( const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer; override;
+ procedure Write( const pBuf : Pointer; off, len : Integer); override;
+ procedure Flush; override;
+
+ procedure SetDnsResolveTimeout(const Value: Integer);
+ function GetDnsResolveTimeout: Integer;
+ procedure SetConnectionTimeout(const Value: Integer);
+ function GetConnectionTimeout: Integer;
+ procedure SetSendTimeout(const Value: Integer);
+ function GetSendTimeout: Integer;
+ procedure SetReadTimeout(const Value: Integer);
+ function GetReadTimeout: Integer;
+
+ 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;
+ property ReadTimeout: Integer read GetReadTimeout write SetReadTimeout;
+ property CustomHeaders: IThriftDictionary<string,string> read GetCustomHeaders;
+ public
+ constructor Create( const AUri: string);
+ destructor Destroy; override;
+ end;
+
+
+implementation
+
+
+{ TMsxmlHTTPClientImpl }
+
+constructor TMsxmlHTTPClientImpl.Create(const AUri: string);
+begin
+ inherited Create;
+ FUri := AUri;
+
+ // defaults according to MSDN
+ FDnsResolveTimeout := 0; // no timeout
+ FConnectionTimeout := 60 * 1000;
+ FSendTimeout := 30 * 1000;
+ FReadTimeout := 30 * 1000;
+
+ FCustomHeaders := TThriftDictionaryImpl<string,string>.Create;
+ FOutputStream := TThriftStreamAdapterDelphi.Create( TMemoryStream.Create, True);
+end;
+
+function TMsxmlHTTPClientImpl.CreateRequest: IXMLHTTPRequest;
+var
+ pair : TPair<string,string>;
+ srvHttp : IServerXMLHTTPRequest;
+begin
+ {$IF CompilerVersion >= 21.0}
+ Result := CoServerXMLHTTP.Create;
+ {$ELSE}
+ Result := CoXMLHTTPRequest.Create;
+ {$IFEND}
+
+ // setting a timeout value to 0 (zero) means "no timeout" for that setting
+ if Supports( result, IServerXMLHTTPRequest, srvHttp)
+ 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( 'User-Agent', 'Delphi/IHTTPClient');
+
+ for pair in FCustomHeaders do begin
+ Result.setRequestHeader( pair.Key, pair.Value );
+ end;
+end;
+
+destructor TMsxmlHTTPClientImpl.Destroy;
+begin
+ Close;
+ inherited;
+end;
+
+function TMsxmlHTTPClientImpl.GetDnsResolveTimeout: Integer;
+begin
+ Result := FDnsResolveTimeout;
+end;
+
+procedure TMsxmlHTTPClientImpl.SetDnsResolveTimeout(const Value: Integer);
+begin
+ FDnsResolveTimeout := Value;
+end;
+
+function TMsxmlHTTPClientImpl.GetConnectionTimeout: Integer;
+begin
+ Result := FConnectionTimeout;
+end;
+
+procedure TMsxmlHTTPClientImpl.SetConnectionTimeout(const Value: Integer);
+begin
+ FConnectionTimeout := Value;
+end;
+
+function TMsxmlHTTPClientImpl.GetSendTimeout: Integer;
+begin
+ Result := FSendTimeout;
+end;
+
+procedure TMsxmlHTTPClientImpl.SetSendTimeout(const Value: Integer);
+begin
+ FSendTimeout := Value;
+end;
+
+function TMsxmlHTTPClientImpl.GetReadTimeout: Integer;
+begin
+ Result := FReadTimeout;
+end;
+
+procedure TMsxmlHTTPClientImpl.SetReadTimeout(const Value: Integer);
+begin
+ FReadTimeout := Value;
+end;
+
+function TMsxmlHTTPClientImpl.GetCustomHeaders: IThriftDictionary<string,string>;
+begin
+ Result := FCustomHeaders;
+end;
+
+function TMsxmlHTTPClientImpl.GetIsOpen: Boolean;
+begin
+ Result := True;
+end;
+
+procedure TMsxmlHTTPClientImpl.Open;
+begin
+ FOutputStream := TThriftStreamAdapterDelphi.Create( TMemoryStream.Create, True);
+end;
+
+procedure TMsxmlHTTPClientImpl.Close;
+begin
+ FInputStream := nil;
+ FOutputStream := nil;
+end;
+
+procedure TMsxmlHTTPClientImpl.Flush;
+begin
+ try
+ SendRequest;
+ finally
+ FOutputStream := nil;
+ FOutputStream := TThriftStreamAdapterDelphi.Create( TMemoryStream.Create, True);
+ ASSERT( FOutputStream <> nil);
+ end;
+end;
+
+function TMsxmlHTTPClientImpl.Read( const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer;
+begin
+ if FInputStream = nil then begin
+ raise TTransportExceptionNotOpen.Create('No request has been sent');
+ end;
+
+ try
+ Result := FInputStream.Read( pBuf, buflen, off, len)
+ except
+ on E: Exception
+ do raise TTransportExceptionUnknown.Create(E.Message);
+ end;
+end;
+
+procedure TMsxmlHTTPClientImpl.SendRequest;
+var
+ xmlhttp : IXMLHTTPRequest;
+ ms : TMemoryStream;
+ a : TBytes;
+ len : Integer;
+begin
+ xmlhttp := CreateRequest;
+
+ ms := TMemoryStream.Create;
+ try
+ a := FOutputStream.ToArray;
+ len := Length(a);
+ if len > 0 then begin
+ ms.WriteBuffer( Pointer(@a[0])^, len);
+ end;
+ ms.Position := 0;
+ xmlhttp.send( IUnknown( TStreamAdapter.Create( ms, soReference )));
+ FInputStream := nil;
+ FInputStream := TThriftStreamAdapterCOM.Create( IUnknown( xmlhttp.responseStream) as IStream);
+ finally
+ ms.Free;
+ end;
+end;
+
+procedure TMsxmlHTTPClientImpl.Write( const pBuf : Pointer; off, len : Integer);
+begin
+ FOutputStream.Write( pBuf, off, len);
+end;
+
+
+
+end.
+
diff --git a/lib/delphi/src/Thrift.Transport.WinHTTP.pas b/lib/delphi/src/Thrift.Transport.WinHTTP.pas
new file mode 100644
index 0000000..aac2aea
--- /dev/null
+++ b/lib/delphi/src/Thrift.Transport.WinHTTP.pas
@@ -0,0 +1,335 @@
+(*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *)
+unit Thrift.Transport.WinHTTP;
+
+{$I Thrift.Defines.inc}
+{$SCOPEDENUMS ON}
+
+interface
+
+uses
+ Classes,
+ SysUtils,
+ Math,
+ Generics.Collections,
+ Thrift.Collections,
+ Thrift.Transport,
+ Thrift.Exception,
+ Thrift.Utils,
+ Thrift.WinHTTP,
+ Thrift.Stream;
+
+type
+ TWinHTTPClientImpl = class( TTransportImpl, IHTTPClient)
+ private
+ FUri : string;
+ FInputStream : IThriftStream;
+ FOutputMemoryStream : TMemoryStream;
+ FDnsResolveTimeout : Integer;
+ FConnectionTimeout : Integer;
+ FSendTimeout : Integer;
+ FReadTimeout : Integer;
+ FCustomHeaders : IThriftDictionary<string,string>;
+
+ function CreateRequest: IWinHTTPRequest;
+
+ private type
+ THTTPResponseStream = class( TThriftStreamImpl)
+ private
+ FRequest : IWinHTTPRequest;
+ protected
+ procedure Write( const pBuf : Pointer; offset: Integer; count: Integer); override;
+ function Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer; override;
+ procedure Open; override;
+ procedure Close; override;
+ procedure Flush; override;
+ function IsOpen: Boolean; override;
+ function ToArray: TBytes; override;
+ public
+ constructor Create( const aRequest : IWinHTTPRequest);
+ destructor Destroy; override;
+ end;
+
+ protected
+ function GetIsOpen: Boolean; override;
+ procedure Open(); override;
+ procedure Close(); override;
+ function Read( const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer; override;
+ procedure Write( const pBuf : Pointer; off, len : Integer); override;
+ procedure Flush; override;
+
+ procedure SetDnsResolveTimeout(const Value: Integer);
+ function GetDnsResolveTimeout: Integer;
+ procedure SetConnectionTimeout(const Value: Integer);
+ function GetConnectionTimeout: Integer;
+ procedure SetSendTimeout(const Value: Integer);
+ function GetSendTimeout: Integer;
+ procedure SetReadTimeout(const Value: Integer);
+ function GetReadTimeout: Integer;
+
+ 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;
+ property ReadTimeout: Integer read GetReadTimeout write SetReadTimeout;
+ property CustomHeaders: IThriftDictionary<string,string> read GetCustomHeaders;
+ public
+ constructor Create( const AUri: string);
+ destructor Destroy; override;
+ end;
+
+implementation
+
+
+{ TWinHTTPClientImpl }
+
+constructor TWinHTTPClientImpl.Create(const AUri: string);
+begin
+ inherited Create;
+ FUri := AUri;
+
+ // defaults according to MSDN
+ FDnsResolveTimeout := 0; // no timeout
+ FConnectionTimeout := 60 * 1000;
+ FSendTimeout := 30 * 1000;
+ FReadTimeout := 30 * 1000;
+
+ FCustomHeaders := TThriftDictionaryImpl<string,string>.Create;
+ FOutputMemoryStream := TMemoryStream.Create;
+end;
+
+destructor TWinHTTPClientImpl.Destroy;
+begin
+ Close;
+ FreeAndNil( FOutputMemoryStream);
+ inherited;
+end;
+
+function TWinHTTPClientImpl.CreateRequest: IWinHTTPRequest;
+var
+ pair : TPair<string,string>;
+ session : IWinHTTPSession;
+ connect : IWinHTTPConnection;
+ url : IWinHTTPUrl;
+ sPath : string;
+begin
+ url := TWinHTTPUrlImpl.Create( FUri);
+
+ session := TWinHTTPSessionImpl.Create('Apache Thrift Delphi Client');
+ connect := session.Connect( url.HostName, url.Port);
+
+ sPath := url.UrlPath + url.ExtraInfo;
+ result := connect.OpenRequest( (url.Scheme = 'https'), 'POST', sPath, 'application/x-thrift');
+
+ // 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);
+
+ for pair in FCustomHeaders do begin
+ Result.AddRequestHeader( pair.Key +': '+ pair.Value, WINHTTP_ADDREQ_FLAG_ADD);
+ end;
+end;
+
+function TWinHTTPClientImpl.GetDnsResolveTimeout: Integer;
+begin
+ Result := FDnsResolveTimeout;
+end;
+
+procedure TWinHTTPClientImpl.SetDnsResolveTimeout(const Value: Integer);
+begin
+ FDnsResolveTimeout := Value;
+end;
+
+function TWinHTTPClientImpl.GetConnectionTimeout: Integer;
+begin
+ Result := FConnectionTimeout;
+end;
+
+procedure TWinHTTPClientImpl.SetConnectionTimeout(const Value: Integer);
+begin
+ FConnectionTimeout := Value;
+end;
+
+function TWinHTTPClientImpl.GetSendTimeout: Integer;
+begin
+ Result := FSendTimeout;
+end;
+
+procedure TWinHTTPClientImpl.SetSendTimeout(const Value: Integer);
+begin
+ FSendTimeout := Value;
+end;
+
+function TWinHTTPClientImpl.GetReadTimeout: Integer;
+begin
+ Result := FReadTimeout;
+end;
+
+procedure TWinHTTPClientImpl.SetReadTimeout(const Value: Integer);
+begin
+ FReadTimeout := Value;
+end;
+
+function TWinHTTPClientImpl.GetCustomHeaders: IThriftDictionary<string,string>;
+begin
+ Result := FCustomHeaders;
+end;
+
+function TWinHTTPClientImpl.GetIsOpen: Boolean;
+begin
+ Result := True;
+end;
+
+procedure TWinHTTPClientImpl.Open;
+begin
+ FreeAndNil( FOutputMemoryStream);
+ FOutputMemoryStream := TMemoryStream.Create;
+end;
+
+procedure TWinHTTPClientImpl.Close;
+begin
+ FInputStream := nil;
+ FreeAndNil( FOutputMemoryStream);
+end;
+
+procedure TWinHTTPClientImpl.Flush;
+begin
+ try
+ SendRequest;
+ finally
+ FreeAndNil( FOutputMemoryStream);
+ FOutputMemoryStream := TMemoryStream.Create;
+ ASSERT( FOutputMemoryStream <> nil);
+ end;
+end;
+
+function TWinHTTPClientImpl.Read( const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer;
+begin
+ if FInputStream = nil then begin
+ raise TTransportExceptionNotOpen.Create('No request has been sent');
+ end;
+
+ try
+ Result := FInputStream.Read( pBuf, buflen, off, len)
+ except
+ on E: Exception
+ do raise TTransportExceptionUnknown.Create(E.Message);
+ end;
+end;
+
+procedure TWinHTTPClientImpl.SendRequest;
+var
+ http : IWinHTTPRequest;
+ pData : PByte;
+ len : Integer;
+begin
+ http := CreateRequest;
+
+ pData := FOutputMemoryStream.Memory;
+ len := FOutputMemoryStream.Size;
+
+ // send all data immediately, since we have it in memory
+ if not http.SendRequest( pData, len, 0)
+ then raise TTransportExceptionUnknown.Create('send request error');
+
+ // end request and start receiving
+ if not http.FlushAndReceiveResponse
+ then raise TTransportExceptionInterrupted.Create('flush/receive error');
+
+ FInputStream := THTTPResponseStream.Create(http);
+end;
+
+procedure TWinHTTPClientImpl.Write( const pBuf : Pointer; off, len : Integer);
+var pTmp : PByte;
+begin
+ pTmp := pBuf;
+ Inc(pTmp,off);
+ FOutputMemoryStream.Write( pTmp^, len);
+end;
+
+
+{ TWinHTTPClientImpl.THTTPResponseStream }
+
+constructor TWinHTTPClientImpl.THTTPResponseStream.Create( const aRequest : IWinHTTPRequest);
+begin
+ inherited Create;
+ FRequest := aRequest;
+end;
+
+destructor TWinHTTPClientImpl.THTTPResponseStream.Destroy;
+begin
+ try
+ Close;
+ finally
+ inherited Destroy;
+ end;
+end;
+
+procedure TWinHTTPClientImpl.THTTPResponseStream.Close;
+begin
+ FRequest := nil;
+end;
+
+procedure TWinHTTPClientImpl.THTTPResponseStream.Flush;
+begin
+ raise ENotImplemented(ClassName+'.Flush');
+end;
+
+function TWinHTTPClientImpl.THTTPResponseStream.IsOpen: Boolean;
+begin
+ Result := FRequest <> nil;
+end;
+
+procedure TWinHTTPClientImpl.THTTPResponseStream.Open;
+begin
+ // nothing to do
+end;
+
+procedure TWinHTTPClientImpl.THTTPResponseStream.Write(const pBuf : Pointer; offset, count: Integer);
+begin
+ inherited; // check pointers
+ raise ENotImplemented(ClassName+'.Write');
+end;
+
+function TWinHTTPClientImpl.THTTPResponseStream.Read(const pBuf : Pointer; const buflen : Integer; offset, count: Integer): Integer;
+var pTmp : PByte;
+begin
+ inherited; // check pointers
+
+ if count >= buflen-offset
+ then count := buflen-offset;
+
+ if count > 0 then begin
+ pTmp := pBuf;
+ Inc( pTmp, offset);
+ Result := FRequest.ReadData( pTmp, count);
+ ASSERT( Result >= 0);
+ end
+ else Result := 0;
+end;
+
+function TWinHTTPClientImpl.THTTPResponseStream.ToArray: TBytes;
+begin
+ raise ENotImplemented(ClassName+'.ToArray');
+end;
+
+
+end.
diff --git a/lib/delphi/src/Thrift.Transport.pas b/lib/delphi/src/Thrift.Transport.pas
index dad9ab7..1f8fdb0 100644
--- a/lib/delphi/src/Thrift.Transport.pas
+++ b/lib/delphi/src/Thrift.Transport.pas
@@ -29,9 +29,9 @@
Math,
Generics.Collections,
{$IFDEF OLD_UNIT_NAMES}
- ActiveX, msxml, WinSock, Sockets,
+ WinSock, Sockets,
{$ELSE}
- Winapi.ActiveX, Winapi.msxml, Winapi.WinSock,
+ Winapi.WinSock,
{$IFDEF OLD_SOCKETS}
Web.Win.Sockets,
{$ELSE}
@@ -41,6 +41,7 @@
Thrift.Collections,
Thrift.Exception,
Thrift.Utils,
+ Thrift.WinHTTP,
Thrift.Stream;
type
@@ -137,47 +138,6 @@
property CustomHeaders: IThriftDictionary<string,string> read GetCustomHeaders;
end;
- THTTPClientImpl = class( TTransportImpl, IHTTPClient)
- private
- FUri : string;
- FInputStream : IThriftStream;
- FOutputStream : IThriftStream;
- FDnsResolveTimeout : Integer;
- FConnectionTimeout : Integer;
- FSendTimeout : Integer;
- FReadTimeout : Integer;
- FCustomHeaders : IThriftDictionary<string,string>;
-
- function CreateRequest: IXMLHTTPRequest;
- protected
- function GetIsOpen: Boolean; override;
- procedure Open(); override;
- procedure Close(); override;
- function Read( const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer; override;
- procedure Write( const pBuf : Pointer; off, len : Integer); override;
- procedure Flush; override;
-
- procedure SetDnsResolveTimeout(const Value: Integer);
- function GetDnsResolveTimeout: Integer;
- procedure SetConnectionTimeout(const Value: Integer);
- function GetConnectionTimeout: Integer;
- procedure SetSendTimeout(const Value: Integer);
- function GetSendTimeout: Integer;
- procedure SetReadTimeout(const Value: Integer);
- function GetReadTimeout: Integer;
-
- 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;
- property ReadTimeout: Integer read GetReadTimeout write SetReadTimeout;
- property CustomHeaders: IThriftDictionary<string,string> read GetCustomHeaders;
- public
- constructor Create( const AUri: string);
- destructor Destroy; override;
- end;
-
IServerTransport = interface
['{C43B87ED-69EA-47C4-B77C-15E288252900}']
procedure Listen;
@@ -472,170 +432,6 @@
Self.Write( pBuf, 0, len);
end;
-{ THTTPClientImpl }
-
-constructor THTTPClientImpl.Create(const AUri: string);
-begin
- inherited Create;
- FUri := AUri;
-
- // defaults according to MSDN
- FDnsResolveTimeout := 0; // no timeout
- FConnectionTimeout := 60 * 1000;
- FSendTimeout := 30 * 1000;
- FReadTimeout := 30 * 1000;
-
- FCustomHeaders := TThriftDictionaryImpl<string,string>.Create;
- FOutputStream := TThriftStreamAdapterDelphi.Create( TMemoryStream.Create, True);
-end;
-
-function THTTPClientImpl.CreateRequest: IXMLHTTPRequest;
-var
- pair : TPair<string,string>;
- srvHttp : IServerXMLHTTPRequest;
-begin
- {$IF CompilerVersion >= 21.0}
- Result := CoServerXMLHTTP.Create;
- {$ELSE}
- Result := CoXMLHTTPRequest.Create;
- {$IFEND}
-
- // setting a timeout value to 0 (zero) means "no timeout" for that setting
- if Supports( result, IServerXMLHTTPRequest, srvHttp)
- 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( 'User-Agent', 'Delphi/IHTTPClient');
-
- for pair in FCustomHeaders do begin
- Result.setRequestHeader( pair.Key, pair.Value );
- end;
-end;
-
-destructor THTTPClientImpl.Destroy;
-begin
- Close;
- inherited;
-end;
-
-function THTTPClientImpl.GetDnsResolveTimeout: Integer;
-begin
- Result := FDnsResolveTimeout;
-end;
-
-procedure THTTPClientImpl.SetDnsResolveTimeout(const Value: Integer);
-begin
- FDnsResolveTimeout := Value;
-end;
-
-function THTTPClientImpl.GetConnectionTimeout: Integer;
-begin
- Result := FConnectionTimeout;
-end;
-
-procedure THTTPClientImpl.SetConnectionTimeout(const Value: Integer);
-begin
- FConnectionTimeout := Value;
-end;
-
-function THTTPClientImpl.GetSendTimeout: Integer;
-begin
- Result := FSendTimeout;
-end;
-
-procedure THTTPClientImpl.SetSendTimeout(const Value: Integer);
-begin
- FSendTimeout := Value;
-end;
-
-function THTTPClientImpl.GetReadTimeout: Integer;
-begin
- Result := FReadTimeout;
-end;
-
-procedure THTTPClientImpl.SetReadTimeout(const Value: Integer);
-begin
- FReadTimeout := Value;
-end;
-
-function THTTPClientImpl.GetCustomHeaders: IThriftDictionary<string,string>;
-begin
- Result := FCustomHeaders;
-end;
-
-function THTTPClientImpl.GetIsOpen: Boolean;
-begin
- Result := True;
-end;
-
-procedure THTTPClientImpl.Open;
-begin
- FOutputStream := TThriftStreamAdapterDelphi.Create( TMemoryStream.Create, True);
-end;
-
-procedure THTTPClientImpl.Close;
-begin
- FInputStream := nil;
- FOutputStream := nil;
-end;
-
-procedure THTTPClientImpl.Flush;
-begin
- try
- SendRequest;
- finally
- FOutputStream := nil;
- FOutputStream := TThriftStreamAdapterDelphi.Create( TMemoryStream.Create, True);
- ASSERT( FOutputStream <> nil);
- end;
-end;
-
-function THTTPClientImpl.Read( const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer;
-begin
- if FInputStream = nil then begin
- raise TTransportExceptionNotOpen.Create('No request has been sent');
- end;
-
- try
- Result := FInputStream.Read( pBuf, buflen, off, len)
- except
- on E: Exception
- do raise TTransportExceptionUnknown.Create(E.Message);
- end;
-end;
-
-procedure THTTPClientImpl.SendRequest;
-var
- xmlhttp : IXMLHTTPRequest;
- ms : TMemoryStream;
- a : TBytes;
- len : Integer;
-begin
- xmlhttp := CreateRequest;
-
- ms := TMemoryStream.Create;
- try
- a := FOutputStream.ToArray;
- len := Length(a);
- if len > 0 then begin
- ms.WriteBuffer( Pointer(@a[0])^, len);
- end;
- ms.Position := 0;
- xmlhttp.send( IUnknown( TStreamAdapter.Create( ms, soReference )));
- FInputStream := nil;
- FInputStream := TThriftStreamAdapterCOM.Create( IUnknown( xmlhttp.responseStream) as IStream);
- finally
- ms.Free;
- end;
-end;
-
-procedure THTTPClientImpl.Write( const pBuf : Pointer; off, len : Integer);
-begin
- FOutputStream.Write( pBuf, off, len);
-end;
-
{ TTransportException }
function TTransportException.GetType: TExceptionType;
diff --git a/lib/delphi/src/Thrift.WinHTTP.pas b/lib/delphi/src/Thrift.WinHTTP.pas
new file mode 100644
index 0000000..0d824b6
--- /dev/null
+++ b/lib/delphi/src/Thrift.WinHTTP.pas
@@ -0,0 +1,805 @@
+(*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *)
+unit Thrift.WinHTTP;
+
+{$I Thrift.Defines.inc}
+{$SCOPEDENUMS ON}
+
+// packing according to winhttp.h
+{$IFDEF Win64} {$ALIGN 8} {$ELSE} {$ALIGN 4} {$ENDIF}
+
+interface
+
+uses
+ Windows,
+ Classes,
+ SysUtils,
+ Math,
+ Generics.Collections;
+
+
+type
+ HINTERNET = type Pointer;
+ INTERNET_PORT = type WORD;
+ INTERNET_SCHEME = type Integer;
+ LPLPCWSTR = ^LPCWSTR;
+
+ LPURL_COMPONENTS = ^URL_COMPONENTS;
+ URL_COMPONENTS = record
+ dwStructSize : DWORD; // set to SizeOf(URL_COMPONENTS)
+ lpszScheme : LPWSTR; // scheme name
+ dwSchemeLength : DWORD;
+ nScheme : INTERNET_SCHEME; // enumerated scheme type
+ lpszHostName : LPWSTR; // host name
+ dwHostNameLength : DWORD;
+ nPort : INTERNET_PORT; // port number
+ lpszUserName : LPWSTR; // user name
+ dwUserNameLength : DWORD;
+ lpszPassword : LPWSTR; // password
+ dwPasswordLength : DWORD;
+ lpszUrlPath : LPWSTR; // URL-path
+ dwUrlPathLength : DWORD;
+ lpszExtraInfo : LPWSTR; // extra information
+ dwExtraInfoLength : DWORD;
+ end;
+
+ URL_COMPONENTSW = URL_COMPONENTS;
+ LPURL_COMPONENTSW = LPURL_COMPONENTS;
+
+
+function WinHttpCloseHandle( aHandle : HINTERNET) : BOOL; stdcall;
+
+function WinHttpOpen( const pszAgentW : LPCWSTR;
+ const dwAccessType : DWORD;
+ const pszProxyW : LPCWSTR;
+ const pszProxyBypassW : LPCWSTR;
+ const dwFlags : DWORD
+ ) : HINTERNET; stdcall;
+
+function WinHttpConnect( const hSession : HINTERNET;
+ const pswzServerName : LPCWSTR;
+ const nServerPort : INTERNET_PORT;
+ const dwReserved : DWORD
+ ) : HINTERNET; stdcall;
+
+function WinHttpOpenRequest( const hConnect : HINTERNET;
+ const pwszVerb, pwszObjectName, pwszVersion, pwszReferrer : LPCWSTR;
+ const ppwszAcceptTypes : LPLPCWSTR;
+ const dwFlags : DWORD
+ ) : HINTERNET; stdcall;
+
+function WinHttpSetTimeouts( const hRequestOrSession : HINTERNET;
+ const aResolveTimeout, aConnectTimeout, aSendTimeout, aReceiveTimeout : Int32
+ ) : BOOL; stdcall;
+
+function WinHttpAddRequestHeaders( const hRequest : HINTERNET;
+ const pwszHeaders : LPCWSTR;
+ const dwHeadersLengthInChars : DWORD;
+ const dwModifiers : DWORD
+ ) : BOOL; stdcall;
+
+function WinHttpSendRequest( const hRequest : HINTERNET;
+ const lpszHeaders : LPCWSTR;
+ const dwHeadersLength : DWORD;
+ const lpOptional : Pointer;
+ const dwOptionalLength : DWORD;
+ const dwTotalLength : DWORD;
+ const pContext : Pointer
+ ) : BOOL; stdcall;
+
+function WinHttpWriteData( const hRequest : HINTERNET;
+ const pBuf : Pointer;
+ const dwBytesToWrite : DWORD;
+ out dwBytesWritten : DWORD
+ ) : BOOL; stdcall;
+
+function WinHttpReceiveResponse( const hRequest : HINTERNET; const lpReserved : Pointer) : BOOL; stdcall;
+
+function WinHttpQueryHeaders( const hRequest : HINTERNET;
+ const dwInfoLevel : DWORD;
+ const pwszName : LPCWSTR;
+ const lpBuffer : Pointer;
+ var dwBufferLength : DWORD;
+ var dwIndex : DWORD
+ ) : BOOL; stdcall;
+
+function WinHttpQueryDataAvailable( const hRequest : HINTERNET;
+ var dwNumberOfBytesAvailable : DWORD
+ ) : BOOL; stdcall;
+
+function WinHttpReadData( const hRequest : HINTERNET;
+ const lpBuffer : Pointer;
+ const dwBytesToRead : DWORD;
+ out dwBytesRead : DWORD
+ ) : BOOL; stdcall;
+
+function WinHttpCrackUrl( const pwszUrl : LPCWSTR;
+ const dwUrlLength : DWORD;
+ const dwFlags : DWORD;
+ var urlComponents : URL_COMPONENTS
+ ) : BOOL; stdcall;
+
+function WinHttpCreateUrl( const UrlComponents : URL_COMPONENTS;
+ const dwFlags : DWORD;
+ const pwszUrl : LPCWSTR;
+ var pdwUrlLength : DWORD
+ ) : BOOL; stdcall;
+
+
+const
+ // WinHttpOpen dwAccessType values
+ WINHTTP_ACCESS_TYPE_DEFAULT_PROXY = 0;
+ WINHTTP_ACCESS_TYPE_NO_PROXY = 1;
+ WINHTTP_ACCESS_TYPE_NAMED_PROXY = 3;
+
+ // flags for WinHttpOpen():
+ WINHTTP_FLAG_ASYNC = $10000000; // want async session, requires WinHttpSetStatusCallback() usage
+
+ // ports
+ INTERNET_DEFAULT_PORT = 0; // use the protocol-specific default (80 or 443)
+
+ // flags for WinHttpOpenRequest():
+ WINHTTP_FLAG_SECURE = $00800000; // use SSL if applicable (HTTPS)
+ WINHTTP_FLAG_ESCAPE_PERCENT = $00000004; // if escaping enabled, escape percent as well
+ WINHTTP_FLAG_NULL_CODEPAGE = $00000008; // assume all symbols are ASCII, use fast convertion
+ WINHTTP_FLAG_BYPASS_PROXY_CACHE = $00000100; // add "pragma: no-cache" request header
+ WINHTTP_FLAG_REFRESH = WINHTTP_FLAG_BYPASS_PROXY_CACHE;
+ WINHTTP_FLAG_ESCAPE_DISABLE = $00000040; // disable escaping
+ WINHTTP_FLAG_ESCAPE_DISABLE_QUERY = $00000080; // if escaping enabled escape path part, but do not escape query
+
+ // flags for WinHttpSendRequest():
+ WINHTTP_NO_ADDITIONAL_HEADERS = nil;
+ WINHTTP_NO_REQUEST_DATA = nil;
+
+ // WinHttpAddRequestHeaders() dwModifiers
+ WINHTTP_ADDREQ_INDEX_MASK = $0000FFFF;
+ WINHTTP_ADDREQ_FLAGS_MASK = $FFFF0000;
+
+ WINHTTP_ADDREQ_FLAG_ADD_IF_NEW = $10000000;
+ WINHTTP_ADDREQ_FLAG_ADD = $20000000;
+ WINHTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA = $40000000;
+ WINHTTP_ADDREQ_FLAG_COALESCE_WITH_SEMICOLON = $01000000;
+ WINHTTP_ADDREQ_FLAG_COALESCE = WINHTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA;
+ WINHTTP_ADDREQ_FLAG_REPLACE = $80000000;
+
+ // URL functions
+ ICU_NO_ENCODE = $20000000; // Don't convert unsafe characters to escape sequence
+ ICU_DECODE = $10000000; // Convert %XX escape sequences to characters
+ ICU_NO_META = $08000000; // Don't convert .. etc. meta path sequences
+ ICU_ENCODE_SPACES_ONLY = $04000000; // Encode spaces only
+ ICU_BROWSER_MODE = $02000000; // Special encode/decode rules for browser
+ ICU_ENCODE_PERCENT = $00001000; // Encode any percent (ASCII25)
+
+ ICU_ESCAPE = $80000000; // (un)escape URL characters
+ ICU_ESCAPE_AUTHORITY = $00002000; // causes InternetCreateUrlA to escape chars in authority components (user, pwd, host)
+ ICU_REJECT_USERPWD = $00004000; // rejects usrls whick have username/pwd sections
+
+ INTERNET_SCHEME_HTTP = INTERNET_SCHEME(1);
+ INTERNET_SCHEME_HTTPS = INTERNET_SCHEME(2);
+
+const
+ WINHTTP_ERROR_BASE = 12000;
+ ERROR_WINHTTP_OUT_OF_HANDLES = WINHTTP_ERROR_BASE + 1;
+ ERROR_WINHTTP_TIMEOUT = WINHTTP_ERROR_BASE + 2;
+ ERROR_WINHTTP_INTERNAL_ERROR = WINHTTP_ERROR_BASE + 4;
+ ERROR_WINHTTP_INVALID_URL = WINHTTP_ERROR_BASE + 5;
+ ERROR_WINHTTP_UNRECOGNIZED_SCHEME = WINHTTP_ERROR_BASE + 6;
+ ERROR_WINHTTP_NAME_NOT_RESOLVED = WINHTTP_ERROR_BASE + 7;
+ ERROR_WINHTTP_INVALID_OPTION = WINHTTP_ERROR_BASE + 9;
+ ERROR_WINHTTP_OPTION_NOT_SETTABLE = WINHTTP_ERROR_BASE + 11;
+ ERROR_WINHTTP_SHUTDOWN = WINHTTP_ERROR_BASE + 12;
+ ERROR_WINHTTP_LOGIN_FAILURE = WINHTTP_ERROR_BASE + 15;
+ ERROR_WINHTTP_OPERATION_CANCELLED = WINHTTP_ERROR_BASE + 17;
+ ERROR_WINHTTP_INCORRECT_HANDLE_TYPE = WINHTTP_ERROR_BASE + 18;
+ ERROR_WINHTTP_INCORRECT_HANDLE_STATE = WINHTTP_ERROR_BASE + 19;
+ ERROR_WINHTTP_CANNOT_CONNECT = WINHTTP_ERROR_BASE + 29;
+ ERROR_WINHTTP_CONNECTION_ERROR = WINHTTP_ERROR_BASE + 30;
+ ERROR_WINHTTP_RESEND_REQUEST = WINHTTP_ERROR_BASE + 32;
+ ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED = WINHTTP_ERROR_BASE + 44;
+ ERROR_WINHTTP_CANNOT_CALL_BEFORE_OPEN = WINHTTP_ERROR_BASE + 100;
+ ERROR_WINHTTP_CANNOT_CALL_BEFORE_SEND = WINHTTP_ERROR_BASE + 101;
+ ERROR_WINHTTP_CANNOT_CALL_AFTER_SEND = WINHTTP_ERROR_BASE + 102;
+ ERROR_WINHTTP_CANNOT_CALL_AFTER_OPEN = WINHTTP_ERROR_BASE + 103;
+ ERROR_WINHTTP_HEADER_NOT_FOUND = WINHTTP_ERROR_BASE + 150;
+ ERROR_WINHTTP_INVALID_SERVER_RESPONSE = WINHTTP_ERROR_BASE + 152;
+ ERROR_WINHTTP_INVALID_HEADER = WINHTTP_ERROR_BASE + 153;
+ ERROR_WINHTTP_INVALID_QUERY_REQUEST = WINHTTP_ERROR_BASE + 154;
+ ERROR_WINHTTP_HEADER_ALREADY_EXISTS = WINHTTP_ERROR_BASE + 155;
+ ERROR_WINHTTP_REDIRECT_FAILED = WINHTTP_ERROR_BASE + 156;
+ ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR = WINHTTP_ERROR_BASE + 178;
+ ERROR_WINHTTP_BAD_AUTO_PROXY_SCRIPT = WINHTTP_ERROR_BASE + 166;
+ ERROR_WINHTTP_UNABLE_TO_DOWNLOAD_SCRIPT = WINHTTP_ERROR_BASE + 167;
+ ERROR_WINHTTP_NOT_INITIALIZED = WINHTTP_ERROR_BASE + 172;
+ ERROR_WINHTTP_SECURE_FAILURE = WINHTTP_ERROR_BASE + 175;
+
+ // Certificate security errors. Additional information is provided
+ // via the WINHTTP_CALLBACK_STATUS_SECURE_FAILURE callback notification.
+ ERROR_WINHTTP_SECURE_CERT_DATE_INVALID = WINHTTP_ERROR_BASE + 37;
+ ERROR_WINHTTP_SECURE_CERT_CN_INVALID = WINHTTP_ERROR_BASE + 38;
+ ERROR_WINHTTP_SECURE_INVALID_CA = WINHTTP_ERROR_BASE + 45;
+ ERROR_WINHTTP_SECURE_CERT_REV_FAILED = WINHTTP_ERROR_BASE + 57;
+ ERROR_WINHTTP_SECURE_CHANNEL_ERROR = WINHTTP_ERROR_BASE + 157;
+ ERROR_WINHTTP_SECURE_INVALID_CERT = WINHTTP_ERROR_BASE + 169;
+ ERROR_WINHTTP_SECURE_CERT_REVOKED = WINHTTP_ERROR_BASE + 170;
+ ERROR_WINHTTP_SECURE_CERT_WRONG_USAGE = WINHTTP_ERROR_BASE + 179;
+
+ ERROR_WINHTTP_AUTODETECTION_FAILED = WINHTTP_ERROR_BASE + 180;
+ ERROR_WINHTTP_HEADER_COUNT_EXCEEDED = WINHTTP_ERROR_BASE + 181;
+ ERROR_WINHTTP_HEADER_SIZE_OVERFLOW = WINHTTP_ERROR_BASE + 182;
+ ERROR_WINHTTP_CHUNKED_ENCODING_HEADER_SIZE_OVERFLOW = WINHTTP_ERROR_BASE + 183;
+ ERROR_WINHTTP_RESPONSE_DRAIN_OVERFLOW = WINHTTP_ERROR_BASE + 184;
+ ERROR_WINHTTP_CLIENT_CERT_NO_PRIVATE_KEY = WINHTTP_ERROR_BASE + 185;
+ ERROR_WINHTTP_CLIENT_CERT_NO_ACCESS_PRIVATE_KEY = WINHTTP_ERROR_BASE + 186;
+
+
+const
+ WINHTTP_THRIFT_DEFAULTS = WINHTTP_FLAG_NULL_CODEPAGE
+ or WINHTTP_FLAG_BYPASS_PROXY_CACHE
+ or WINHTTP_FLAG_ESCAPE_DISABLE;
+
+
+type
+ IWinHTTPRequest = interface
+ ['{35C6D9D4-FDCE-42C6-B84C-9294E6FB904C}']
+ function Handle : HINTERNET;
+ function AddRequestHeader( const aHeader : string; const addflag : DWORD = WINHTTP_ADDREQ_FLAG_ADD) : Boolean;
+ function SetTimeouts( const aResolveTimeout, aConnectTimeout, aSendTimeout, aReceiveTimeout : Int32) : Boolean;
+ 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;
+ function ReadData( const dwRead : DWORD) : TBytes; overload;
+ function ReadData( const pBuf : Pointer; const dwRead : DWORD) : DWORD; overload;
+ end;
+
+ IWinHTTPConnection = interface
+ ['{1C4F78B5-1525-4788-B638-A0E41BCF4D43}']
+ function Handle : HINTERNET;
+ function OpenRequest( const secure : Boolean; const aVerb, aObjName, aAcceptTypes : UnicodeString) : IWinHTTPRequest;
+ end;
+
+ IWinHTTPSession = interface
+ ['{B6F8BD98-0605-4A9E-B671-4CB191D74A5E}']
+ 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;
+ end;
+
+ IWinHTTPUrl = interface
+ ['{78BE977C-4171-4AF5-A250-FD2890205E63}']
+ // url parts getter
+ function GetScheme : UnicodeString;
+ function GetNumScheme : INTERNET_SCHEME;
+ function GetHostName : UnicodeString;
+ function GetPort : INTERNET_PORT;
+ function GetUserName : UnicodeString;
+ function GetPassword : UnicodeString;
+ function GetUrlPath : UnicodeString;
+ function GetExtraInfo : UnicodeString;
+
+ // url parts setter
+ procedure SetScheme( const value : UnicodeString);
+ procedure SetHostName ( const value : UnicodeString);
+ procedure SetPort( const value : INTERNET_PORT);
+ procedure SetUserName( const value : UnicodeString);
+ procedure SetPassword( const value : UnicodeString);
+ procedure SetUrlPath( const value : UnicodeString);
+ procedure SetExtraInfo( const value : UnicodeString);
+
+ // url as a whole
+ function BuildUrl : UnicodeString;
+ procedure CrackUrl( const value : UnicodeString);
+
+ // url parts
+ property Scheme : UnicodeString read GetScheme write SetScheme;
+ property NumScheme : INTERNET_SCHEME read GetNumScheme; // readonly
+ property HostName : UnicodeString read GetHostName write SetHostName;
+ property Port : INTERNET_PORT read GetPort write SetPort;
+ property UserName : UnicodeString read GetUserName write SetUserName;
+ property Password : UnicodeString read GetPassword write SetPassword;
+ property UrlPath : UnicodeString read GetUrlPath write SetUrlPath;
+ property ExtraInfo : UnicodeString read GetExtraInfo write SetExtraInfo;
+
+ // url as a whole
+ property CompleteURL : UnicodeString read BuildUrl write CrackUrl;
+ end;
+
+
+
+
+type
+ TWinHTTPHandleObjectImpl = class( TInterfacedObject)
+ strict protected
+ FHandle : HINTERNET;
+ function Handle : HINTERNET;
+ public
+ constructor Create( const aHandle : HINTERNET);
+ destructor Destroy; override;
+ end;
+
+
+ TWinHTTPSessionImpl = class( TWinHTTPHandleObjectImpl, IWinHTTPSession)
+ strict protected
+
+ // IWinHTTPSession
+ function Connect( const aHostName : UnicodeString; const aPort : INTERNET_PORT = INTERNET_DEFAULT_PORT) : IWinHTTPConnection;
+ function SetTimeouts( const aResolveTimeout, aConnectTimeout, aSendTimeout, aReceiveTimeout : Int32) : Boolean;
+
+ public
+ constructor Create( const aAgent : UnicodeString;
+ const aAccessType : DWORD = WINHTTP_ACCESS_TYPE_DEFAULT_PROXY;
+ const aProxy : UnicodeString = '';
+ const aProxyBypass : UnicodeString = '';
+ const aFlags : DWORD = 0);
+ destructor Destroy; override;
+ end;
+
+
+ TWinHTTPConnectionImpl = class( TWinHTTPHandleObjectImpl, IWinHTTPConnection)
+ strict protected
+ FSession : IWinHTTPSession;
+
+ // IWinHTTPConnection
+ function OpenRequest( const secure : Boolean; const aVerb, aObjName, aAcceptTypes : UnicodeString) : IWinHTTPRequest;
+
+ public
+ constructor Create( const aSession : IWinHTTPSession; const aHostName : UnicodeString; const aPort : INTERNET_PORT);
+ destructor Destroy; override;
+ end;
+
+
+ TAcceptTypesArray = array of string;
+
+ TWinHTTPRequestImpl = class( TWinHTTPHandleObjectImpl, IWinHTTPRequest)
+ strict protected
+ FConnection : IWinHTTPConnection;
+
+ // IWinHTTPRequest
+ function AddRequestHeader( const aHeader : string; const addflag : DWORD = WINHTTP_ADDREQ_FLAG_ADD) : Boolean;
+ function SetTimeouts( const aResolveTimeout, aConnectTimeout, aSendTimeout, aReceiveTimeout : Int32) : Boolean;
+ 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;
+ function ReadData( const dwRead : DWORD) : TBytes; overload;
+ function ReadData( const pBuf : Pointer; const dwRead : DWORD) : DWORD; overload;
+
+ public
+ constructor Create( const aConnection : IWinHTTPConnection;
+ const aVerb, aObjName : UnicodeString;
+ const aVersion : UnicodeString = '';
+ const aReferrer : UnicodeString = '';
+ const aAcceptTypes : UnicodeString = '*/*';
+ const aFlags : DWORD = WINHTTP_THRIFT_DEFAULTS
+ );
+
+ destructor Destroy; override;
+ end;
+
+
+ TWinHTTPUrlImpl = class( TInterfacedObject, IWinHTTPUrl)
+ strict private
+ FScheme : UnicodeString;
+ FNumScheme : INTERNET_SCHEME;
+ FHostName : UnicodeString;
+ FPort : INTERNET_PORT;
+ FUserName : UnicodeString;
+ FPassword : UnicodeString;
+ FUrlPath : UnicodeString;
+ FExtraInfo : UnicodeString;
+
+ strict protected
+ // url parts getter
+ function GetScheme : UnicodeString;
+ function GetNumScheme : INTERNET_SCHEME;
+ function GetHostName : UnicodeString;
+ function GetPort : INTERNET_PORT;
+ function GetUserName : UnicodeString;
+ function GetPassword : UnicodeString;
+ function GetUrlPath : UnicodeString;
+ function GetExtraInfo : UnicodeString;
+
+ // url parts setter
+ procedure SetScheme( const value : UnicodeString);
+ procedure SetHostName ( const value : UnicodeString);
+ procedure SetPort( const value : INTERNET_PORT);
+ procedure SetUserName( const value : UnicodeString);
+ procedure SetPassword( const value : UnicodeString);
+ procedure SetUrlPath( const value : UnicodeString);
+ procedure SetExtraInfo( const value : UnicodeString);
+
+ // url as a whole
+ function BuildUrl : UnicodeString;
+ procedure CrackUrl( const value : UnicodeString);
+
+ public
+ constructor Create( const aUri : UnicodeString);
+ destructor Destroy; override;
+ end;
+
+
+ EWinHTTPException = class(Exception);
+
+implementation
+
+const WINHTTP_DLL = 'WinHTTP.dll';
+
+function WinHttpCloseHandle; stdcall; external WINHTTP_DLL;
+function WinHttpOpen; stdcall; external WINHTTP_DLL;
+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 WinHttpAddRequestHeaders; stdcall; external WINHTTP_DLL;
+function WinHttpWriteData; stdcall; external WINHTTP_DLL;
+function WinHttpReceiveResponse; stdcall; external WINHTTP_DLL;
+function WinHttpQueryHeaders; stdcall; external WINHTTP_DLL;
+function WinHttpQueryDataAvailable; stdcall; external WINHTTP_DLL;
+function WinHttpReadData; stdcall; external WINHTTP_DLL;
+function WinHttpCrackUrl; stdcall; external WINHTTP_DLL;
+function WinHttpCreateUrl; stdcall; external WINHTTP_DLL;
+
+
+{ TWinHTTPHandleObjectImpl }
+
+constructor TWinHTTPHandleObjectImpl.Create( const aHandle : HINTERNET);
+begin
+ inherited Create;
+ FHandle := aHandle;
+
+ if FHandle = nil
+ then raise EWinHTTPException.Create('Invalid handle');
+end;
+
+
+destructor TWinHTTPHandleObjectImpl.Destroy;
+begin
+ try
+ if Assigned(FHandle) then begin
+ WinHttpCloseHandle(FHandle);
+ FHandle := nil;
+ end;
+
+ finally
+ inherited Destroy;
+ end;
+end;
+
+
+function TWinHTTPHandleObjectImpl.Handle : HINTERNET;
+begin
+ result := FHandle;
+end;
+
+
+{ TWinHTTPSessionImpl }
+
+
+constructor TWinHTTPSessionImpl.Create( const aAgent : UnicodeString; const aAccessType : DWORD;
+ const aProxy, aProxyBypass : UnicodeString; const aFlags : DWORD);
+var handle : HINTERNET;
+begin
+ handle := WinHttpOpen( PWideChar(aAgent), aAccessType,
+ PWideChar(Pointer(aProxy)), // may be nil
+ PWideChar(Pointer(aProxyBypass)), // may be nil
+ aFlags);
+ inherited Create( handle);
+end;
+
+
+destructor TWinHTTPSessionImpl.Destroy;
+begin
+ inherited Destroy;
+ // add code here
+end;
+
+
+function TWinHTTPSessionImpl.Connect( const aHostName : UnicodeString; const aPort : INTERNET_PORT) : IWinHTTPConnection;
+begin
+ result := TWinHTTPConnectionImpl.Create( Self, aHostName, aPort);
+end;
+
+
+function TWinHTTPSessionImpl.SetTimeouts( const aResolveTimeout, aConnectTimeout, aSendTimeout, aReceiveTimeout : Int32) : Boolean;
+begin
+ result := WinHttpSetTimeouts( FHandle, aResolveTimeout, aConnectTimeout, aSendTimeout, aReceiveTimeout);
+end;
+
+
+{ TWinHTTPConnectionImpl }
+
+constructor TWinHTTPConnectionImpl.Create( const aSession : IWinHTTPSession; const aHostName : UnicodeString; const aPort : INTERNET_PORT);
+var handle : HINTERNET;
+begin
+ FSession := aSession;
+ handle := WinHttpConnect( FSession.Handle, PWideChar(aHostName), aPort, 0);
+ inherited Create( handle);
+end;
+
+
+destructor TWinHTTPConnectionImpl.Destroy;
+begin
+ inherited Destroy;
+ FSession := nil;
+end;
+
+
+function TWinHTTPConnectionImpl.OpenRequest( const secure : Boolean; const aVerb, aObjName, aAcceptTypes : UnicodeString) : IWinHTTPRequest;
+var dwFlags : DWORD;
+begin
+ dwFlags := WINHTTP_THRIFT_DEFAULTS;
+ if secure
+ then dwFlags := dwFlags or WINHTTP_FLAG_SECURE
+ else dwFlags := dwFlags and not WINHTTP_FLAG_SECURE;
+
+ result := TWinHTTPRequestImpl.Create( Self, aVerb, aObjName, '', '', aAcceptTypes, dwFlags);
+end;
+
+
+{ TWinHTTPRequestImpl }
+
+constructor TWinHTTPRequestImpl.Create( const aConnection : IWinHTTPConnection;
+ const aVerb, aObjName, aVersion, aReferrer : UnicodeString;
+ const aAcceptTypes : UnicodeString;
+ const aFlags : DWORD
+ );
+var handle : HINTERNET;
+ accept : array[0..1] of PWideChar;
+begin
+ FConnection := aConnection;
+
+ accept[0] := PWideChar(aAcceptTypes);
+ accept[1] := nil;
+
+ handle := WinHttpOpenRequest( FConnection.Handle,
+ PWideChar(UpperCase(aVerb)),
+ PWideChar(aObjName),
+ PWideChar(aVersion),
+ PWideChar(aReferrer),
+ @accept,
+ aFlags);
+ inherited Create( handle);
+end;
+
+
+destructor TWinHTTPRequestImpl.Destroy;
+begin
+ inherited Destroy;
+ FConnection := nil;
+end;
+
+
+function TWinHTTPRequestImpl.SetTimeouts( const aResolveTimeout, aConnectTimeout, aSendTimeout, aReceiveTimeout : Int32) : Boolean;
+begin
+ result := WinHttpSetTimeouts( FHandle, aResolveTimeout, aConnectTimeout, aSendTimeout, aReceiveTimeout);
+end;
+
+
+function TWinHTTPRequestImpl.AddRequestHeader( const aHeader : string; const addflag : DWORD) : Boolean;
+begin
+ result := WinHttpAddRequestHeaders( FHandle, PWideChar(aHeader), DWORD(-1), addflag);
+end;
+
+
+function TWinHTTPRequestImpl.SendRequest( const pBuf : Pointer; const dwBytes, dwExtra : DWORD) : Boolean;
+begin
+ result := WinHttpSendRequest( FHandle,
+ WINHTTP_NO_ADDITIONAL_HEADERS, 0,
+ pBuf, dwBytes, // number of bytes in pBuf
+ dwBytes + dwExtra, // becomes the Content-Length
+ nil); // context for async operations
+end;
+
+
+function TWinHTTPRequestImpl.WriteExtraData( const pBuf : Pointer; const dwBytes : DWORD) : DWORD;
+begin
+ if not WinHttpWriteData( FHandle, pBuf, dwBytes, result)
+ then result := 0;
+end;
+
+
+function TWinHTTPRequestImpl.FlushAndReceiveResponse : Boolean;
+begin
+ result := WinHttpReceiveResponse( FHandle, nil);
+end;
+
+
+function TWinHTTPRequestImpl.ReadData( const dwRead : DWORD) : TBytes;
+var dwAvailable, dwReceived : DWORD;
+begin
+ if WinHttpQueryDataAvailable( FHandle, dwAvailable)
+ then dwAvailable := Min( dwRead, dwAvailable)
+ else dwAvailable := 0;
+
+ SetLength( result, dwAvailable);
+ if dwAvailable = 0 then Exit;
+
+ if WinHttpReadData( FHandle, @result[0], Length(result), dwReceived)
+ then SetLength( result, dwReceived)
+ else SetLength( result, 0);
+end;
+
+
+function TWinHTTPRequestImpl.ReadData( const pBuf : Pointer; const dwRead : DWORD) : DWORD;
+var dwAvailable : DWORD;
+begin
+ if WinHttpQueryDataAvailable( FHandle, dwAvailable)
+ then dwAvailable := Min( dwRead, dwAvailable)
+ else dwAvailable := 0;
+
+ if (dwAvailable = 0)
+ or not WinHttpReadData( FHandle, pBuf, dwAvailable, result)
+ then result := 0;
+end;
+
+
+{ TWinHTTPUrlImpl }
+
+constructor TWinHTTPUrlImpl.Create(const aUri: UnicodeString);
+begin
+ inherited Create;
+ CrackUrl( aUri)
+end;
+
+
+destructor TWinHTTPUrlImpl.Destroy;
+begin
+ inherited Destroy;
+end;
+
+
+procedure TWinHTTPUrlImpl.CrackURL( const value : UnicodeString);
+const FLAGS = 0; // no special operations, leave components as-is
+var components : URL_COMPONENTS;
+begin
+ FillChar(components, SizeOf(components), 0);
+ components.dwStructSize := SizeOf(components);
+
+ if value <> '' then begin
+ { For the WinHttpCrackUrl function, [...] if the pointer member is NULL but the
+ length member is not zero, both the pointer and length members are returned. }
+ components.dwSchemeLength := DWORD(-1);
+ components.dwHostNameLength := DWORD(-1);
+ components.dwUserNameLength := DWORD(-1);
+ components.dwPasswordLength := DWORD(-1);
+ components.dwUrlPathLength := DWORD(-1);
+ components.dwExtraInfoLength := DWORD(-1);
+
+ WinHttpCrackUrl( PWideChar(value), Length(value), FLAGS, components);
+ end;
+
+ FNumScheme := components.nScheme;
+ FPort := components.nPort;
+ SetString( FScheme, components.lpszScheme, components.dwSchemeLength);
+ SetString( FHostName, components.lpszHostName, components.dwHostNameLength);
+ SetString( FUserName, components.lpszUserName, components.dwUserNameLength);
+ SetString( FPassword, components.lpszPassword, components.dwPasswordLength);
+ SetString( FUrlPath, components.lpszUrlPath, components.dwUrlPathLength);
+ SetString( FExtraInfo, components.lpszExtraInfo, components.dwExtraInfoLength);
+end;
+
+
+function TWinHTTPUrlImpl.BuildUrl : UnicodeString;
+const FLAGS = 0; // no special operations, leave components as-is
+var components : URL_COMPONENTS;
+ dwChars : DWORD;
+begin
+ FillChar(components, SizeOf(components), 0);
+ components.dwStructSize := SizeOf(components);
+ components.lpszScheme := PWideChar(FScheme);
+ components.dwSchemeLength := Length(FScheme);
+ components.lpszHostName := PWideChar(FHostName);
+ components.dwHostNameLength := Length(FHostName);
+ components.nPort := FPort;
+ components.lpszUserName := PWideChar(FUserName);
+ components.dwUserNameLength := Length(FUserName);
+ components.lpszPassword := PWideChar(FPassword);
+ components.dwPasswordLength := Length(FPassword);
+ components.lpszUrlPath := PWideChar(FUrlPath);
+ components.dwUrlPathLength := Length(FUrlPath);
+ components.lpszExtraInfo := PWideChar(FExtraInfo);
+ components.dwExtraInfoLength := Length(FExtraInfo);
+
+ WinHttpCreateUrl( components, FLAGS, nil, dwChars);
+ if dwChars = 0
+ then result := ''
+ else begin
+ SetLength( result, dwChars + 1);
+ WinHttpCreateUrl( components, FLAGS, @result[1], dwChars);
+ SetLength( result, dwChars); // cut off terminating #0
+ end;
+end;
+
+
+function TWinHTTPUrlImpl.GetExtraInfo: UnicodeString;
+begin
+ result := FExtraInfo;
+end;
+
+function TWinHTTPUrlImpl.GetHostName: UnicodeString;
+begin
+ result := FHostName;
+end;
+
+function TWinHTTPUrlImpl.GetNumScheme: INTERNET_SCHEME;
+begin
+ result := FNumScheme;
+end;
+
+function TWinHTTPUrlImpl.GetPassword: UnicodeString;
+begin
+ result := FPassword;
+end;
+
+function TWinHTTPUrlImpl.GetPort: INTERNET_PORT;
+begin
+ result := FPort;
+end;
+
+function TWinHTTPUrlImpl.GetScheme: UnicodeString;
+begin
+ result := FScheme;
+end;
+
+function TWinHTTPUrlImpl.GetUrlPath: UnicodeString;
+begin
+ result := FUrlPath;
+end;
+
+function TWinHTTPUrlImpl.GetUserName: UnicodeString;
+begin
+ result := FUserName;
+end;
+
+procedure TWinHTTPUrlImpl.SetExtraInfo(const value: UnicodeString);
+begin
+ FExtraInfo := value;
+end;
+
+procedure TWinHTTPUrlImpl.SetHostName(const value: UnicodeString);
+begin
+ FHostName := value;
+end;
+
+procedure TWinHTTPUrlImpl.SetPassword(const value: UnicodeString);
+begin
+ FPassword := value;
+end;
+
+procedure TWinHTTPUrlImpl.SetPort(const value: INTERNET_PORT);
+begin
+ FPort := value;
+end;
+
+procedure TWinHTTPUrlImpl.SetScheme(const value: UnicodeString);
+begin
+ FScheme := value;
+end;
+
+procedure TWinHTTPUrlImpl.SetUrlPath(const value: UnicodeString);
+begin
+ FUrlPath := value;
+end;
+
+procedure TWinHTTPUrlImpl.SetUserName(const value: UnicodeString);
+begin
+ FUserName := value;
+end;
+
+
+end.
+
diff --git a/lib/delphi/test/TestClient.pas b/lib/delphi/test/TestClient.pas
index 7b603a3..55bf92b 100644
--- a/lib/delphi/test/TestClient.pas
+++ b/lib/delphi/test/TestClient.pas
@@ -43,6 +43,8 @@
Thrift.Protocol.JSON,
Thrift.Protocol,
Thrift.Transport.Pipes,
+ Thrift.Transport.WinHTTP,
+ Thrift.Transport.MsxmlHTTP,
Thrift.Transport,
Thrift.Stream,
Thrift.Test,
@@ -115,6 +117,7 @@
procedure InitializeProtocolTransportStack;
procedure ShutdownProtocolTransportStack;
+ function InitializeHttpTransport( const aTimeoutSetting : Integer) : IHTTPClient;
procedure JSONProtocolReadWriteTest;
function PrepareBinaryData( aRandomDist : Boolean; aSize : TTestSize) : TBytes;
@@ -188,7 +191,7 @@
+ ' instead of host and port'#10
+ ' --named-pipe arg Windows Named Pipe (e.g. MyThriftPipe)'#10
+ ' --anon-pipes hRead hWrite Windows Anonymous Pipes pair (handles)'#10
- + ' --transport arg (=sockets) Transport: buffered, framed, http, evhttp'#10
+ + ' --transport arg (=sockets) Transport: buffered, framed, http, winhttp'#10
+ ' --protocol arg (=binary) Protocol: binary, compact, json'#10
+ ' --ssl Encrypted Transport using SSL'#10
+ ' -n [ --testloops ] arg (=1) Number of Tests'#10
@@ -274,14 +277,15 @@
Console.WriteLine('Using anonymous pipes ('+IntToStr(Integer(setup.hAnonRead))+' and '+IntToStr(Integer(setup.hAnonWrite))+')');
end
else if s = '--transport' then begin
- // --transport arg (=sockets) Transport: buffered, framed, http, evhttp
+ // --transport arg (=sockets) Transport: buffered, framed, http, winhttp, evhttp
s := args[i];
Inc( i);
if s = 'buffered' then Include( setup.layered, trns_Buffered)
else if s = 'framed' then Include( setup.layered, trns_Framed)
- else if s = 'http' then setup.endpoint := trns_Http
- else if s = 'evhttp' then setup.endpoint := trns_EvHttp
+ else if s = 'http' then setup.endpoint := trns_MsXmlHttp
+ else if s = 'winhttp' then setup.endpoint := trns_WinHttp
+ else if s = 'evhttp' then setup.endpoint := trns_EvHttp // recognized, but not supported
else InvalidArgs;
end
else if s = '--protocol' then begin
@@ -1315,11 +1319,41 @@
end;
+function TClientThread.InitializeHttpTransport( const aTimeoutSetting : Integer) : IHTTPClient;
+var sUrl : string;
+begin
+ ASSERT( FSetup.endpoint in [trns_MsxmlHttp, trns_WinHttp]);
+
+ if FSetup.useSSL
+ then sUrl := 'https://'
+ else sUrl := 'http://';
+
+ sUrl := sUrl + FSetup.host;
+
+ 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);
+ else
+ if FSetup.port > 0 then sUrl := sUrl + ':'+ IntToStr(FSetup.port);
+ end;
+
+ Console.WriteLine('Target URL: '+sUrl);
+ case FSetup.endpoint of
+ trns_MsxmlHttp : result := TMsxmlHTTPClientImpl.Create( sUrl);
+ trns_WinHttp : result := TWinHTTPClientImpl.Create( sUrl);
+ else
+ raise Exception.Create(ENDPOINT_TRANSPORTS[FSetup.endpoint]+' unhandled case');
+ end;
+
+ result.DnsResolveTimeout := aTimeoutSetting;
+ result.ConnectionTimeout := aTimeoutSetting;
+ result.SendTimeout := aTimeoutSetting;
+ result.ReadTimeout := aTimeoutSetting;
+end;
+
+
procedure TClientThread.InitializeProtocolTransportStack;
-var
- streamtrans : IStreamTransport;
- http : IHTTPClient;
- sUrl : string;
+var streamtrans : IStreamTransport;
const
DEBUG_TIMEOUT = 30 * 1000;
RELEASE_TIMEOUT = DEFAULT_THRIFT_TIMEOUT;
@@ -1336,24 +1370,10 @@
FTransport := streamtrans;
end;
- trns_Http: begin
+ trns_MsxmlHttp,
+ trns_WinHttp: begin
Console.WriteLine('Using HTTPClient');
- if FSetup.useSSL
- then sUrl := 'https://'
- else sUrl := 'http://';
- sUrl := sUrl + FSetup.host;
- 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);
- else
- if FSetup.port > 0 then sUrl := sUrl + ':'+ IntToStr(FSetup.port);
- end;
- http := THTTPClientImpl.Create( sUrl);
- http.DnsResolveTimeout := HTTP_TIMEOUTS;
- http.ConnectionTimeout := HTTP_TIMEOUTS;
- http.SendTimeout := HTTP_TIMEOUTS;
- http.ReadTimeout := HTTP_TIMEOUTS;
- FTransport := http;
+ FTransport := InitializeHttpTransport( HTTP_TIMEOUTS);
end;
trns_EvHttp: begin
diff --git a/lib/delphi/test/TestConstants.pas b/lib/delphi/test/TestConstants.pas
index 37969dc..6bb20e9 100644
--- a/lib/delphi/test/TestConstants.pas
+++ b/lib/delphi/test/TestConstants.pas
@@ -39,7 +39,8 @@
TEndpointTransport = (
trns_Sockets,
- trns_Http,
+ trns_MsxmlHttp,
+ trns_WinHttp,
trns_NamedPipes,
trns_AnonPipes,
trns_EvHttp // as listed on http://thrift.apache.org/test
@@ -63,7 +64,7 @@
= ('Buffered', 'Framed');
ENDPOINT_TRANSPORTS : array[TEndpointTransport] of string
- = ('Sockets', 'Http', 'Named Pipes','Anon Pipes', 'EvHttp');
+ = ('Sockets', 'Http', 'WinHttp', 'Named Pipes','Anon Pipes', 'EvHttp');
// defaults are: read=false, write=true
BINARY_STRICT_READ = FALSE;
diff --git a/lib/delphi/test/TestServer.pas b/lib/delphi/test/TestServer.pas
index 69cb175..374472c 100644
--- a/lib/delphi/test/TestServer.pas
+++ b/lib/delphi/test/TestServer.pas
@@ -592,7 +592,8 @@
if s = 'buffered' then Include( layered, trns_Buffered)
else if s = 'framed' then Include( layered, trns_Framed)
- else if s = 'http' then endpoint := trns_Http
+ else if s = 'http' then endpoint := trns_MsxmlHttp
+ else if s = 'winhttp' then endpoint := trns_WinHttp
else if s = 'anonpipe' then endpoint := trns_AnonPipes
else InvalidArgs;
end
@@ -650,8 +651,9 @@
servertrans := TServerSocketImpl.Create( Port, 0, (trns_Buffered in layered));
end;
- trns_Http : begin
- raise Exception.Create(ENDPOINT_TRANSPORTS[endpoint]+' server transport not implemented');
+ trns_MsxmlHttp,
+ trns_WinHttp : begin
+ raise Exception.Create('HTTP server transport not implemented');
end;
trns_NamedPipes : begin
diff --git a/lib/delphi/test/client.dpr b/lib/delphi/test/client.dpr
index 06dbd3d..1d1607d 100644
--- a/lib/delphi/test/client.dpr
+++ b/lib/delphi/test/client.dpr
@@ -31,6 +31,8 @@
Thrift.Socket in '..\src\Thrift.Socket.pas',
Thrift.Exception in '..\src\Thrift.Exception.pas',
Thrift.Transport.Pipes in '..\src\Thrift.Transport.Pipes.pas',
+ Thrift.Transport.WinHTTP in '..\src\Thrift.Transport.WinHTTP.pas',
+ Thrift.Transport.MsxmlHTTP in '..\src\Thrift.Transport.MsxmlHTTP.pas',
Thrift.Protocol in '..\src\Thrift.Protocol.pas',
Thrift.Protocol.JSON in '..\src\Thrift.Protocol.JSON.pas',
Thrift.Protocol.Compact in '..\src\Thrift.Protocol.Compact.pas',
@@ -39,6 +41,7 @@
Thrift.Server in '..\src\Thrift.Server.pas',
Thrift.Stream in '..\src\Thrift.Stream.pas',
Thrift.TypeRegistry in '..\src\Thrift.TypeRegistry.pas',
+ Thrift.WinHTTP in '..\src\Thrift.WinHTTP.pas',
Thrift.Utils in '..\src\Thrift.Utils.pas';
var
diff --git a/lib/delphi/test/multiplexed/Multiplex.Test.Client.dpr b/lib/delphi/test/multiplexed/Multiplex.Test.Client.dpr
index 4278d8f..a57e93a 100644
--- a/lib/delphi/test/multiplexed/Multiplex.Test.Client.dpr
+++ b/lib/delphi/test/multiplexed/Multiplex.Test.Client.dpr
@@ -36,6 +36,7 @@
Thrift.Server in '..\..\src\Thrift.Server.pas',
Thrift.Stream in '..\..\src\Thrift.Stream.pas',
Thrift.TypeRegistry in '..\..\src\Thrift.TypeRegistry.pas',
+ Thrift.WinHTTP in '..\..\src\Thrift.WinHTTP.pas',
Thrift.Utils in '..\..\src\Thrift.Utils.pas';
var
diff --git a/lib/delphi/test/multiplexed/Multiplex.Test.Server.dpr b/lib/delphi/test/multiplexed/Multiplex.Test.Server.dpr
index 120462b..81ed3dd 100644
--- a/lib/delphi/test/multiplexed/Multiplex.Test.Server.dpr
+++ b/lib/delphi/test/multiplexed/Multiplex.Test.Server.dpr
@@ -36,6 +36,7 @@
Thrift.Collections in '..\..\src\Thrift.Collections.pas',
Thrift.Server in '..\..\src\Thrift.Server.pas',
Thrift.Utils in '..\..\src\Thrift.Utils.pas',
+ Thrift.WinHTTP in '..\..\src\Thrift.WinHTTP.pas',
Thrift.TypeRegistry in '..\..\src\Thrift.TypeRegistry.pas',
Thrift.Stream in '..\..\src\Thrift.Stream.pas';
diff --git a/lib/delphi/test/serializer/TestSerializer.dpr b/lib/delphi/test/serializer/TestSerializer.dpr
index 51e22a4..1f5ae8b 100644
--- a/lib/delphi/test/serializer/TestSerializer.dpr
+++ b/lib/delphi/test/serializer/TestSerializer.dpr
@@ -34,6 +34,7 @@
Thrift.Utils in '..\..\src\Thrift.Utils.pas',
Thrift.Serializer in '..\..\src\Thrift.Serializer.pas',
Thrift.Stream in '..\..\src\Thrift.Stream.pas',
+ Thrift.WinHTTP in '..\..\src\Thrift.WinHTTP.pas',
Thrift.TypeRegistry in '..\..\src\Thrift.TypeRegistry.pas',
System_,
DebugProtoTest,
diff --git a/lib/delphi/test/server.dpr b/lib/delphi/test/server.dpr
index b5e48a6..9731dd4 100644
--- a/lib/delphi/test/server.dpr
+++ b/lib/delphi/test/server.dpr
@@ -40,6 +40,7 @@
Thrift.Server in '..\src\Thrift.Server.pas',
Thrift.TypeRegistry in '..\src\Thrift.TypeRegistry.pas',
Thrift.Utils in '..\src\Thrift.Utils.pas',
+ Thrift.WinHTTP in '..\src\Thrift.WinHTTP.pas',
Thrift.Stream in '..\src\Thrift.Stream.pas';
var
diff --git a/lib/delphi/test/skip/skiptest_version1.dpr b/lib/delphi/test/skip/skiptest_version1.dpr
index 803d6bd..0bfe96f 100644
--- a/lib/delphi/test/skip/skiptest_version1.dpr
+++ b/lib/delphi/test/skip/skiptest_version1.dpr
@@ -33,6 +33,7 @@
Thrift.Collections in '..\..\src\Thrift.Collections.pas',
Thrift.Server in '..\..\src\Thrift.Server.pas',
Thrift.Utils in '..\..\src\Thrift.Utils.pas',
+ Thrift.WinHTTP in '..\..\src\Thrift.WinHTTP.pas',
Thrift.TypeRegistry in '..\..\src\Thrift.TypeRegistry.pas',
Thrift.Stream in '..\..\src\Thrift.Stream.pas';
diff --git a/lib/delphi/test/skip/skiptest_version2.dpr b/lib/delphi/test/skip/skiptest_version2.dpr
index 633b247..7893748 100644
--- a/lib/delphi/test/skip/skiptest_version2.dpr
+++ b/lib/delphi/test/skip/skiptest_version2.dpr
@@ -33,6 +33,7 @@
Thrift.Collections in '..\..\src\Thrift.Collections.pas',
Thrift.Server in '..\..\src\Thrift.Server.pas',
Thrift.Utils in '..\..\src\Thrift.Utils.pas',
+ Thrift.WinHTTP in '..\..\src\Thrift.WinHTTP.pas',
Thrift.TypeRegistry in '..\..\src\Thrift.TypeRegistry.pas',
Thrift.Stream in '..\..\src\Thrift.Stream.pas';
diff --git a/lib/delphi/test/typeregistry/TestTypeRegistry.dpr b/lib/delphi/test/typeregistry/TestTypeRegistry.dpr
index 18a7c7d..fd5e3dd 100644
--- a/lib/delphi/test/typeregistry/TestTypeRegistry.dpr
+++ b/lib/delphi/test/typeregistry/TestTypeRegistry.dpr
@@ -34,6 +34,7 @@
Thrift.Utils in '..\..\src\Thrift.Utils.pas',
Thrift.Serializer in '..\..\src\Thrift.Serializer.pas',
Thrift.Stream in '..\..\src\Thrift.Stream.pas',
+ Thrift.WinHTTP in '..\..\src\Thrift.WinHTTP.pas',
Thrift.TypeRegistry in '..\..\src\Thrift.TypeRegistry.pas',
DebugProtoTest;