Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Comment: | added SendTimeout and ReceiveTimeout optional parameters (in ms) to TWinHttpAPI constructors (instead of published properties which were not taken in account by the API) and to TSQLHttpClientWinHTTP / TSQLHttpClientWinINet constructors - fix for feature request [bfe485b678] |
---|---|
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
51f977e95f427b74bdd27987c1aca606 |
User & Date: | User 2014-03-31 07:09:34 |
2014-03-31
| ||
07:33 | added TTimeLogBits.FromUnixTime/FromUnixMSTime/ToUnixTime/ToUnixMSTime methods check-in: 58d6fdcc44 user: User tags: trunk | |
07:09 | added SendTimeout and ReceiveTimeout optional parameters (in ms) to TWinHttpAPI constructors (instead of published properties which were not taken in account by the API) and to TSQLHttpClientWinHTTP / TSQLHttpClientWinINet constructors - fix for feature request [bfe485b678] check-in: 51f977e95f user: User tags: trunk | |
2014-03-30
| ||
13:31 | enhanced TTimeLogBits for enhanced speed, and silent failure when value is invalid check-in: c05f0fa20a user: User tags: trunk | |
Changes to SQLite3/mORMotHttpClient.pas.
101 102 103 104 105 106 107 108 109 110 111 112 113 114 ... 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 ... 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 ... 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 ... 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 |
- classes TSQLite3HttpClient* renamed as TSQLHttpClient* - fixed TSQLHttpClientGeneric.InternalURI() method to raise an explicit exception on connection error (as expected by TSQLRestClientURI.URI) - TSQLHttpClient* classes will now handle properly reconnection in case of connection break via overriden InternalCheckOpen/InternalClose methods - introducing TSQLHttpClientGeneric.Compression property to set the handled compression schemes at runtime, i.e. SynLZ, deflate or SynLZ+SHA/AES } interface {.$define USETCPPREFIX} { if defined, a prefix will be added to the TCP/IP stream so that it won't be ................................................................................ var Header, Data, DataType: RawUTF8): Int64Rec; override; /// overriden protected method to handle HTTP connection function InternalCheckOpen: boolean; override; /// overriden protected method to close HTTP connection procedure InternalClose; override; public /// internal HTTP/1.1 compatible client property Socket: THttpClientSocket read fSocket; end; {$ifdef USEWININET} /// HTTP/1.1 RESTFUL JSON mORMot Client abstract class using either WinINet // either TWinHTTP API // - not to be called directly, but via TSQLHttpClientWinINet or (even // better) TSQLHttpClientWinHTTP overriden classes TSQLHttpClientWinGeneric = class(TSQLHttpClientGeneric) protected fWinAPI: TWinHttpAPI; fProxyName, fProxyByPass: AnsiString; fHttps: boolean; /// call fWinAPI.Request() function InternalRequest(const url, method: RawUTF8; var Header, Data, DataType: RawUTF8): Int64Rec; override; /// overriden protected method to close HTTP connection procedure InternalClose; override; /// overriden protected method to handle HTTP connection function InternalCheckOpen: boolean; override; /// create a fWinAPI instance if needed procedure InternalCreate; virtual; abstract; public /// connect to TSQLHttpServer on aServer:aPort // - optional aProxyName may contain the name of the proxy server to use, // and aProxyByPass an optional semicolon delimited list of host names or // IP addresses, or both, that should not be routed through the proxy constructor Create(const aServer, aPort: AnsiString; aModel: TSQLModel; aHttps: boolean=false; const aProxyName: AnsiString=''; const aProxyByPass: AnsiString=''); reintroduce; /// internal class instance used for the connection // - will return either a TWinINet, either a TWinHTTP class instance // - you can use this property to access to the low-level Timeout values, // for instance property WinAPI: TWinHttpAPI read fWinAPI; end; /// HTTP/1.1 RESTFUL JSON mORMot Client class using WinINet API // - this class is 15/20 times slower than TSQLHttpClient using SynCrtSock // on a local machine, but was found to be faster throughout local networks // - this class is able to connect via the secure HTTPS protocol // - it will retrieve by default the Internet Explorer proxy settings, and // display some error messages or authentification dialog on screen // - you can optionaly specify manual Proxy settings at constructor level // - by design, the WinINet API should not be used from a service // - is implemented by creating a TWinINet internal class instance TSQLHttpClientWinINet = class(TSQLHttpClientWinGeneric) protected procedure InternalCreate; override; end; {{ HTTP/1.1 RESTFUL JSON Client class using WinHTTP API - has a common behavior as THttpClientSocket() but seems to be faster over a network and is able to retrieve the current proxy settings (if available) and handle secure HTTPS connection - so it seems to be used in your client programs: TSQLHttpClient will therefore map to this class - WinHTTP does not share directly any proxy settings with Internet Explorer. ................................................................................ Vista/Seven, to configure applications using the 32 bit WinHttp settings, call netsh or proxycfg bits from %SystemRoot%\SysWOW64 folder explicitely) - you can optionaly specify manual Proxy settings at constructor level - by design, the WinHTTP API can be used from a service or a server - is implemented by creating a TWinHTTP internal class instance } TSQLHttpClientWinHTTP = class(TSQLHttpClientWinGeneric) protected procedure InternalCreate; override; end; /// HTTP/1.1 RESTFUL JSON default mORMot Client class // - under Windows, maps the TSQLHttpClientWinHTTP class TSQLHttpClient = TSQLHttpClientWinHTTP; {$else} /// HTTP/1.1 RESTFUL JSON deault mORMot Client class ................................................................................ {$ifdef USEWININET} { TSQLHttpClientWinGeneric } constructor TSQLHttpClientWinGeneric.Create(const aServer, aPort: AnsiString; aModel: TSQLModel; aHttps: boolean; const aProxyName, aProxyByPass: AnsiString); begin inherited Create(aServer,aPort,aModel); fHttps := aHttps; fProxyName := aProxyName; fProxyByPass := aProxyByPass; end; function TSQLHttpClientWinGeneric.InternalCheckOpen: boolean; begin result := false; if fWinAPI=nil then try InternalCreate; if fWinAPI<>nil then begin // note that first registered algo will be the prefered one if hcSynShaAes in Compression then // global SHA-256 / AES-256-CTR encryption + SynLZ compression fWinAPI.RegisterCompress(CompressShaAes,0); // CompressMinSize=0 if hcSynLz in Compression then // SynLZ is very fast and efficient, perfect for a Delphi Client fWinAPI.RegisterCompress(CompressSynLZ); if hcDeflate in Compression then // standard (slower) AJAX/HTTP zip/deflate compression fWinAPI.RegisterCompress(CompressDeflate); result := true; end; except on Exception do fWinAPI := nil; end else result := true; end; procedure TSQLHttpClientWinGeneric.InternalClose; begin FreeAndNil(fWinAPI); ................................................................................ Data := OutData; end; end; { TSQLHttpClientWinINet } procedure TSQLHttpClientWinINet.InternalCreate; begin fWinAPI := TWinINet.Create(fServer,fPort,fHttps,fProxyName,fProxyByPass); end; { TSQLHttpClientWinHTTP } procedure TSQLHttpClientWinHTTP.InternalCreate; begin fWinAPI := TWinHTTP.Create(fServer,fPort,fHttps,fProxyName,fProxyByPass); end; {$endif} end. |
> > > > | > > | > | > > > > > | > > < < | | | | | > > > | | > > > | | | | | | | | | | | < | | | > | | > |
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 ... 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 ... 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 ... 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 ... 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 |
- classes TSQLite3HttpClient* renamed as TSQLHttpClient* - fixed TSQLHttpClientGeneric.InternalURI() method to raise an explicit exception on connection error (as expected by TSQLRestClientURI.URI) - TSQLHttpClient* classes will now handle properly reconnection in case of connection break via overriden InternalCheckOpen/InternalClose methods - introducing TSQLHttpClientGeneric.Compression property to set the handled compression schemes at runtime, i.e. SynLZ, deflate or SynLZ+SHA/AES - added SendTimeout and ReceiveTimeout optional parameters (in ms) to TSQLHttpClientWinHTTP / TSQLHttpClientWinINet constructors [bfe485b678] } interface {.$define USETCPPREFIX} { if defined, a prefix will be added to the TCP/IP stream so that it won't be ................................................................................ var Header, Data, DataType: RawUTF8): Int64Rec; override; /// overriden protected method to handle HTTP connection function InternalCheckOpen: boolean; override; /// overriden protected method to close HTTP connection procedure InternalClose; override; public /// internal HTTP/1.1 compatible client // - can be used e.g. to access SendTimeout and ReceiveTimeout properties property Socket: THttpClientSocket read fSocket; end; {$ifdef USEWININET} /// HTTP/1.1 RESTFUL JSON mORMot Client abstract class using either WinINet // or WinHTTP API // - not to be called directly, but via TSQLHttpClientWinINet or (even // better) TSQLHttpClientWinHTTP overriden classes TSQLHttpClientWinGeneric = class(TSQLHttpClientGeneric) protected fWinAPI: TWinHttpAPI; fWinAPIClass: TWinHttpAPIClass; fProxyName, fProxyByPass: AnsiString; fSendTimeout, fReceiveTimeout: DWORD; fHttps: boolean; /// call fWinAPI.Request() function InternalRequest(const url, method: RawUTF8; var Header, Data, DataType: RawUTF8): Int64Rec; override; /// overriden protected method to close HTTP connection procedure InternalClose; override; /// overriden protected method to handle HTTP connection function InternalCheckOpen: boolean; override; /// set the fWinAPI class // - the overriden implementation should set the expected fWinAPIClass procedure InternalSetClass; virtual; abstract; public /// connect to TSQLHttpServer on aServer:aPort // - optional aProxyName may contain the name of the proxy server to use, // and aProxyByPass an optional semicolon delimited list of host names or // IP addresses, or both, that should not be routed through the proxy // - you can customize the default client timeouts by setting appropriate // SendTimeout and ReceiveTimeout parameters (in ms) - note that after // creation of this instance, the connection is tied to those initial // parameters, so we won't publish any properties to change those // initial values once created constructor Create(const aServer, aPort: AnsiString; aModel: TSQLModel; aHttps: boolean=false; const aProxyName: AnsiString=''; const aProxyByPass: AnsiString=''; SendTimeout: DWORD=HTTP_DEFAULT_SENDTIMEOUT; ReceiveTimeout: DWORD=HTTP_DEFAULT_RECEIVETIMEOUT); reintroduce; /// internal class instance used for the connection // - will return either a TWinINet, either a TWinHTTP class instance property WinAPI: TWinHttpAPI read fWinAPI; end; /// HTTP/1.1 RESTFUL JSON mORMot Client class using WinINet API // - this class is 15/20 times slower than TSQLHttpClient using SynCrtSock // on a local machine, but was found to be faster throughout local networks // - this class is able to connect via the secure HTTPS protocol // - it will retrieve by default the Internet Explorer proxy settings, and // display some error messages or authentification dialog on screen // - you can optionaly specify manual Proxy settings at constructor level // - by design, the WinINet API should not be used from a service // - is implemented by creating a TWinINet internal class instance TSQLHttpClientWinINet = class(TSQLHttpClientWinGeneric) protected procedure InternalSetClass; override; end; {{ HTTP/1.1 RESTFUL JSON Client class using WinHTTP API - has a common behavior as THttpClientSocket() but seems to be faster over a network and is able to retrieve the current proxy settings (if available) and handle secure HTTPS connection - so it seems to be used in your client programs: TSQLHttpClient will therefore map to this class - WinHTTP does not share directly any proxy settings with Internet Explorer. ................................................................................ Vista/Seven, to configure applications using the 32 bit WinHttp settings, call netsh or proxycfg bits from %SystemRoot%\SysWOW64 folder explicitely) - you can optionaly specify manual Proxy settings at constructor level - by design, the WinHTTP API can be used from a service or a server - is implemented by creating a TWinHTTP internal class instance } TSQLHttpClientWinHTTP = class(TSQLHttpClientWinGeneric) protected procedure InternalSetClass; override; end; /// HTTP/1.1 RESTFUL JSON default mORMot Client class // - under Windows, maps the TSQLHttpClientWinHTTP class TSQLHttpClient = TSQLHttpClientWinHTTP; {$else} /// HTTP/1.1 RESTFUL JSON deault mORMot Client class ................................................................................ {$ifdef USEWININET} { TSQLHttpClientWinGeneric } constructor TSQLHttpClientWinGeneric.Create(const aServer, aPort: AnsiString; aModel: TSQLModel; aHttps: boolean; const aProxyName, aProxyByPass: AnsiString; SendTimeout,ReceiveTimeout: DWORD); begin inherited Create(aServer,aPort,aModel); fHttps := aHttps; fProxyName := aProxyName; fProxyByPass := aProxyByPass; fSendTimeout := SendTimeout; fReceiveTimeout := ReceiveTimeout; end; function TSQLHttpClientWinGeneric.InternalCheckOpen: boolean; begin result := false; if fWinAPI=nil then try InternalSetClass; if fWinAPIClass=nil then raise ECommunicationException.CreateFmt('fWinAPIClass=nil for %s',[ClassName]); fWinAPI := fWinAPIClass.Create(fServer,fPort,fHttps,fProxyName,fProxyByPass, fSendTimeout,fReceiveTimeout); // note that first registered algo will be the prefered one if hcSynShaAes in Compression then // global SHA-256 / AES-256-CTR encryption + SynLZ compression fWinAPI.RegisterCompress(CompressShaAes,0); // CompressMinSize=0 if hcSynLz in Compression then // SynLZ is very fast and efficient, perfect for a Delphi Client fWinAPI.RegisterCompress(CompressSynLZ); if hcDeflate in Compression then // standard (slower) AJAX/HTTP zip/deflate compression fWinAPI.RegisterCompress(CompressDeflate); result := true; except on Exception do FreeAndNil(fWinAPI); end else result := true; end; procedure TSQLHttpClientWinGeneric.InternalClose; begin FreeAndNil(fWinAPI); ................................................................................ Data := OutData; end; end; { TSQLHttpClientWinINet } procedure TSQLHttpClientWinINet.InternalSetClass; begin fWinAPIClass := TWinINet; inherited; end; { TSQLHttpClientWinHTTP } procedure TSQLHttpClientWinHTTP.InternalSetClass; begin fWinAPIClass := TWinHTTP; inherited; end; {$endif} end. |
Changes to SynCrtSock.pas.
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 ... 221 222 223 224 225 226 227 228 229 230 231 232 233 234 .... 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 .... 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 .... 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 .... 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 .... 5284 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 .... 5486 5487 5488 5489 5490 5491 5492 5493 5494 5495 5496 5497 5498 5499 5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 .... 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 5548 5549 5550 5551 5552 5553 5554 5555 .... 5620 5621 5622 5623 5624 5625 5626 5627 5628 5629 5630 5631 5632 5633 5634 5635 5636 5637 5638 5639 5640 5641 5642 .... 5675 5676 5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 |
- WinSock-based THttpServer will avoid creating a thread per connection, when the maximum of 64 threads is reached in the pool, with an exception of kept-alife or huge body requets (avoiding DoS attacks by limiting the total number of created threads) - let WinSock-based THttpServer.Process() handle HTTP_RESP_STATICFILE - force disable range checking and other compiler options for this unit - included more detailed information to HTTP client User-Agent header - added ResolveTimeout/ConnectTimeout/SendTimeout/ReceiveTimeout properties to TWinHttpAPI classes - feature request [bfe485b678] - added optional aCompressMinSize parameter to RegisterCompress() methods - added TWinHttpAPI.Get/Post/Put/Delete() class functions for easy remote resource retrieval using either WinHTTP or WinINet APIs - added TURI structure, ready to parse a supplied HTTP URI - added 'ConnectionID: 1234578' to the HTTP headers - request [0636eeec54] - fixed ticket [82df275784] TWinHttpAPI with responses without Content-Length - fixed ticket [f0749956af] TWinINet does not work with HTTPS servers ................................................................................ {$endif} SysUtils, Classes; const /// the corresponding version of the freeware Synopse framework SYNOPSE_FRAMEWORK_VERSION = '1.18'{$ifdef LVCL}+' LVCL'{$endif}; type {$ifndef UNICODE} /// define RawByteString, as it does exist in Delphi 2009 and up // - to be used for byte storage into an AnsiString RawByteString = AnsiString; {$endif} ................................................................................ fCompress: THttpSocketCompressRecDynArray; /// set by RegisterCompress method fCompressAcceptEncoding: RawByteString; /// set index of protocol in fCompress[], from ACCEPT-ENCODING: header fCompressHeader: THttpSocketCompressSet; /// used for internal connection fSession, fConnection, fRequest: HINTERNET; fResolveTimeout: DWORD; fConnectTimeout: DWORD; fSendTimeout: DWORD; fReceiveTimeout: DWORD; procedure InternalConnect; virtual; abstract; procedure InternalRequest(const method, aURL: RawByteString); virtual; abstract; procedure InternalCloseRequest; virtual; abstract; procedure InternalAddHeader(const hdr: RawByteString); virtual; abstract; procedure InternalSendRequest(const aData: RawByteString); virtual; abstract; function InternalGetInfo(Info: DWORD): RawByteString; virtual; abstract; function InternalGetInfo32(Info: DWORD): DWORD; virtual; abstract; function InternalReadData(var Data: RawByteString; Read: integer): cardinal; virtual; abstract; class function InternalREST(const url,method,data,header: RawByteString): RawByteString; public /// connect to http://aServer:aPort or https://aServer:aPort // - optional aProxyName may contain the name of the proxy server to use, // and aProxyByPass an optional semicolon delimited list of host names or // IP addresses, or both, that should not be routed through the proxy constructor Create(const aServer, aPort: RawByteString; aHttps: boolean; const aProxyName: RawByteString=''; const aProxyByPass: RawByteString=''); /// low-level HTTP/1.1 request // - after an Create(server,port), return 200,202,204 if OK, // http status error otherwize function Request(const url, method: RawByteString; KeepAlive: cardinal; const InHeader, InData, InDataType: RawByteString; out OutHeader, OutData: RawByteString): integer; virtual; ................................................................................ /// if the remote server uses HTTPS, as specified to the class constructor property Https: boolean read fHttps; /// the remote server optional proxy, as specified to the class constructor property ProxyName: RawByteString read fProxyName; /// the remote server optional proxy by-pass list, as specified to the class // constructor property ProxyByPass: RawByteString read fProxyByPass; /// time-out time, in milliseconds, to use for name resolution // - not implemented with TWinINet class property ResolveTimeout: DWORD read fResolveTimeout write fResolveTimeout; /// time-out time, in milliseconds, to use for server connection requests property ConnectTimeout: DWORD read fConnectTimeout write fConnectTimeout; /// time-out time, in milliseconds, to use for sending requests property SendTimeout: DWORD read fSendTimeout write fSendTimeout; /// time-out time, in milliseconds, to receive a response to a request property ReceiveTimeout: DWORD read fReceiveTimeout write fReceiveTimeout; end; {/ a class to handle HTTP/1.1 request using the WinINet API - has a common behavior as THttpClientSocket() - The Microsoft Windows Internet (WinINet) application programming interface (API) enables applications to access standard Internet protocols, such as FTP and HTTP/HTTPS. - by design, the WinINet API should not be used from a service - note: WinINet is MUCH slower than THttpClientSocket: do not use this, only if you find some performance improvements on some networks } TWinINet = class(TWinHttpAPI) protected // those internal methods will raise an EWinINet exception on error procedure InternalConnect; override; procedure InternalRequest(const method, aURL: RawByteString); override; procedure InternalCloseRequest; override; procedure InternalAddHeader(const hdr: RawByteString); override; procedure InternalSendRequest(const aData: RawByteString); override; function InternalGetInfo(Info: DWORD): RawByteString; override; function InternalGetInfo32(Info: DWORD): DWORD; override; function InternalReadData(var Data: RawByteString; Read: integer): cardinal; override; ................................................................................ call netsh or proxycfg bits from %SystemRoot%\SysWOW64 folder explicitely) - Microsoft Windows HTTP Services (WinHTTP) is targeted at middle-tier and back-end server applications that require access to an HTTP client stack } TWinHTTP = class(TWinHttpAPI) private protected // those internal methods will raise an EOSError exception on error procedure InternalConnect; override; procedure InternalRequest(const method, aURL: RawByteString); override; procedure InternalCloseRequest; override; procedure InternalAddHeader(const hdr: RawByteString); override; procedure InternalSendRequest(const aData: RawByteString); override; function InternalGetInfo(Info: DWORD): RawByteString; override; function InternalGetInfo32(Info: DWORD): DWORD; override; function InternalReadData(var Data: RawByteString; Read: integer): cardinal; override; ................................................................................ TWinHttpAPIClass = class of TWinHttpAPI; /// WinHTTP exception type EWinHTTP = class(Exception); {$endif} const /// used by THttpApiServer.Request for http.sys to send a static file // - the OutCustomHeader should contain the proper 'Content-type: ....' // corresponding to the file (e.g. by calling GetMimeContentType() function // from SynCommons supplyings the file name) // - should match HTML_CONTENT_STATICFILE constant defined in mORMot.pas unit HTTP_RESP_STATICFILE = '!STATICFILE'; // some timeout default values HTTP_DEFAULT_RESOLVETIMEOUT = 0; HTTP_DEFAULT_CONNECTTIMEOUT = 60000; HTTP_DEFAULT_SENDTIMEOUT = 30000; HTTP_DEFAULT_RECEIVETIMEOUT = 30000; /// create a TCrtSocket, returning nil on error // (usefull to easily catch socket error exception ECrtSocket) function Open(const aServer, aPort: RawByteString): TCrtSocket; /// create a THttpClientSocket, returning nil on error // (usefull to easily catch socket error exception ECrtSocket) ................................................................................ { ************ WinHttp / WinINet HTTP clients } {$ifdef USEWININET} { TWinHttpAPI } constructor TWinHttpAPI.Create(const aServer, aPort: RawByteString; aHttps: boolean; const aProxyName: RawByteString=''; const aProxyByPass: RawByteString=''); begin fPort := GetCardinal(pointer(aPort)); if fPort=0 then if aHttps then fPort := INTERNET_DEFAULT_HTTPS_PORT else fPort := INTERNET_DEFAULT_HTTP_PORT; fServer := aServer; fHttps := aHttps; fProxyName := aProxyName; fProxyByPass := aProxyByPass; fResolveTimeout := HTTP_DEFAULT_RESOLVETIMEOUT; fConnectTimeout := HTTP_DEFAULT_CONNECTTIMEOUT; fSendTimeout := HTTP_DEFAULT_SENDTIMEOUT; fReceiveTimeout := HTTP_DEFAULT_RECEIVETIMEOUT; InternalConnect; // should raise an exception on error end; function TWinHttpAPI.RegisterCompress(aFunction: THttpSocketCompress; aCompressMinSize: integer): boolean; begin result := RegisterCompressFunc(fCompress,aFunction,fCompressAcceptEncoding,aCompressMinSize)<>''; end; ................................................................................ begin if fRequest<>nil then begin InternetCloseHandle(fRequest); fRequest := nil; end; end; procedure TWinINet.InternalConnect; var OpenType: integer; begin if fProxyName='' then OpenType := INTERNET_OPEN_TYPE_PRECONFIG else OpenType := INTERNET_OPEN_TYPE_PROXY; fSession := InternetOpenA(Pointer(DefaultUserAgent(self)), OpenType, pointer(fProxyName), pointer(fProxyByPass), 0); if fSession=nil then raise EWinINet.Create; fConnection := InternetConnectA(fSession, pointer(fServer), fPort, nil, nil, INTERNET_SERVICE_HTTP, 0, 0); if fConnection=nil then raise EWinINet.Create; end; function TWinINet.InternalGetInfo(Info: DWORD): RawByteString; ................................................................................ raise EWinINet.Create; end; procedure TWinINet.InternalRequest(const method, aURL: RawByteString); const ALL_ACCEPT: array[0..1] of PAnsiChar = ('*/*',nil); var Flags: DWORD; begin InternetSetOption(fConnection,INTERNET_OPTION_CONNECT_TIMEOUT, @fConnectTimeout,SizeOf(fConnectTimeout)); InternetSetOption(fConnection,INTERNET_OPTION_SEND_TIMEOUT, @fSendTimeout,SizeOf(fSendTimeout)); InternetSetOption(fConnection,INTERNET_OPTION_RECEIVE_TIMEOUT, @fReceiveTimeout,SizeOf(fReceiveTimeout)); Flags := INTERNET_FLAG_HYPERLINK or INTERNET_FLAG_PRAGMA_NOCACHE or INTERNET_FLAG_RESYNCHRONIZE; // options for a true RESTful request if fKeepAlive<>0 then Flags := Flags or INTERNET_FLAG_KEEP_CONNECTION; if fHttps then Flags := Flags or INTERNET_FLAG_SECURE; FRequest := HttpOpenRequestA(FConnection, Pointer(method), Pointer(aURL), nil, ................................................................................ begin if fRequest<>nil then begin WinHttpCloseHandle(fRequest); FRequest := nil; end; end; procedure TWinHTTP.InternalConnect; var OpenType: integer; begin if fProxyName='' then OpenType := WINHTTP_ACCESS_TYPE_DEFAULT_PROXY else OpenType := WINHTTP_ACCESS_TYPE_NAMED_PROXY; fSession := WinHttpOpen(pointer(Ansi7ToUnicode(DefaultUserAgent(self))), OpenType, pointer(Ansi7ToUnicode(fProxyName)), pointer(Ansi7ToUnicode(fProxyByPass)), 0); if fSession=nil then RaiseLastOSError; fConnection := WinHttpConnect(fSession, pointer(Ansi7ToUnicode(FServer)), fPort, 0); if fConnection=nil then RaiseLastOSError; end; function TWinHTTP.InternalGetInfo(Info: DWORD): RawByteString; ................................................................................ RaiseLastOSError; end; procedure TWinHTTP.InternalRequest(const method, aURL: RawByteString); const ALL_ACCEPT: array[0..1] of PWideChar = ('*/*',nil); var Flags: DWORD; begin // cf. http://msdn.microsoft.com/en-us/library/windows/desktop/aa384116 if not WinHttpSetTimeouts(fSession,fResolveTimeout,fConnectTimeout,fSendTimeout,fReceiveTimeout) then RaiseLastOSError; Flags := WINHTTP_FLAG_REFRESH; // options for a true RESTful request if fHttps then Flags := Flags or WINHTTP_FLAG_SECURE; fRequest := WinHttpOpenRequest(fConnection, pointer(Ansi7ToUnicode(method)), pointer(Ansi7ToUnicode(aURL)), nil, nil, @ALL_ACCEPT, Flags); if fRequest=nil then RaiseLastOSError; |
| | > > > > > > > > > > > > > > > > > > > > > > > > < < < | < > > > > > | > > < < < < < < < < < | | < < < < < < < < < < < < < < | < < < < | | > > > > < < < < < < | > > > > < < < |
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 ... 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 .... 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 .... 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 .... 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 .... 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 .... 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 .... 5486 5487 5488 5489 5490 5491 5492 5493 5494 5495 5496 5497 5498 5499 5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 .... 5540 5541 5542 5543 5544 5545 5546 5547 5548 5549 5550 5551 5552 5553 .... 5618 5619 5620 5621 5622 5623 5624 5625 5626 5627 5628 5629 5630 5631 5632 5633 5634 5635 5636 5637 5638 5639 5640 5641 5642 5643 5644 .... 5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 |
- WinSock-based THttpServer will avoid creating a thread per connection, when the maximum of 64 threads is reached in the pool, with an exception of kept-alife or huge body requets (avoiding DoS attacks by limiting the total number of created threads) - let WinSock-based THttpServer.Process() handle HTTP_RESP_STATICFILE - force disable range checking and other compiler options for this unit - included more detailed information to HTTP client User-Agent header - added SendTimeout and ReceiveTimeout optional parameters to TWinHttpAPI constructors - feature request [bfe485b678] - added optional aCompressMinSize parameter to RegisterCompress() methods - added TWinHttpAPI.Get/Post/Put/Delete() class functions for easy remote resource retrieval using either WinHTTP or WinINet APIs - added TURI structure, ready to parse a supplied HTTP URI - added 'ConnectionID: 1234578' to the HTTP headers - request [0636eeec54] - fixed ticket [82df275784] TWinHttpAPI with responses without Content-Length - fixed ticket [f0749956af] TWinINet does not work with HTTPS servers ................................................................................ {$endif} SysUtils, Classes; const /// the corresponding version of the freeware Synopse framework SYNOPSE_FRAMEWORK_VERSION = '1.18'{$ifdef LVCL}+' LVCL'{$endif}; /// used by THttpApiServer.Request for http.sys to send a static file // - the OutCustomHeader should contain the proper 'Content-type: ....' // corresponding to the file (e.g. by calling GetMimeContentType() function // from SynCommons supplyings the file name) // - should match HTML_CONTENT_STATICFILE constant defined in mORMot.pas unit HTTP_RESP_STATICFILE = '!STATICFILE'; /// TWinHttpAPI timeout default value for DNS resolution // - leaving to 0 will let system default value be used HTTP_DEFAULT_RESOLVETIMEOUT = 0; /// TWinHttpAPI timeout default value for remote connection // - default is 60 seconds HTTP_DEFAULT_CONNECTTIMEOUT = 60000; /// TWinHttpAPI timeout default value for data sending // - default is 30 seconds // - you can override this value by setting the corresponding parameter in // TWinHttpAPI.Create() constructor HTTP_DEFAULT_SENDTIMEOUT = 30000; /// TWinHttpAPI timeout default value for data receiving // - default is 30 seconds // - you can override this value by setting the corresponding parameter in // TWinHttpAPI.Create() constructor HTTP_DEFAULT_RECEIVETIMEOUT = 30000; type {$ifndef UNICODE} /// define RawByteString, as it does exist in Delphi 2009 and up // - to be used for byte storage into an AnsiString RawByteString = AnsiString; {$endif} ................................................................................ fCompress: THttpSocketCompressRecDynArray; /// set by RegisterCompress method fCompressAcceptEncoding: RawByteString; /// set index of protocol in fCompress[], from ACCEPT-ENCODING: header fCompressHeader: THttpSocketCompressSet; /// used for internal connection fSession, fConnection, fRequest: HINTERNET; procedure InternalConnect(SendTimeout,ReceiveTimeout: DWORD); virtual; abstract; procedure InternalRequest(const method, aURL: RawByteString); virtual; abstract; procedure InternalCloseRequest; virtual; abstract; procedure InternalAddHeader(const hdr: RawByteString); virtual; abstract; procedure InternalSendRequest(const aData: RawByteString); virtual; abstract; function InternalGetInfo(Info: DWORD): RawByteString; virtual; abstract; function InternalGetInfo32(Info: DWORD): DWORD; virtual; abstract; function InternalReadData(var Data: RawByteString; Read: integer): cardinal; virtual; abstract; class function InternalREST(const url,method,data,header: RawByteString): RawByteString; public /// connect to http://aServer:aPort or https://aServer:aPort // - optional aProxyName may contain the name of the proxy server to use, // and aProxyByPass an optional semicolon delimited list of host names or // IP addresses, or both, that should not be routed through the proxy // - you can customize the default client timeouts by setting appropriate // SendTimeout and ReceiveTimeout parameters (in ms) - note that after // creation of this instance, the connection is tied to the initial // parameters, so we won't publish any properties to change those // initial values once created constructor Create(const aServer, aPort: RawByteString; aHttps: boolean; const aProxyName: RawByteString=''; const aProxyByPass: RawByteString=''; SendTimeout: DWORD=HTTP_DEFAULT_SENDTIMEOUT; ReceiveTimeout: DWORD=HTTP_DEFAULT_RECEIVETIMEOUT); /// low-level HTTP/1.1 request // - after an Create(server,port), return 200,202,204 if OK, // http status error otherwize function Request(const url, method: RawByteString; KeepAlive: cardinal; const InHeader, InData, InDataType: RawByteString; out OutHeader, OutData: RawByteString): integer; virtual; ................................................................................ /// if the remote server uses HTTPS, as specified to the class constructor property Https: boolean read fHttps; /// the remote server optional proxy, as specified to the class constructor property ProxyName: RawByteString read fProxyName; /// the remote server optional proxy by-pass list, as specified to the class // constructor property ProxyByPass: RawByteString read fProxyByPass; end; {/ a class to handle HTTP/1.1 request using the WinINet API - has a common behavior as THttpClientSocket() - The Microsoft Windows Internet (WinINet) application programming interface (API) enables applications to access standard Internet protocols, such as FTP and HTTP/HTTPS. - by design, the WinINet API should not be used from a service - note: WinINet is MUCH slower than THttpClientSocket: do not use this, only if you find some performance improvements on some networks } TWinINet = class(TWinHttpAPI) protected // those internal methods will raise an EWinINet exception on error procedure InternalConnect(SendTimeout,ReceiveTimeout: DWORD); override; procedure InternalRequest(const method, aURL: RawByteString); override; procedure InternalCloseRequest; override; procedure InternalAddHeader(const hdr: RawByteString); override; procedure InternalSendRequest(const aData: RawByteString); override; function InternalGetInfo(Info: DWORD): RawByteString; override; function InternalGetInfo32(Info: DWORD): DWORD; override; function InternalReadData(var Data: RawByteString; Read: integer): cardinal; override; ................................................................................ call netsh or proxycfg bits from %SystemRoot%\SysWOW64 folder explicitely) - Microsoft Windows HTTP Services (WinHTTP) is targeted at middle-tier and back-end server applications that require access to an HTTP client stack } TWinHTTP = class(TWinHttpAPI) private protected // those internal methods will raise an EOSError exception on error procedure InternalConnect(SendTimeout,ReceiveTimeout: DWORD); override; procedure InternalRequest(const method, aURL: RawByteString); override; procedure InternalCloseRequest; override; procedure InternalAddHeader(const hdr: RawByteString); override; procedure InternalSendRequest(const aData: RawByteString); override; function InternalGetInfo(Info: DWORD): RawByteString; override; function InternalGetInfo32(Info: DWORD): DWORD; override; function InternalReadData(var Data: RawByteString; Read: integer): cardinal; override; ................................................................................ TWinHttpAPIClass = class of TWinHttpAPI; /// WinHTTP exception type EWinHTTP = class(Exception); {$endif} /// create a TCrtSocket, returning nil on error // (usefull to easily catch socket error exception ECrtSocket) function Open(const aServer, aPort: RawByteString): TCrtSocket; /// create a THttpClientSocket, returning nil on error // (usefull to easily catch socket error exception ECrtSocket) ................................................................................ { ************ WinHttp / WinINet HTTP clients } {$ifdef USEWININET} { TWinHttpAPI } constructor TWinHttpAPI.Create(const aServer, aPort: RawByteString; aHttps: boolean; const aProxyName,aProxyByPass: RawByteString; SendTimeout,ReceiveTimeout: DWORD); begin fPort := GetCardinal(pointer(aPort)); if fPort=0 then if aHttps then fPort := INTERNET_DEFAULT_HTTPS_PORT else fPort := INTERNET_DEFAULT_HTTP_PORT; fServer := aServer; fHttps := aHttps; fProxyName := aProxyName; fProxyByPass := aProxyByPass; InternalConnect(SendTimeout,ReceiveTimeout); // should raise an exception on error end; function TWinHttpAPI.RegisterCompress(aFunction: THttpSocketCompress; aCompressMinSize: integer): boolean; begin result := RegisterCompressFunc(fCompress,aFunction,fCompressAcceptEncoding,aCompressMinSize)<>''; end; ................................................................................ begin if fRequest<>nil then begin InternetCloseHandle(fRequest); fRequest := nil; end; end; procedure TWinINet.InternalConnect(SendTimeout,ReceiveTimeout: DWORD); var OpenType: integer; begin if fProxyName='' then OpenType := INTERNET_OPEN_TYPE_PRECONFIG else OpenType := INTERNET_OPEN_TYPE_PROXY; fSession := InternetOpenA(Pointer(DefaultUserAgent(self)), OpenType, pointer(fProxyName), pointer(fProxyByPass), 0); if fSession=nil then raise EWinINet.Create; InternetSetOption(fConnection,INTERNET_OPTION_SEND_TIMEOUT, @SendTimeout,SizeOf(SendTimeout)); InternetSetOption(fConnection,INTERNET_OPTION_RECEIVE_TIMEOUT, @ReceiveTimeout,SizeOf(ReceiveTimeout)); fConnection := InternetConnectA(fSession, pointer(fServer), fPort, nil, nil, INTERNET_SERVICE_HTTP, 0, 0); if fConnection=nil then raise EWinINet.Create; end; function TWinINet.InternalGetInfo(Info: DWORD): RawByteString; ................................................................................ raise EWinINet.Create; end; procedure TWinINet.InternalRequest(const method, aURL: RawByteString); const ALL_ACCEPT: array[0..1] of PAnsiChar = ('*/*',nil); var Flags: DWORD; begin Flags := INTERNET_FLAG_HYPERLINK or INTERNET_FLAG_PRAGMA_NOCACHE or INTERNET_FLAG_RESYNCHRONIZE; // options for a true RESTful request if fKeepAlive<>0 then Flags := Flags or INTERNET_FLAG_KEEP_CONNECTION; if fHttps then Flags := Flags or INTERNET_FLAG_SECURE; FRequest := HttpOpenRequestA(FConnection, Pointer(method), Pointer(aURL), nil, ................................................................................ begin if fRequest<>nil then begin WinHttpCloseHandle(fRequest); FRequest := nil; end; end; procedure TWinHTTP.InternalConnect(SendTimeout,ReceiveTimeout: DWORD); var OpenType: integer; begin if fProxyName='' then OpenType := WINHTTP_ACCESS_TYPE_DEFAULT_PROXY else OpenType := WINHTTP_ACCESS_TYPE_NAMED_PROXY; fSession := WinHttpOpen(pointer(Ansi7ToUnicode(DefaultUserAgent(self))), OpenType, pointer(Ansi7ToUnicode(fProxyName)), pointer(Ansi7ToUnicode(fProxyByPass)), 0); if fSession=nil then RaiseLastOSError; // cf. http://msdn.microsoft.com/en-us/library/windows/desktop/aa384116 if not WinHttpSetTimeouts(fSession,HTTP_DEFAULT_RESOLVETIMEOUT, HTTP_DEFAULT_CONNECTTIMEOUT,SendTimeout,ReceiveTimeout) then RaiseLastOSError; fConnection := WinHttpConnect(fSession, pointer(Ansi7ToUnicode(FServer)), fPort, 0); if fConnection=nil then RaiseLastOSError; end; function TWinHTTP.InternalGetInfo(Info: DWORD): RawByteString; ................................................................................ RaiseLastOSError; end; procedure TWinHTTP.InternalRequest(const method, aURL: RawByteString); const ALL_ACCEPT: array[0..1] of PWideChar = ('*/*',nil); var Flags: DWORD; begin Flags := WINHTTP_FLAG_REFRESH; // options for a true RESTful request if fHttps then Flags := Flags or WINHTTP_FLAG_SECURE; fRequest := WinHttpOpenRequest(fConnection, pointer(Ansi7ToUnicode(method)), pointer(Ansi7ToUnicode(aURL)), nil, nil, @ALL_ACCEPT, Flags); if fRequest=nil then RaiseLastOSError; |