diff --git a/build/cmake/lib/net/CMakeLists.txt b/build/cmake/lib/net/CMakeLists.txt index 7d1e71cfda..7778ebf095 100644 --- a/build/cmake/lib/net/CMakeLists.txt +++ b/build/cmake/lib/net/CMakeLists.txt @@ -35,7 +35,7 @@ if (wxUSE_WEBREQUEST_CURL) find_package(CURL REQUIRED) target_include_directories(net PRIVATE ${CURL_INCLUDE_DIRS}) - wx_lib_link_libraries(net PRIVATE CURL::libcurl) + wx_lib_link_libraries(net PRIVATE ${CURL_LIBRARIES}) endif() wx_finalize_lib(net) diff --git a/build/cmake/options.cmake b/build/cmake/options.cmake index 9d3852521e..6927c412e4 100644 --- a/build/cmake/options.cmake +++ b/build/cmake/options.cmake @@ -155,8 +155,11 @@ endif() if(APPLE) wx_option(wxUSE_WEBREQUEST_URLSESSION "use wxWebRequest URLSession backend") endif() -set(wxUSE_WEBREQUEST_CURL_DEFAULT OFF) -#TODO: determine wxUSE_WEBREQUEST_CURL_DEFAULT (based) +if(APPLE OR WIN32) + set(wxUSE_WEBREQUEST_CURL_DEFAULT OFF) +else() + set(wxUSE_WEBREQUEST_CURL_DEFAULT ON) +endif() wx_option(wxUSE_WEBREQUEST_CURL "use wxWebRequest libcurl backend" ${wxUSE_WEBREQUEST_CURL_DEFAULT}) wx_option(wxUSE_ZIPSTREAM "use wxZip streams") diff --git a/configure b/configure index 6501210d28..03426ec764 100755 --- a/configure +++ b/configure @@ -1138,6 +1138,7 @@ enable_ipv6 enable_ole enable_dataobj enable_webrequest +enable_webrequestcurl enable_ipc enable_baseevtloop enable_epollloop @@ -2081,6 +2082,7 @@ Optional Features: --enable-ole use OLE classes (Win32 only) --enable-dataobj use data object classes --enable-webrequest use wxWebRequest + --enable-webrequest-curl use libcurl with wxWebRequest --enable-ipc use interprocess communication (wxSocket etc.) --enable-baseevtloop use event loop in console programs too --enable-epollloop use wxEpollDispatcher class (Linux only) @@ -6550,6 +6552,35 @@ fi eval "$wx_cv_use_webrequest" + enablestring= + defaultval=$wxUSE_ALL_FEATURES + if test -z "$defaultval"; then + if test x"$enablestring" = xdisable; then + defaultval=yes + else + defaultval=no + fi + fi + + # Check whether --enable-webrequestcurl was given. +if test "${enable_webrequestcurl+set}" = set; then : + enableval=$enable_webrequestcurl; + if test "$enableval" = yes; then + wx_cv_use_webrequestcurl='wxUSE_WEBREQUEST_LIBCURL=yes' + else + wx_cv_use_webrequestcurl='wxUSE_WEBREQUEST_LIBCURL=no' + fi + +else + + wx_cv_use_webrequestcurl='wxUSE_WEBREQUEST_LIBCURL=${'DEFAULT_wxUSE_WEBREQUEST_LIBCURL":-$defaultval}" + +fi + + + eval "$wx_cv_use_webrequestcurl" + + enablestring= defaultval=$wxUSE_ALL_FEATURES @@ -23764,6 +23795,67 @@ if test "$wxUSE_LIBMSPACK" != "no"; then fi +if test "$wxUSE_WEBREQUEST_CURL" != "no"; then + ac_fn_c_check_header_mongrel "$LINENO" "curl/curl.h" "ac_cv_header_curl_curl_h" "$ac_includes_default" +if test "x$ac_cv_header_curl_curl_h" = xyes; then : + +fi + + + + if test "$ac_cv_header_curl_curl_h" = "yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for curl_easy_init in -lcurl" >&5 +$as_echo_n "checking for curl_easy_init in -lcurl... " >&6; } +if ${ac_cv_lib_curl_curl_easy_init+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lcurl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char curl_easy_init (); +int +main () +{ +return curl_easy_init (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_curl_curl_easy_init=yes +else + ac_cv_lib_curl_curl_easy_init=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curl_curl_easy_init" >&5 +$as_echo "$ac_cv_lib_curl_curl_easy_init" >&6; } +if test "x$ac_cv_lib_curl_curl_easy_init" = xyes; then : + + CURL_LINK="-lcurl" + LIBS="$CURL_LINK $LIBS" + $as_echo "#define wxUSE_WEBREQUEST_CURL 1" >>confdefs.h + + +fi + + fi + + if test -z "$CURL_LINK"; then + wxUSE_WEBREQUEST_CURL=no + fi +fi + TOOLKIT= TOOLKIT_INCLUDE= diff --git a/configure.in b/configure.in index 03959b657b..db5151b392 100644 --- a/configure.in +++ b/configure.in @@ -699,6 +699,7 @@ WX_ARG_FEATURE(ipv6, [ --enable-ipv6 enable IPv6 support in WX_ARG_FEATURE(ole, [ --enable-ole use OLE classes (Win32 only)], wxUSE_OLE) WX_ARG_FEATURE(dataobj, [ --enable-dataobj use data object classes], wxUSE_DATAOBJ) WX_ARG_FEATURE(webrequest, [ --enable-webrequest use wxWebRequest], wxUSE_WEBREQUEST) +WX_ARG_FEATURE(webrequestcurl, [ --enable-webrequest-curl use libcurl with wxWebRequest], wxUSE_WEBREQUEST_LIBCURL) WX_ARG_FEATURE(ipc, [ --enable-ipc use interprocess communication (wxSocket etc.)], wxUSE_IPC) @@ -2736,6 +2737,26 @@ if test "$wxUSE_LIBMSPACK" != "no"; then AC_DEFINE(wxUSE_LIBMSPACK) fi +dnl ------------------------------------------------------------------------ +dnl Check for libcurl +dnl ------------------------------------------------------------------------ + +if test "$wxUSE_WEBREQUEST_CURL" != "no"; then + AC_CHECK_HEADER(curl/curl.h,,,[]) + + if test "$ac_cv_header_curl_curl_h" = "yes"; then + AC_CHECK_LIB(curl, curl_easy_init, + [ + CURL_LINK="-lcurl" + LIBS="$CURL_LINK $LIBS" + AC_DEFINE(wxUSE_WEBREQUEST_CURL) + ]) + fi + + if test -z "$CURL_LINK"; then + wxUSE_WEBREQUEST_CURL=no + fi +fi dnl ---------------------------------------------------------------- dnl search for toolkit (widget sets) diff --git a/include/wx/webrequest_curl.h b/include/wx/webrequest_curl.h index 9eb674095c..6a75b35c53 100644 --- a/include/wx/webrequest_curl.h +++ b/include/wx/webrequest_curl.h @@ -12,24 +12,135 @@ #if wxUSE_WEBREQUEST_CURL -class WXDLLIMPEXP_NET wxWebSessionCURL: public wxWebSession +#include "wx/thread.h" + +#include "curl/curl.h" + +class wxWebResponseCURL; +class wxWebRequestCURL; + +class WXDLLIMPEXP_NET wxWebAuthChallengeCURL : public wxWebAuthChallenge { public: - wxWebSessionCURL(); + explicit wxWebAuthChallengeCURL(Source source, wxWebRequestCURL& request); - ~wxWebSessionCURL(); + bool Init(); - wxWebRequest* CreateRequest(const wxString& url, int id = wxID_ANY) wxOVERRIDE; + void SetCredentials(const wxString& user, const wxString& password) wxOVERRIDE; private: - wxDECLARE_NO_COPY_CLASS(wxWebSessionCURL); + wxWebRequestCURL& m_request; + + wxDECLARE_NO_COPY_CLASS(wxWebAuthChallengeCURL); +}; + +class WXDLLIMPEXP_NET wxWebRequestCURL: public wxWebRequest +{ +public: + wxWebRequestCURL(wxWebSession& session, int id, const wxString& url); + + ~wxWebRequestCURL(); + + void Start() wxOVERRIDE; + + void Cancel() wxOVERRIDE; + + wxWebResponse* GetResponse() const wxOVERRIDE; + + wxWebAuthChallenge* GetAuthChallenge() const wxOVERRIDE + { return m_authChallenge.get(); } + + wxFileOffset GetBytesSent() const wxOVERRIDE; + + wxFileOffset GetBytesExpectedToSend() const wxOVERRIDE; + + CURL* GetHandle() const { return m_handle; } + + bool StartRequest(); + + void HandleCompletion(); + + wxString GetError() const; + + size_t ReadData(char* buffer, size_t size); + +private: + CURL* m_handle; + char m_errorBuffer[CURL_ERROR_SIZE]; + struct curl_slist *m_headerList; + wxScopedPtr m_response; + wxScopedPtr m_authChallenge; + + void DestroyHeaderList(); + + wxDECLARE_NO_COPY_CLASS(wxWebRequestCURL); +}; + +class WXDLLIMPEXP_NET wxWebResponseCURL : public wxWebResponse +{ +public: + wxWebResponseCURL(wxWebRequest& request); + + wxInt64 GetContentLength() const wxOVERRIDE; + + wxString GetURL() const wxOVERRIDE; + + wxString GetHeader(const wxString& name) const wxOVERRIDE; + + int GetStatus() const wxOVERRIDE; + + wxString GetStatusText() const wxOVERRIDE { return m_statusText; } + + size_t WriteData(void *buffer, size_t size); + + size_t AddHeaderData(const char* buffer, size_t size); + +private: + wxWebRequestHeaderMap m_headers; + wxString m_statusText; + + CURL* GetHandle() const + { return static_cast(m_request).GetHandle(); } + + wxDECLARE_NO_COPY_CLASS(wxWebResponseCURL); +}; + +class WXDLLIMPEXP_NET wxWebSessionCURL: public wxWebSession, private wxThreadHelper +{ +public: + wxWebSessionCURL(); + + ~wxWebSessionCURL(); + + wxWebRequest* CreateRequest(const wxString& url, int id = wxID_ANY) wxOVERRIDE; + + bool StartRequest(wxWebRequestCURL& request); + +protected: + wxThread::ExitCode Entry() wxOVERRIDE; + +private: + CURLM* m_handle; + wxCondition m_condition; + wxMutex m_mutex; + bool m_shuttingDown; + + void Initialize(); + + static int ms_activeSessions; + + static void InitializeCURL(); + + static void CleanupCURL(); + + wxDECLARE_NO_COPY_CLASS(wxWebSessionCURL); }; class WXDLLIMPEXP_NET wxWebSessionFactoryCURL: public wxWebSessionFactory { public: - wxWebSession* Create() wxOVERRIDE - { return new wxWebSessionCURL(); } + wxWebSession* Create() wxOVERRIDE + { return new wxWebSessionCURL(); } }; #endif // wxUSE_WEBREQUEST_CURL diff --git a/src/common/webrequest_curl.cpp b/src/common/webrequest_curl.cpp index 86ce25c337..c4f0ecb6d0 100644 --- a/src/common/webrequest_curl.cpp +++ b/src/common/webrequest_curl.cpp @@ -20,20 +20,455 @@ #include "wx/webrequest_curl.h" -wxWebSessionCURL::wxWebSessionCURL() -{ +#ifndef WX_PRECOMP + #include "wx/log.h" + #include "wx/utils.h" +#endif +// Define symbols that might be missing from older libcurl headers +#ifndef CURL_AT_LEAST_VERSION +#define CURL_VERSION_BITS(x,y,z) ((x)<<16|(y)<<8|z) +#define CURL_AT_LEAST_VERSION(x,y,z) \ + (LIBCURL_VERSION_NUM >= CURL_VERSION_BITS(x, y, z)) +#endif + +// +// wxWebResponseCURL +// + +static size_t wxCURLWriteData(void* buffer, size_t size, size_t nmemb, void* userp) +{ + if ( userp ) + return static_cast(userp)->WriteData(buffer, size * nmemb); + else + return 0; +} + +static size_t wxCURLHeader(char *buffer, size_t size, size_t nitems, void *userdata) +{ + if ( userdata ) + return static_cast(userdata)->AddHeaderData(buffer, size * nitems); + else + return 0; +} + +wxWebResponseCURL::wxWebResponseCURL(wxWebRequest& request) : + wxWebResponse(request) +{ + curl_easy_setopt(GetHandle(), CURLOPT_WRITEDATA, static_cast(this)); + curl_easy_setopt(GetHandle(), CURLOPT_HEADERDATA, static_cast(this)); +} + +size_t wxWebResponseCURL::WriteData(void* buffer, size_t size) +{ + void* buf = GetDataBuffer(size); + memcpy(buf, buffer, size); + ReportDataReceived(size); + return size; +} + +size_t wxWebResponseCURL::AddHeaderData(const char * buffer, size_t size) +{ + wxString hdr(buffer, size); + hdr.Trim(); + + if ( hdr.StartsWith("HTTP/") ) + { + // First line of the headers contains status text after + // version and status + m_statusText = hdr.AfterFirst(' ').AfterFirst(' '); + m_headers.clear(); + } + else if ( !hdr.empty() ) + { + wxArrayString hdrArr = wxSplit(hdr, ':'); + wxString hdrName; + wxString hdrValue; + if ( hdrArr.size() > 0 ) + hdrName = hdrArr[0].Trim().MakeUpper(); + if ( hdrArr.size() > 1 ) + hdrValue = hdrArr[1].Trim(false); + m_headers[hdrName] = hdrValue; + } + + return size; +} + +wxInt64 wxWebResponseCURL::GetContentLength() const +{ +#if CURL_AT_LEAST_VERSION(7, 55, 0) + curl_off_t len = 0; + curl_easy_getinfo(GetHandle(), CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &len); + return len; +#else + double len = 0; + curl_easy_getinfo(GetHandle(), CURLINFO_CONTENT_LENGTH_DOWNLOAD, &len); + return (wxInt64)len; +#endif +} + +wxString wxWebResponseCURL::GetURL() const +{ + char* urlp = NULL; + curl_easy_getinfo(GetHandle(), CURLINFO_EFFECTIVE_URL, &urlp); + return wxString(urlp); +} + +wxString wxWebResponseCURL::GetHeader(const wxString& name) const +{ + wxWebRequestHeaderMap::const_iterator it = m_headers.find(name.Upper()); + if ( it != m_headers.end() ) + return it->second; + else + return wxString(); +} + +int wxWebResponseCURL::GetStatus() const +{ + long status = 0; + curl_easy_getinfo(GetHandle(), CURLINFO_RESPONSE_CODE, &status); + return status; +} + +// +// wxWebRequestCURL +// + +static size_t wxCURLRead(char *buffer, size_t size, size_t nitems, void *userdata) +{ + if ( userdata ) + return static_cast(userdata)->ReadData(buffer, size * nitems); + else + return 0; +} + +wxWebRequestCURL::wxWebRequestCURL(wxWebSession & session, int id, const wxString & url): + wxWebRequest(session, id) +{ + m_headers = session.GetHeaders(); + m_headerList = NULL; + + m_handle = curl_easy_init(); + // Set error buffer to get more detailed CURL status + m_errorBuffer[0] = '\0'; + curl_easy_setopt(m_handle, CURLOPT_ERRORBUFFER, m_errorBuffer); + // Set this request in the private pointer + curl_easy_setopt(m_handle, CURLOPT_PRIVATE, static_cast(this)); + // Set URL to handle + curl_easy_setopt(m_handle, CURLOPT_URL, static_cast(url.mb_str())); + // Set callback functions + curl_easy_setopt(m_handle, CURLOPT_WRITEFUNCTION, wxCURLWriteData); + curl_easy_setopt(m_handle, CURLOPT_HEADERFUNCTION, wxCURLHeader); + curl_easy_setopt(m_handle, CURLOPT_READFUNCTION, wxCURLRead); + curl_easy_setopt(m_handle, CURLOPT_READDATA, static_cast(this)); + // Enable gzip, etc decompression + curl_easy_setopt(m_handle, CURLOPT_ACCEPT_ENCODING, ""); + // Enable redirection handling + curl_easy_setopt(m_handle, CURLOPT_FOLLOWLOCATION, 1L); + // Limit redirect to HTTP + curl_easy_setopt(m_handle, CURLOPT_REDIR_PROTOCOLS, + CURLPROTO_HTTP | CURLPROTO_HTTPS); + // Enable all supported authentication methods + curl_easy_setopt(m_handle, CURLOPT_HTTPAUTH, CURLAUTH_ANY); + curl_easy_setopt(m_handle, CURLOPT_PROXYAUTH, CURLAUTH_ANY); +} + +wxWebRequestCURL::~wxWebRequestCURL() +{ + DestroyHeaderList(); + + curl_easy_cleanup(m_handle); +} + +void wxWebRequestCURL::Start() +{ + if ( GetState() != State_Idle ) + return; + + m_response.reset(new wxWebResponseCURL(*this)); + m_response->Init(); + + if ( m_dataSize ) + { + if ( m_method.empty() || m_method.IsSameAs("POST", false) ) + { + curl_easy_setopt(m_handle, CURLOPT_POSTFIELDSIZE_LARGE, + static_cast(m_dataSize)); + curl_easy_setopt(m_handle, CURLOPT_POST, 1L); + } + else if ( m_method.IsSameAs("PUT", false) ) + { + curl_easy_setopt(m_handle, CURLOPT_UPLOAD, 1L); + curl_easy_setopt(m_handle, CURLOPT_INFILESIZE_LARGE, + static_cast(m_dataSize)); + } + } + + if ( m_method.IsSameAs("HEAD", false) ) + { + curl_easy_setopt(m_handle, CURLOPT_NOBODY, 1L); + } + else if ( !m_method.empty() ) + { + curl_easy_setopt(m_handle, CURLOPT_CUSTOMREQUEST, + static_cast(m_method.mb_str())); + } + + for ( wxWebRequestHeaderMap::const_iterator it = m_headers.begin(); + it != m_headers.end(); ++it ) + { + wxString hdrStr = wxString::Format("%s: %s", it->first, it->second); + m_headerList = curl_slist_append(m_headerList, hdrStr.mb_str()); + } + curl_easy_setopt(m_handle, CURLOPT_HTTPHEADER, m_headerList); + + StartRequest(); +} + +bool wxWebRequestCURL::StartRequest() +{ + if ( static_cast(GetSession()).StartRequest(*this) ) + { + SetState(State_Active); + return true; + } + else + { + SetState(State_Failed); + return false; + } +} + +void wxWebRequestCURL::Cancel() +{ + wxFAIL_MSG("not implemented"); +} + +void wxWebRequestCURL::HandleCompletion() +{ + int status = (m_response) ? m_response->GetStatus() : 0; + + if ( status == 0) + SetState(State_Failed, GetError()); + else if ( status == 401 || status == 407 ) + { + m_authChallenge.reset(new wxWebAuthChallengeCURL( + (status == 407) ? wxWebAuthChallenge::Source_Proxy : wxWebAuthChallenge::Source_Server, *this)); + if ( m_authChallenge->Init() ) + SetState(State_Unauthorized, m_response->GetStatusText()); + else + SetState(State_Failed); + } + else if ( CheckServerStatus() ) + SetState(wxWebRequest::State_Completed); +} + +wxString wxWebRequestCURL::GetError() const +{ + return wxString(m_errorBuffer); +} + +size_t wxWebRequestCURL::ReadData(char* buffer, size_t size) +{ + if ( m_dataStream ) + return m_dataStream->Read((void*)buffer, size).LastRead(); + else + return 0; +} + +void wxWebRequestCURL::DestroyHeaderList() +{ + if ( m_headerList ) + { + curl_slist_free_all(m_headerList); + m_headerList = NULL; + } +} + +wxWebResponse* wxWebRequestCURL::GetResponse() const +{ + return m_response.get(); +} + +wxFileOffset wxWebRequestCURL::GetBytesSent() const +{ + wxFAIL_MSG("not implemented"); + return 0; +} + +wxFileOffset wxWebRequestCURL::GetBytesExpectedToSend() const +{ + wxFAIL_MSG("not implemented"); + return 0; +} + +// +// wxWebAuthChallengeCURL +// + +wxWebAuthChallengeCURL::wxWebAuthChallengeCURL(Source source, wxWebRequestCURL& request) : + wxWebAuthChallenge(source), + m_request(request) +{ +} + +bool wxWebAuthChallengeCURL::Init() +{ + return true; +} + +void wxWebAuthChallengeCURL::SetCredentials(const wxString& user, const wxString& password) +{ + wxString authStr = wxString::Format("%s:%s", user, password); + curl_easy_setopt(m_request.GetHandle(), + (GetSource() == Source_Proxy) ? CURLOPT_PROXYUSERPWD : CURLOPT_USERPWD, + static_cast(authStr.mb_str())); + m_request.StartRequest(); +} + +// +// wxWebSessionCURL +// + +int wxWebSessionCURL::ms_activeSessions = 0; + +wxWebSessionCURL::wxWebSessionCURL() : + m_handle(NULL), + m_condition(m_mutex), + m_shuttingDown(false) +{ + // Initialize CURL globally if no sessions are active + if ( ms_activeSessions == 0 ) + InitializeCURL(); + + ms_activeSessions++; } wxWebSessionCURL::~wxWebSessionCURL() { + { + // Notify the work thread + m_shuttingDown = true; + wxMutexLocker lock(m_mutex); + m_condition.Broadcast(); + } + // Wait for work thread to finish + if ( GetThread() && GetThread()->IsRunning() ) + GetThread()->Wait(wxTHREAD_WAIT_BLOCK); + + if ( m_handle ) + curl_multi_cleanup(m_handle); + + // Global CURL cleanup if this is the last session + --ms_activeSessions; + if ( ms_activeSessions == 0 ) + CleanupCURL(); +} + +void wxWebSessionCURL::Initialize() +{ + m_handle = curl_multi_init(); } wxWebRequest* wxWebSessionCURL::CreateRequest(const wxString& url, int id) { - wxFAIL_MSG("not implemented"); - return NULL; + if ( !m_handle ) + Initialize(); + + return new wxWebRequestCURL(*this, id, url); +} + +wxThread::ExitCode wxWebSessionCURL::Entry() +{ + m_mutex.Lock(); + + int activeRequests = -1; + int repeats = 0; + + while ( activeRequests ) + { + // Instruct CURL to work on requests + curl_multi_perform(m_handle, &activeRequests); + + // Process CURL message queue + int msgQueueCount; + while ( CURLMsg* msg = curl_multi_info_read(m_handle, &msgQueueCount) ) + { + if ( msg->msg == CURLMSG_DONE ) + { + wxWebRequestCURL* request; + curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, &request); + curl_multi_remove_handle(m_handle, msg->easy_handle); + request->HandleCompletion(); + } + } + + if ( activeRequests ) + { + // Wait for CURL work to finish + int numfds; + curl_multi_wait(m_handle, NULL, 0, 1000, &numfds); + + if ( !numfds ) + { + repeats++; // count number of repeated zero numfds + if ( repeats > 1 ) + wxMilliSleep(100); + } + else + repeats = 0; + } + else + { + // Wait for new requests or shutdown of the session + m_condition.Wait(); + if ( !m_shuttingDown ) + activeRequests = -1; + } + } + + return (wxThread::ExitCode)0; +} + +bool wxWebSessionCURL::StartRequest(wxWebRequestCURL & request) +{ + // Add request easy handle to multi handle + curl_multi_add_handle(m_handle, request.GetHandle()); + + // Create and start session thread if not yet running + if ( !GetThread() ) + { + if ( CreateThread() ) + return false; + + if ( GetThread()->Run() != wxTHREAD_NO_ERROR ) + return false; + } + + // Signal the worker thread to resume work + wxMutexLocker lock(m_mutex); + m_condition.Broadcast(); + + return true; +} + +// static +void wxWebSessionCURL::InitializeCURL() +{ + long initFlags = CURL_GLOBAL_SSL; +#ifdef WIN32 + initFlags |= CURL_GLOBAL_WIN32; +#endif // WIN32 + if ( curl_global_init(initFlags) ) + wxLogError("libcurl could not be initialized"); +} + +// static +void wxWebSessionCURL::CleanupCURL() +{ + if ( ms_activeSessions == 0 ) + curl_global_cleanup(); } #endif // wxUSE_WEBREQUEST_CURL