Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Comment: | can make TCP/IP stream not HTTP compliant (against antivirus slowdown) |
---|---|
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
9098c15a115c3df6a3b48b6ce7fb89f2 |
User & Date: | ab 2011-03-02 08:12:54 |
2011-03-02
| ||
13:58 | added horizontal scaling for GDI enumeration in case of text kerning (could occur for small fonts) check-in: 66177c6117 user: ab tags: trunk | |
08:12 | can make TCP/IP stream not HTTP compliant (against antivirus slowdown) check-in: 9098c15a11 user: ab tags: trunk | |
2011-03-01
| ||
19:13 | compatibility fix for Delphi 2009/2010/XE check-in: f35f39f17a user: ab tags: trunk | |
Changes to SQLite3/SQLite3HttpClient.pas.
77 78 79 80 81 82 83 84 85 86 87 88 89 90 .. 96 97 98 99 100 101 102 103 104 105 106 107 108 109 ... 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
Version 1.13 - now can compress its content using deflate or faster SynLZ algorithm: by default, the SynLZ algorithm will be used between a Delphi Client and Server over HTTP/1.1 - there will be no speed penalty on the server side, whereas deflate would use much more CPU - by default, will handle SynLZ compression for TSQLite3HttpServer } interface {$define COMPRESSSYNLZ} { if defined, will use SynLZ for content compression ................................................................................ - is defined by default for a Delphi client } {.$define COMPRESSDEFLATE} { if defined, will use deflate/zip for content compression - can be set globally for Client and Server applications - not defined by default for a Delphi client (SynLZ is more convenient) } uses Windows, SysUtils, {$ifdef COMPRESSDEFLATE} SynZip, {$endif} {$ifdef COMPRESSSYNLZ} ................................................................................ { TSQLite3HttpClient } constructor TSQLite3HttpClient.Create(const aServer, aPort: AnsiString; aModel: TSQLModel); begin inherited Create(aModel); fSocket := THttpClientSocket.Open(aServer,aPort); KeepAliveMS := 20000; // 20 seconds connection keep alive by default {$ifdef COMPRESSSYNLZ} // SynLZ is very fast and efficient, perfect for a Delphi Client fSocket.RegisterCompress(CompressSynLZ); {$endif} {$ifdef COMPRESSDEFLATE} fSocket.RegisterCompress(CompressDeflate); |
> > > > > > > > > > > |
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 .. 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 ... 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
Version 1.13 - now can compress its content using deflate or faster SynLZ algorithm: by default, the SynLZ algorithm will be used between a Delphi Client and Server over HTTP/1.1 - there will be no speed penalty on the server side, whereas deflate would use much more CPU - by default, will handle SynLZ compression for TSQLite3HttpServer - can make TCP/IP stream not HTTP compliant (against antivirus slowdown) } interface {$define COMPRESSSYNLZ} { if defined, will use SynLZ for content compression ................................................................................ - is defined by default for a Delphi client } {.$define COMPRESSDEFLATE} { if defined, will use deflate/zip for content compression - can be set globally for Client and Server applications - not defined by default for a Delphi client (SynLZ is more convenient) } {.$define USETCPPREFIX} { if defined, a prefix will be added to the TCP/IP stream so that it won't be valid HTTP content any more: it could increase the client/server speed with some anti-virus software, but the remote access won't work any more with Internet Browsers nor AJAX applications - not defined by default - should be set globally to the project conditionals } uses Windows, SysUtils, {$ifdef COMPRESSDEFLATE} SynZip, {$endif} {$ifdef COMPRESSSYNLZ} ................................................................................ { TSQLite3HttpClient } constructor TSQLite3HttpClient.Create(const aServer, aPort: AnsiString; aModel: TSQLModel); begin inherited Create(aModel); fSocket := THttpClientSocket.Open(aServer,aPort); {$ifdef USETCPPREFIX} fSocket.TCPPrefix := 'magic'; {$endif} KeepAliveMS := 20000; // 20 seconds connection keep alive by default {$ifdef COMPRESSSYNLZ} // SynLZ is very fast and efficient, perfect for a Delphi Client fSocket.RegisterCompress(CompressSynLZ); {$endif} {$ifdef COMPRESSDEFLATE} fSocket.RegisterCompress(CompressDeflate); |
Changes to SQLite3/SQLite3HttpServer.pas.
85 86 87 88 89 90 91 92 93 94 95 96 97 98 ... 106 107 108 109 110 111 112 113 114 115 116 117 118 119 ... 325 326 327 328 329 330 331 332 333 334 335 336 337 338 |
per one server (dispatching requests via the Root URI used) - new AddServer method, to register a TSQLRestServer after launch - new TSQLRestServer.OnlyJSONRequests property Version 1.13 - now can compress its content using deflate or faster SynLZ algorithm - by default, will handle SynLZ compression for TSQLite3HttpClient } interface {$define COMPRESSSYNLZ} { if defined, will use SynLZ for content compression - SynLZ is much faster than deflate/zip, so is preferred ................................................................................ { if defined, will use deflate/zip for content compression - can be set global for Client and Server applications - SynLZ is faster but only known by Delphi clients: you can enable deflate when the server is connected an AJAX application (not defined by default) - if you define both COMPRESSSYNLZ and COMPRESSDEFLATE, the server will use SynLZ if available, and deflate if not called from a Delphi client } {.$define HTTPEMBEDSQLITE3} { if defined, some additional methods will be included, in order to initialize directly a SQLite3 database engine -> it's cleaner to instantiate the TSQLRestServerDB instance first, then assign it to the TSQLite3HttpServer -> don't define it, even for TTestSQLite3Remote or TestSQL3.dpr } ................................................................................ if aServers[j].Model.Root=Root then ErrMsg:= 'Duplicated Root URI'; if ErrMsg<>'' then raise Exception.Create('TSQLite3HttpServer.Create: '+ErrMsg); SetLength(fDBServers,length(aServers)); for i := 0 to high(aServers) do fDBServers[i] := aServers[i]; {$ifdef COMPRESSSYNLZ} RegisterCompress(CompressSynLZ); {$endif} {$ifdef COMPRESSDEFLATE} RegisterCompress(CompressDeflate); {$endif} end; |
> > > > > > > > > > > |
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 ... 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 ... 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 |
per one server (dispatching requests via the Root URI used) - new AddServer method, to register a TSQLRestServer after launch - new TSQLRestServer.OnlyJSONRequests property Version 1.13 - now can compress its content using deflate or faster SynLZ algorithm - by default, will handle SynLZ compression for TSQLite3HttpClient - can make TCP/IP stream not HTTP compliant (against antivirus slowdown) } interface {$define COMPRESSSYNLZ} { if defined, will use SynLZ for content compression - SynLZ is much faster than deflate/zip, so is preferred ................................................................................ { if defined, will use deflate/zip for content compression - can be set global for Client and Server applications - SynLZ is faster but only known by Delphi clients: you can enable deflate when the server is connected an AJAX application (not defined by default) - if you define both COMPRESSSYNLZ and COMPRESSDEFLATE, the server will use SynLZ if available, and deflate if not called from a Delphi client } {.$define USETCPPREFIX} { if defined, a prefix will be added to the TCP/IP stream so that it won't be valid HTTP content any more: it could increase the client/server speed with some anti-virus software, but the remote access won't work any more with Internet Browsers nor AJAX applications - not defined by default - should be set globally to the project conditionals } {.$define HTTPEMBEDSQLITE3} { if defined, some additional methods will be included, in order to initialize directly a SQLite3 database engine -> it's cleaner to instantiate the TSQLRestServerDB instance first, then assign it to the TSQLite3HttpServer -> don't define it, even for TTestSQLite3Remote or TestSQL3.dpr } ................................................................................ if aServers[j].Model.Root=Root then ErrMsg:= 'Duplicated Root URI'; if ErrMsg<>'' then raise Exception.Create('TSQLite3HttpServer.Create: '+ErrMsg); SetLength(fDBServers,length(aServers)); for i := 0 to high(aServers) do fDBServers[i] := aServers[i]; {$ifdef USETCPPREFIX} TCPPrefix := 'magic'; {$endif} {$ifdef COMPRESSSYNLZ} RegisterCompress(CompressSynLZ); {$endif} {$ifdef COMPRESSDEFLATE} RegisterCompress(CompressDeflate); {$endif} end; |
Changes to SynCrtSock.pas.
309 310 311 312 313 314 315 316 317 318 319 320 321 322 ... 500 501 502 503 504 505 506 507 508 509 510 511 512 513 .... 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 .... 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 .... 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 .... 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 .... 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 |
/// decode 'CONTENT-ENCODING: ' parameter procedure SetfCompressHeader(P: PAnsiChar); /// retrieve the HTTP headers into Headers[] and fill most properties below procedure GetHeader; /// retrieve the HTTP body (after uncompression if necessary) into Content procedure GetBody; public /// will contain the first header line: // - 'GET /path HTTP/1.1' for a GET request with THttpServer, e.g. // - 'HTTP/1.0 200 OK' for a GET response after Get() e.g. Command: TSockData; /// will contain the header lines after a Request - use HeaderValue() to get one Headers: array of TSockData; /// will contain the data retrieved from the server, after the Request ................................................................................ Sock: TCrtSocket; /// will contain the total number of connection to the server // - it's the global count since the server started ServerConnectionCount: cardinal; /// time, in milliseconds, for the HTTP.1/1 connections to be kept alive; // default is 3000 ms ServerKeepAliveTimeOut: cardinal; /// create a Server Thread, binded and listening on a port // - this constructor will raise a EHttpServer exception if binding failed // - you can specify a number of threads to be initialized to handle // incoming connections (default is 32, which may be sufficient for most // cases, maximum is 64) constructor Create(const aPort: AnsiString ................................................................................ DoRetry(404) else // socket closed (e.g. KeepAlive=0) -> reconnect try try {$ifdef DEBUG23}system.write(' Send');{$endif} // send request - we use SockSend because writeln() is calling flush() // -> all header will be sent at once DataLen := length(Data); SockSend([method, ' ', url, ' HTTP/1.1'#13#10+ 'Accept: */*'#13#10'Host: ', Server]); if UserAgent='' then SockSend('User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows; FREE)') else SockSend(['User-Agent: ',UserAgent]); // for POST/PUT: always put content byte count to be sent (even 0) SockSend(['Content-Length: ', DataLen]); ................................................................................ {$ifdef DEBUG23} SndBuf[SndBufLen+1] := #0; system.Writeln(#13#10'HeaderOut ',PAnsiChar(SndBuf));{$endif} SockSendFlush; // flush all pending data (i.e. headers) to network if DataLen<>0 then // for POST and PUT methods: content to be sent SndLow(pointer(Data),DataLen); // no CRLF at the end of data {$ifdef DEBUG23}system.write('OK ');{$endif} // get headers SockRecvLn(Command); // will raise ECrtSocket on any error {$ifdef DEBUG23}system.write(Command);{$endif} P := pointer(Command); if IdemPChar(P,'HTTP/1.') then begin if P[7]='0' then KeepAlive := 0; // HTTP/1.0 -> force connection close inc(P,9); result := GetCardinal(P); // get http numeric status code ................................................................................ if not(Code in [200,201]) and (Data='') then begin Setlength(ClientSock.Headers,0); ClientSock.ContentType := 'text/html'; // create message to display Data := TSockData(ClassName+' Server Error '+IntToStr(Code) +'<hr>'+StringReplace(string(s),#13#10,'<br>',[rfReplaceAll])); end; // 1. send HTTP status command if ClientSock.KeepAliveClient then ClientSock.SockSend(['HTTP/1.1 ',Code,' OK']) else ClientSock.SockSend(['HTTP/1.0 ',Code,' OK']); // 2. send headers // 2.1. custom headers from Request() method for i := 0 to high(ClientSock.Headers) do begin s := ClientSock.Headers[i]; ................................................................................ var P: PAnsiChar; StartTix, EndTix: cardinal; begin try StartTix := GetTickCount; // 1st line is command: 'GET /path HTTP/1.1' e.g. SockRecvLn(Command); P := pointer(Command); Method := GetNextItem(P,' '); // 'GET' URL := GetNextItem(P,' '); // '/path' KeepAliveClient := IdemPChar(P,'HTTP/1.1'); Content := ''; // get headers and content GetHeader; ................................................................................ end; constructor THttpServerSocket.Create(aServer: THttpServer); var i: integer; begin inherited Create; if aServer<>nil then for i := 0 to aServer.fCompress.Count-1 do RegisterCompress(aServer.fCompress[i]); end; { ECrtSocket } constructor ECrtSocket.Create(const Msg: string); begin inherited CreateFmt('%s %d',[Msg,WSAGetLastError]); |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > |
309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 ... 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 .... 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 .... 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 .... 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 .... 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 .... 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 |
/// decode 'CONTENT-ENCODING: ' parameter procedure SetfCompressHeader(P: PAnsiChar); /// retrieve the HTTP headers into Headers[] and fill most properties below procedure GetHeader; /// retrieve the HTTP body (after uncompression if necessary) into Content procedure GetBody; public /// TCP/IP prefix to mask HTTP protocol // - if not set, will create full HTTP/1.0 or HTTP/1.1 compliant content // - in order to make the TCP/IP stream not HTTP compliant, you can specify // a prefix which will be put before the first header line: in this case, // the TCP/IP stream won't be recognized as HTTP, and will be ignored by // most AntiVirus programs, and increase security - but you won't be able // to use an Internet Browser nor AJAX application for remote access any more TCPPrefix: TSockData; /// will contain the first header line: // - 'GET /path HTTP/1.1' for a GET request with THttpServer, e.g. // - 'HTTP/1.0 200 OK' for a GET response after Get() e.g. Command: TSockData; /// will contain the header lines after a Request - use HeaderValue() to get one Headers: array of TSockData; /// will contain the data retrieved from the server, after the Request ................................................................................ Sock: TCrtSocket; /// will contain the total number of connection to the server // - it's the global count since the server started ServerConnectionCount: cardinal; /// time, in milliseconds, for the HTTP.1/1 connections to be kept alive; // default is 3000 ms ServerKeepAliveTimeOut: cardinal; /// TCP/IP prefix to mask HTTP protocol // - if not set, will create full HTTP/1.0 or HTTP/1.1 compliant content // - in order to make the TCP/IP stream not HTTP compliant, you can specify // a prefix which will be put before the first header line: in this case, // the TCP/IP stream won't be recognized as HTTP, and will be ignored by // most AntiVirus programs, and increase security - but you won't be able // to use an Internet Browser nor AJAX application for remote access any more TCPPrefix: TSockData; /// create a Server Thread, binded and listening on a port // - this constructor will raise a EHttpServer exception if binding failed // - you can specify a number of threads to be initialized to handle // incoming connections (default is 32, which may be sufficient for most // cases, maximum is 64) constructor Create(const aPort: AnsiString ................................................................................ DoRetry(404) else // socket closed (e.g. KeepAlive=0) -> reconnect try try {$ifdef DEBUG23}system.write(' Send');{$endif} // send request - we use SockSend because writeln() is calling flush() // -> all header will be sent at once DataLen := length(Data); if TCPPrefix<>'' then SockSend(TCPPrefix); SockSend([method, ' ', url, ' HTTP/1.1'#13#10+ 'Accept: */*'#13#10'Host: ', Server]); if UserAgent='' then SockSend('User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows; FREE)') else SockSend(['User-Agent: ',UserAgent]); // for POST/PUT: always put content byte count to be sent (even 0) SockSend(['Content-Length: ', DataLen]); ................................................................................ {$ifdef DEBUG23} SndBuf[SndBufLen+1] := #0; system.Writeln(#13#10'HeaderOut ',PAnsiChar(SndBuf));{$endif} SockSendFlush; // flush all pending data (i.e. headers) to network if DataLen<>0 then // for POST and PUT methods: content to be sent SndLow(pointer(Data),DataLen); // no CRLF at the end of data {$ifdef DEBUG23}system.write('OK ');{$endif} // get headers SockRecvLn(Command); // will raise ECrtSocket on any error if TCPPrefix<>'' then if Command<>TCPPrefix then begin result := 505; exit; end else SockRecvLn(Command); {$ifdef DEBUG23}system.write(Command);{$endif} P := pointer(Command); if IdemPChar(P,'HTTP/1.') then begin if P[7]='0' then KeepAlive := 0; // HTTP/1.0 -> force connection close inc(P,9); result := GetCardinal(P); // get http numeric status code ................................................................................ if not(Code in [200,201]) and (Data='') then begin Setlength(ClientSock.Headers,0); ClientSock.ContentType := 'text/html'; // create message to display Data := TSockData(ClassName+' Server Error '+IntToStr(Code) +'<hr>'+StringReplace(string(s),#13#10,'<br>',[rfReplaceAll])); end; // 1. send HTTP status command if ClientSock.TCPPrefix<>'' then ClientSock.SockSend(ClientSock.TCPPrefix); if ClientSock.KeepAliveClient then ClientSock.SockSend(['HTTP/1.1 ',Code,' OK']) else ClientSock.SockSend(['HTTP/1.0 ',Code,' OK']); // 2. send headers // 2.1. custom headers from Request() method for i := 0 to high(ClientSock.Headers) do begin s := ClientSock.Headers[i]; ................................................................................ var P: PAnsiChar; StartTix, EndTix: cardinal; begin try StartTix := GetTickCount; // 1st line is command: 'GET /path HTTP/1.1' e.g. SockRecvLn(Command); if TCPPrefix<>'' then if TCPPrefix<>Command then begin result := false; exit end else SockRecvLn(Command); P := pointer(Command); Method := GetNextItem(P,' '); // 'GET' URL := GetNextItem(P,' '); // '/path' KeepAliveClient := IdemPChar(P,'HTTP/1.1'); Content := ''; // get headers and content GetHeader; ................................................................................ end; constructor THttpServerSocket.Create(aServer: THttpServer); var i: integer; begin inherited Create; if aServer<>nil then begin for i := 0 to aServer.fCompress.Count-1 do RegisterCompress(aServer.fCompress[i]); TCPPrefix := aServer.TCPPrefix; end; end; { ECrtSocket } constructor ECrtSocket.Create(const Msg: string); begin inherited CreateFmt('%s %d',[Msg,WSAGetLastError]); |
Changes to SynLZ.pas.
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 |
/// 2nd compression method optimizes pattern copy -> a bit smaller, but slower
function SynLZdecompress2(src: PAnsiChar; size: integer; dst: PAnsiChar): Integer;
/// compress a data content using the SynLZ algorithm
// - as expected by THttpSocket.RegisterCompress
// - will return 'synlz' as ACCEPT-ENCODING: header parameter
// - will use internaly a level compression of 1, i.e. fastest available
function CompressSynLZ(var Data: AnsiString; Compress: boolean): AnsiString;
implementation
{$ifndef FPC}
|
| > |
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 |
/// 2nd compression method optimizes pattern copy -> a bit smaller, but slower function SynLZdecompress2(src: PAnsiChar; size: integer; dst: PAnsiChar): Integer; /// compress a data content using the SynLZ algorithm // - as expected by THttpSocket.RegisterCompress // - will return 'synlz' as ACCEPT-ENCODING: header parameter // - will store a hash of both compressed and uncompressed stream: if the // data is corrupted during transmission, will instantly return '' function CompressSynLZ(var Data: AnsiString; Compress: boolean): AnsiString; implementation {$ifndef FPC} |
Changes to SynLZO.pas.
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 |
/// uncompress in_p(in_len) into out_p (must be allocated before call), returns out_len
// - may write up to out_len+3 bytes in out_p
// - the decompression mode is "fast-unsafe" -> CRC/Adler32 in_p data before call
function lzopas_decompress(in_p: PAnsiChar; in_len: integer; out_p: PAnsiChar): Integer;
/// (de)compress a data content using the SynLZO algorithm
// - as expected by THttpSocket.RegisterCompress
// - will use internaly a level compression of 1, i.e. fastest available
// - will return 'synlzo' as ACCEPT-ENCODING: header parameter
function CompressSynLZO(var Data: AnsiString; Compress: boolean): AnsiString;
{$ifdef LZOFILE}
{$ifdef WIN32}
|
< > > |
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 |
/// uncompress in_p(in_len) into out_p (must be allocated before call), returns out_len // - may write up to out_len+3 bytes in out_p // - the decompression mode is "fast-unsafe" -> CRC/Adler32 in_p data before call function lzopas_decompress(in_p: PAnsiChar; in_len: integer; out_p: PAnsiChar): Integer; /// (de)compress a data content using the SynLZO algorithm // - as expected by THttpSocket.RegisterCompress // - will return 'synlzo' as ACCEPT-ENCODING: header parameter // - will store a hash of both compressed and uncompressed stream: if the // data is corrupted during transmission, will instantly return '' function CompressSynLZO(var Data: AnsiString; Compress: boolean): AnsiString; {$ifdef LZOFILE} {$ifdef WIN32} |