blob: 6704c123c59e8636e6f443db5494d2406f7bbbf3 [file] [log] [blame]
Jens Geyer02230912019-04-03 01:12:51 +02001(*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 *)
19unit Thrift.Transport.MsxmlHTTP;
20
21{$I Thrift.Defines.inc}
22{$SCOPEDENUMS ON}
23
24interface
25
26uses
27 Classes,
28 SysUtils,
29 Math,
30 Generics.Collections,
31 {$IFDEF OLD_UNIT_NAMES}
32 ActiveX, msxml,
33 {$ELSE}
34 Winapi.ActiveX, Winapi.msxml,
35 {$ENDIF}
36 Thrift.Collections,
Jens Geyera019cda2019-11-09 23:24:52 +010037 Thrift.Configuration,
Jens Geyer02230912019-04-03 01:12:51 +020038 Thrift.Transport,
39 Thrift.Exception,
40 Thrift.Utils,
41 Thrift.Stream;
42
43type
Jens Geyera019cda2019-11-09 23:24:52 +010044 TMsxmlHTTPClientImpl = class( TEndpointTransportBase, IHTTPClient)
Jens Geyerfad7fd32019-11-09 23:24:52 +010045 strict private
Jens Geyer02230912019-04-03 01:12:51 +020046 FUri : string;
47 FInputStream : IThriftStream;
48 FOutputStream : IThriftStream;
49 FDnsResolveTimeout : Integer;
50 FConnectionTimeout : Integer;
51 FSendTimeout : Integer;
52 FReadTimeout : Integer;
53 FCustomHeaders : IThriftDictionary<string,string>;
54
55 function CreateRequest: IXMLHTTPRequest;
Jens Geyerfad7fd32019-11-09 23:24:52 +010056 strict protected
Jens Geyer02230912019-04-03 01:12:51 +020057 function GetIsOpen: Boolean; override;
58 procedure Open(); override;
59 procedure Close(); override;
60 function Read( const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer; override;
61 procedure Write( const pBuf : Pointer; off, len : Integer); override;
62 procedure Flush; override;
63
64 procedure SetDnsResolveTimeout(const Value: Integer);
65 function GetDnsResolveTimeout: Integer;
66 procedure SetConnectionTimeout(const Value: Integer);
67 function GetConnectionTimeout: Integer;
68 procedure SetSendTimeout(const Value: Integer);
69 function GetSendTimeout: Integer;
70 procedure SetReadTimeout(const Value: Integer);
71 function GetReadTimeout: Integer;
Jens Geyer47f63172019-06-06 22:42:58 +020072 function GetSecureProtocols : TSecureProtocols;
73 procedure SetSecureProtocols( const value : TSecureProtocols);
Jens Geyer02230912019-04-03 01:12:51 +020074
75 function GetCustomHeaders: IThriftDictionary<string,string>;
76 procedure SendRequest;
Jens Geyer47f63172019-06-06 22:42:58 +020077
Jens Geyer02230912019-04-03 01:12:51 +020078 property DnsResolveTimeout: Integer read GetDnsResolveTimeout write SetDnsResolveTimeout;
79 property ConnectionTimeout: Integer read GetConnectionTimeout write SetConnectionTimeout;
80 property SendTimeout: Integer read GetSendTimeout write SetSendTimeout;
81 property ReadTimeout: Integer read GetReadTimeout write SetReadTimeout;
82 property CustomHeaders: IThriftDictionary<string,string> read GetCustomHeaders;
83 public
Jens Geyera019cda2019-11-09 23:24:52 +010084 constructor Create( const aUri: string; const aConfig : IThriftConfiguration); reintroduce;
Jens Geyer02230912019-04-03 01:12:51 +020085 destructor Destroy; override;
86 end;
87
88
89implementation
90
Jens Geyera019cda2019-11-09 23:24:52 +010091const
92 XMLHTTP_CONNECTION_TIMEOUT = 60 * 1000;
93 XMLHTTP_SENDRECV_TIMEOUT = 30 * 1000;
Jens Geyer02230912019-04-03 01:12:51 +020094
95{ TMsxmlHTTPClientImpl }
96
Jens Geyera019cda2019-11-09 23:24:52 +010097constructor TMsxmlHTTPClientImpl.Create( const aUri: string; const aConfig : IThriftConfiguration);
Jens Geyer02230912019-04-03 01:12:51 +020098begin
Jens Geyera019cda2019-11-09 23:24:52 +010099 inherited Create( aConfig);
100 FUri := aUri;
Jens Geyer02230912019-04-03 01:12:51 +0200101
102 // defaults according to MSDN
103 FDnsResolveTimeout := 0; // no timeout
Jens Geyera019cda2019-11-09 23:24:52 +0100104 FConnectionTimeout := XMLHTTP_CONNECTION_TIMEOUT;
105 FSendTimeout := XMLHTTP_SENDRECV_TIMEOUT;
106 FReadTimeout := XMLHTTP_SENDRECV_TIMEOUT;
Jens Geyer02230912019-04-03 01:12:51 +0200107
108 FCustomHeaders := TThriftDictionaryImpl<string,string>.Create;
109 FOutputStream := TThriftStreamAdapterDelphi.Create( TMemoryStream.Create, True);
110end;
111
112function TMsxmlHTTPClientImpl.CreateRequest: IXMLHTTPRequest;
113var
114 pair : TPair<string,string>;
115 srvHttp : IServerXMLHTTPRequest;
116begin
117 {$IF CompilerVersion >= 21.0}
118 Result := CoServerXMLHTTP.Create;
119 {$ELSE}
120 Result := CoXMLHTTPRequest.Create;
121 {$IFEND}
122
123 // setting a timeout value to 0 (zero) means "no timeout" for that setting
124 if Supports( result, IServerXMLHTTPRequest, srvHttp)
125 then srvHttp.setTimeouts( DnsResolveTimeout, ConnectionTimeout, SendTimeout, ReadTimeout);
126
127 Result.open('POST', FUri, False, '', '');
Jens Geyer83ff7532019-06-06 22:46:03 +0200128 Result.setRequestHeader( 'Content-Type', THRIFT_MIMETYPE);
129 Result.setRequestHeader( 'Accept', THRIFT_MIMETYPE);
Jens Geyer02230912019-04-03 01:12:51 +0200130 Result.setRequestHeader( 'User-Agent', 'Delphi/IHTTPClient');
131
132 for pair in FCustomHeaders do begin
133 Result.setRequestHeader( pair.Key, pair.Value );
134 end;
135end;
136
137destructor TMsxmlHTTPClientImpl.Destroy;
138begin
139 Close;
140 inherited;
141end;
142
143function TMsxmlHTTPClientImpl.GetDnsResolveTimeout: Integer;
144begin
145 Result := FDnsResolveTimeout;
146end;
147
148procedure TMsxmlHTTPClientImpl.SetDnsResolveTimeout(const Value: Integer);
149begin
150 FDnsResolveTimeout := Value;
151end;
152
153function TMsxmlHTTPClientImpl.GetConnectionTimeout: Integer;
154begin
155 Result := FConnectionTimeout;
156end;
157
158procedure TMsxmlHTTPClientImpl.SetConnectionTimeout(const Value: Integer);
159begin
160 FConnectionTimeout := Value;
161end;
162
163function TMsxmlHTTPClientImpl.GetSendTimeout: Integer;
164begin
165 Result := FSendTimeout;
166end;
167
168procedure TMsxmlHTTPClientImpl.SetSendTimeout(const Value: Integer);
169begin
170 FSendTimeout := Value;
171end;
172
173function TMsxmlHTTPClientImpl.GetReadTimeout: Integer;
174begin
175 Result := FReadTimeout;
176end;
177
178procedure TMsxmlHTTPClientImpl.SetReadTimeout(const Value: Integer);
179begin
180 FReadTimeout := Value;
181end;
182
Jens Geyer47f63172019-06-06 22:42:58 +0200183function TMsxmlHTTPClientImpl.GetSecureProtocols : TSecureProtocols;
184begin
185 Result := [];
186end;
187
188procedure TMsxmlHTTPClientImpl.SetSecureProtocols( const value : TSecureProtocols);
189begin
190 raise TTransportExceptionBadArgs.Create('SetSecureProtocols: Not supported with '+ClassName);
191end;
192
Jens Geyer02230912019-04-03 01:12:51 +0200193function TMsxmlHTTPClientImpl.GetCustomHeaders: IThriftDictionary<string,string>;
194begin
195 Result := FCustomHeaders;
196end;
197
198function TMsxmlHTTPClientImpl.GetIsOpen: Boolean;
199begin
Jens Geyercc8c2c62021-03-29 22:38:30 +0200200 Result := Assigned(FOutputStream);
Jens Geyer02230912019-04-03 01:12:51 +0200201end;
202
203procedure TMsxmlHTTPClientImpl.Open;
204begin
205 FOutputStream := TThriftStreamAdapterDelphi.Create( TMemoryStream.Create, True);
206end;
207
208procedure TMsxmlHTTPClientImpl.Close;
209begin
210 FInputStream := nil;
211 FOutputStream := nil;
212end;
213
214procedure TMsxmlHTTPClientImpl.Flush;
215begin
216 try
217 SendRequest;
218 finally
219 FOutputStream := nil;
220 FOutputStream := TThriftStreamAdapterDelphi.Create( TMemoryStream.Create, True);
221 ASSERT( FOutputStream <> nil);
222 end;
223end;
224
225function TMsxmlHTTPClientImpl.Read( const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer;
226begin
227 if FInputStream = nil then begin
228 raise TTransportExceptionNotOpen.Create('No request has been sent');
229 end;
230
231 try
Jens Geyer41f47af2019-11-09 23:24:52 +0100232 Result := FInputStream.Read( pBuf, buflen, off, len);
Jens Geyer02230912019-04-03 01:12:51 +0200233 except
234 on E: Exception
235 do raise TTransportExceptionUnknown.Create(E.Message);
236 end;
237end;
238
239procedure TMsxmlHTTPClientImpl.SendRequest;
240var
241 xmlhttp : IXMLHTTPRequest;
242 ms : TMemoryStream;
243 a : TBytes;
244 len : Integer;
245begin
246 xmlhttp := CreateRequest;
247
248 ms := TMemoryStream.Create;
249 try
250 a := FOutputStream.ToArray;
251 len := Length(a);
252 if len > 0 then begin
253 ms.WriteBuffer( Pointer(@a[0])^, len);
254 end;
255 ms.Position := 0;
256 xmlhttp.send( IUnknown( TStreamAdapter.Create( ms, soReference )));
257 FInputStream := nil;
258 FInputStream := TThriftStreamAdapterCOM.Create( IUnknown( xmlhttp.responseStream) as IStream);
Jens Geyer036665e2021-03-29 22:36:19 +0200259 ResetConsumedMessageSize;
Jens Geyera019cda2019-11-09 23:24:52 +0100260 UpdateKnownMessageSize( FInputStream.Size);
Jens Geyer02230912019-04-03 01:12:51 +0200261 finally
262 ms.Free;
263 end;
264end;
265
266procedure TMsxmlHTTPClientImpl.Write( const pBuf : Pointer; off, len : Integer);
267begin
Jens Geyercc8c2c62021-03-29 22:38:30 +0200268 if FOutputStream <> nil
269 then FOutputStream.Write( pBuf, off, len)
270 else raise TTransportExceptionNotOpen.Create('Transport closed');
Jens Geyer02230912019-04-03 01:12:51 +0200271end;
272
273
274
275end.
276