Skip to content
Permalink
Browse files

properly implement SynCurl after #231

  • Loading branch information...
Arnaud Bouchez
Arnaud Bouchez committed Sep 3, 2019
1 parent b460c09 commit 0056ace18ea45f9661325b317ac513af8dace9d4
Showing with 82 additions and 54 deletions.
  1. +1 −1 ReadMe.txt
  2. +1 −1 SQLite3/mORMot.pas
  3. +1 −1 SynCommons.pas
  4. +10 −12 SynCrtSock.pas
  5. +67 −37 SynCurl.pas
  6. +1 −1 SynOleDB.pas
  7. +1 −1 SynopseCommit.inc
@@ -61,7 +61,7 @@ Contributors
Nzsolt
Oleg Tretyakov
Ondrej (reddwarf)
Pavel (mpv)
Pavel Mashlyakovskii (mpv)
Pierre le Riche
RalfS
Richard6688
@@ -45,7 +45,7 @@
Michalis Kamburelis
MilesYou
Ondrej
Pavel (mpv)
Pavel Mashlyakovskii (mpv)
Sabbiolina
Transmogrifix
Vadim Orel
@@ -47,7 +47,7 @@
- PBa
- RalfS
- Sanyin
- Pavel (mpv)
- Pavel Mashlyakovskii (mpv)
- Wloochacz
- zed
@@ -39,7 +39,7 @@
- Maciej Izak (hnb)
- Marius Maximus
- Mr Yang (ysair)
- Pavel (mpv)
- Pavel Mashlyakovskii (mpv)
- Willo vd Merwe
Alternatively, the contents of this file may be used under the terms of
@@ -223,7 +223,7 @@
}

{$I Synopse.inc} // define HASINLINE CPU32 CPU64 ONLYUSEHTTPSOCKET
{$I Synopse.inc} // define HASINLINE ONLYUSEHTTPSOCKET USELIBCURL SYNCRTDEBUGLOW

{.$define SYNCRTDEBUGLOW}
// internal use: enable some low-level log messages for HTTP socket debugging
@@ -240,6 +240,12 @@ interface
SynCommons,
SynLog,
{$endif SYNCRTDEBUGLOW}
{$ifdef USELIBCURL}
SynCurl,
{$endif USELIBCURL}
{$ifdef FPC}
dynlibs,
{$endif FPC}
{$ifdef MSWINDOWS}
Windows,
SynWinSock,
@@ -3208,16 +3214,8 @@ TPollAsynchSockets = class
function WinHTTP_WebSocketEnabled: boolean;
{$endif}

implementation

uses
{$ifdef USELIBCURL}
SynCurl,
{$endif}
{$ifdef FPC}
dynlibs
{$endif}
;
implementation

{ ************ some shared helper functions and classes }

@@ -5712,7 +5710,7 @@ function SendEmail(const Server, From, CSVDest, Subject, Text, Headers,
GetNextItem(P,',',rec);
rec := Trim(rec);
if rec='' then continue;
if pos({$ifdef HASCODEPAGE}SockString{$endif}('<'),rec)=0 then
if Pos({$ifdef HASCODEPAGE}SockString{$endif}('<'),rec)=0 then
rec := '<'+rec+'>';
Exec('RCPT TO:'+rec,'25');
if ToList='' then
@@ -29,7 +29,8 @@
the Initial Developer. All Rights Reserved.
Contributor(s):
- Pavel Mashlyakovskii (mpv)
- Marcos Douglas B. Santos (mdbs99)
- Pavel Mashlyakovskii (mpv)
Alternatively, the contents of this file may be used under the terms of
@@ -64,27 +65,29 @@ interface
dynlibs,
SynFPCSock,
SynFPCLinux,
{$endif}
{$endif FPC}
{$ifdef KYLIX3}
LibC,
SynFPCSock, // shared with Kylix
SynKylix,
{$endif}
{$endif}
{$endif KYLIX3}
{$endif MSWINDOWS}
SysUtils,
Classes;

{ -------------- curl library low-level interfaces, constants and types }

const
LIBCURL_DLL = {$IFDEF Darwin} 'libcurl.dylib' {$ELSE}
{$IFDEF LINUX} 'libcurl.so' {$ELSE} 'libcurl-x64.dll' {$ENDIF}{$ENDIF};
/// low-level libcurl library file name, depending on the running OS
LIBCURL_DLL = {$ifdef Darwin} 'libcurl.dylib' {$else}
{$ifdef Linux} 'libcurl.so' {$else} 'libcurl-x64.dll' {$endif}{$endif};

{$Z4}
type
/// low-level exception raised during OpenSSL library access
/// low-level exception raised during libcurl library access
ECurl = class(Exception);

/// low-level options for libcurl library API calls
TCurlOption = (
coPort = 3,
coTimeout = 13,
@@ -212,6 +215,8 @@ ECurl = class(Exception);
coMaxFileSizeLarge = 30117,
coPostFieldSizeLarge = 30120
);

/// low-level result codes for libcurl library API calls
TCurlResult = (
crOK, crUnsupportedProtocol, crFailedInit, crURLMalformat, crURLMalformatUser,
crCouldNotResolveProxy, crCouldNotResolveHost, crCouldNotConnect,
@@ -234,6 +239,8 @@ ECurl = class(Exception);
crSSLEngineInitFailed, crLoginDenied, crTFTPNotFound, crTFTPPerm,
crTFTPDiskFull, crTFTPIllegal, crTFTPUnknownID, crTFTPExists, crTFTPNoSuchUser
);

/// low-level information enumeration for libcurl library API calls
TCurlInfo = (
ciNone,
ciLastOne = 28,
@@ -281,6 +288,7 @@ ECurl = class(Exception);
ciAppConnectTimeT = 6291512 // (3) SSL handshake
);
{$ifdef LIBCURLMULTI}
/// low-level result codes for libcurl library API calls in "multi" mode
TCurlMultiCode = (
cmcCallMultiPerform = -1,
cmcOK = 0,
@@ -293,6 +301,8 @@ ECurl = class(Exception);
cmcAddedAlready,
cmcRecursiveApiCall
);

/// low-level options for libcurl library API calls in "multi" mode
TCurlMultiOption = (
cmoPipeLining = 3,
cmoMaxConnects = 6,
@@ -312,11 +322,17 @@ ECurl = class(Exception);
);
{$endif LIBCURLMULTI}

/// low-level version identifier of the libcurl library
TCurlVersion = (cvFirst,cvSecond,cvThird,cvFour);
/// low-level initialization option for libcurl library API
// - currently, only giSSL is set, since giWin32 is redundant with WinHTTP
TCurlGlobalInit = set of (giSSL,giWin32);
/// low-level message state for libcurl library API
TCurlMsg = (cmNone, cmDone);
PAnsiCharArray = array[0..1023] of PAnsiChar;

PAnsiCharArray = array[0..(MaxInt div SizeOf(PAnsiChar))-1] of PAnsiChar;

/// low-level version information for libcurl library
TCurlVersionInfo = record
age: TCurlVersion;
version: PAnsiChar;
@@ -333,22 +349,27 @@ TCurlVersionInfo = record
end;
PCurlVersionInfo = ^TCurlVersionInfo;

/// low-level access to the libcurl library instance
TCurl = type pointer;
/// low-level string list type for libcurl library API
TCurlSList = type pointer;
PCurlSList = ^TCurlSList;
PPCurlSListArray = ^PCurlSListArray;
PCurlSListArray = array[0..(MaxInt div SizeOf(PCurlSList))-1] of PCurlSList;
/// low-level access to the libcurl library instance in "multi" mode
TCurlMulti = type pointer;
/// low-level access to one libcurl library socket instance
TCurlSocket = type TSocket;

PCurlCertInfo = ^TCurlCertInfo;
/// low-level certificate information for libcurl library API
TCurlCertInfo = packed record
num_of_certs: integer;
{$ifdef CPUX64}_align: array[0..3] of byte;{$endif}
certinfo: PPCurlSListArray;
end;
PCurlCertInfo = ^TCurlCertInfo;

PCurlMsgRec = ^TCurlMsgRec;
/// low-level message information for libcurl library API
TCurlMsgRec = packed record
msg: TCurlMsg;
{$ifdef CPUX64}_align: array[0..3] of byte;{$endif}
@@ -358,30 +379,38 @@ TCurlVersionInfo = record
1: (result: TCurlResult);
end;
end;
PCurlMsgRec = ^TCurlMsgRec;

PCurlWaitFD = ^TCurlWaitFD;
/// low-level file description event handler for libcurl library API
TCurlWaitFD = packed record
fd: TCurlSocket;
events: SmallInt;
revents: SmallInt;
{$ifdef CPUX64}_align: array[0..3] of byte;{$endif}
end;
PCurlWaitFD = ^TCurlWaitFD;

/// low-level write callback function signature for libcurl library API
curl_write_callback = function (buffer: PAnsiChar; size,nitems: integer;
outstream: pointer): integer; cdecl;
/// low-level read callback function signature for libcurl library API
curl_read_callback = function (buffer: PAnsiChar; size,nitems: integer;
instream: pointer): integer; cdecl;

{$Z1}


var
/// low-level late binding functions access to the libcurl library API
// - ensure you called LibCurlInitialize or CurlIsAvailable functions to
// setup this global instance before using any of its internal functions
// - see also https://curl.haxx.se/libcurl/c/libcurl-multi.html interface
curl: packed record
{$ifdef FPC}
Module: TLibHandle;
{$else}
Module: THandle;
{$endif}
{$endif FPC}
global_init: function(flags: TCurlGlobalInit): TCurlResult; cdecl;
global_cleanup: procedure; cdecl;
version_info: function(age: TCurlVersion): PCurlVersionInfo; cdecl;
@@ -395,7 +424,7 @@ TCurlVersionInfo = record
easy_strerror: function(code: TCurlResult): PAnsiChar; cdecl;
slist_append: function(list: TCurlSList; s: PAnsiChar): TCurlSList; cdecl;
slist_free_all: procedure(list: TCurlSList); cdecl;
{$ifdef LIBCURLMULTI} // https://curl.haxx.se/libcurl/c/libcurl-multi.html interface
{$ifdef LIBCURLMULTI}
multi_add_handle: function(mcurl: TCurlMulti; curl: TCurl): TCurlMultiCode; cdecl;
multi_assign: function(mcurl: TCurlMulti; socket: TCurlSocket; data: pointer): TCurlMultiCode; cdecl;
multi_cleanup: function(mcurl: TCurlMulti): TCurlMultiCode; cdecl;
@@ -415,31 +444,32 @@ TCurlVersionInfo = record
infoText: string;
end;

procedure LibCurlInitialize;
/// initialize the libcurl API, accessible via the curl global variable
// - do nothing if the library has already been loaded
// - will raise ECurl exception on any loading issue
procedure LibCurlInitialize(engines: TCurlGlobalInit=[giSSL]);

/// return TRUE if a curl library is available
// - will load and initialize it, if necessary
// - will load and initialize it, calling LibCurlInitialize if necessary,
// catching any exception during the process
function CurlIsAvailable: boolean;

/// Callback used by libcurl to write data; Usage:
// curl.easy_setopt(fHandle,coWriteFunction,@CurlWriteRawByteString);
// curl.easy_setopt(curlHandle,coFile,@curlRespBody);
// where curlRespBody: RawByteString;
// where curlRespBody should be a generic AnsiString/RawByteString, i.e.
// in practice a SockString or a RawByteString
function CurlWriteRawByteString(buffer: PAnsiChar; size,nitems: integer;
opaque: pointer): integer; cdecl;


implementation

type
{$ifdef UNICODE}
/// define a raw 8-bit storage string type, used for data buffer management
SockString = type RawByteString;
{$else}
{$ifdef HASCODEPAGE} // FPC may expect a CP, e.g. to compare two string constants
SockString = type RawByteString;
{$else}
/// define a 8-bit raw storage string type, used for data buffer management
SockString = type AnsiString;
{$endif}
{$endif}
// some internal cross-compiler array of bytes string definition
SockString = {$ifdef HASCODEPAGE}RawByteString{$else}AnsiString{$endif};
// some internal cross-compiler PtrInt definition
{$ifndef FPC} PtrInt = {$ifdef CPU64}Int64{$else}integer{$endif}; {$endif}

function CurlWriteRawByteString(buffer: PAnsiChar; size,nitems: integer;
opaque: pointer): integer; cdecl;
@@ -466,7 +496,7 @@ function CurlIsAvailable: boolean;
end;
end;

procedure LibCurlInitialize;
procedure LibCurlInitialize(engines: TCurlGlobalInit);
var P: PPointer;
api: integer;
const NAMES: array[0..{$ifdef LIBCURLMULTI}26{$else}12{$endif}] of string = (
@@ -485,36 +515,36 @@ procedure LibCurlInitialize;
if curl.Module=0 then // try to load libcurl once
try
curl.Module := LoadLibrary(LIBCURL_DLL);
{$ifdef Darwin}
{$ifdef Darwin} // another common names on MacOS
if curl.Module=0 then
curl.Module := LoadLibrary('libcurl.4.dylib');
if curl.Module=0 then
curl.Module := LoadLibrary('libcurl.3.dylib');
{$else}
{$ifdef LINUX}
{$ifdef Linux} // another common names on POSIX
if curl.Module=0 then
curl.Module := LoadLibrary('libcurl.so.4');
if curl.Module=0 then
curl.Module := LoadLibrary('libcurl.so.3');
// for latest Linux Mint and other similar distros
// for latest Linux Mint and other similar distros using gnutls
if curl.Module=0 then
curl.Module := LoadLibrary('libcurl-gnutls.so.4');
if curl.Module=0 then
curl.Module := LoadLibrary('libcurl-gnutls.so.3');
{$endif}
{$endif}
{$endif Linux}
{$endif Darwin}
if curl.Module=0 then
raise ECurl.CreateFmt('Unable to find %s'{$ifdef LINUX}+
raise ECurl.CreateFmt('Unable to find %s'{$ifdef Linux}+
': try e.g. sudo apt-get install libcurl3'{$ifdef CPUX86}+':i386'{$endif}
{$endif LINUX},[LIBCURL_DLL]);
{$endif Linux},[LIBCURL_DLL]);
P := @@curl.global_init;
for api := low(NAMES) to high(NAMES) do begin
P^ := GetProcAddress(curl.Module,{.$ifndef FPC}PChar{.$endif}('curl_'+NAMES[api]));
P^ := GetProcAddress(curl.Module,{$ifndef FPC}PChar{$endif}('curl_'+NAMES[api]));
if P^=nil then
raise ECurl.CreateFmt('Unable to find %s() in %s',[NAMES[api],LIBCURL_DLL]);
inc(P);
end;
curl.global_init([giSSL]);
curl.global_init(engines);
curl.info := curl.version_info(cvFour)^;
curl.infoText := format('%s version %s',[LIBCURL_DLL,curl.info.version]);
if curl.info.ssl_version<>nil then
@@ -30,7 +30,7 @@
Contributor(s):
- Esteban Martin (EMartin)
- Pavel (mpv)
- Pavel Mashlyakovskii (mpv)
Alternatively, the contents of this file may be used under the terms of
either the GNU General Public License Version 2 or later (the "GPL"), or
@@ -1 +1 @@
'1.18.5319'
'1.18.5320'

0 comments on commit 0056ace

Please sign in to comment.
You can’t perform that action at this time.