Initial libcurl wxWebRequest implementation
This commit is contained in:
@@ -35,7 +35,7 @@ if (wxUSE_WEBREQUEST_CURL)
|
|||||||
find_package(CURL REQUIRED)
|
find_package(CURL REQUIRED)
|
||||||
|
|
||||||
target_include_directories(net PRIVATE ${CURL_INCLUDE_DIRS})
|
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()
|
endif()
|
||||||
|
|
||||||
wx_finalize_lib(net)
|
wx_finalize_lib(net)
|
||||||
|
@@ -155,8 +155,11 @@ endif()
|
|||||||
if(APPLE)
|
if(APPLE)
|
||||||
wx_option(wxUSE_WEBREQUEST_URLSESSION "use wxWebRequest URLSession backend")
|
wx_option(wxUSE_WEBREQUEST_URLSESSION "use wxWebRequest URLSession backend")
|
||||||
endif()
|
endif()
|
||||||
set(wxUSE_WEBREQUEST_CURL_DEFAULT OFF)
|
if(APPLE OR WIN32)
|
||||||
#TODO: determine wxUSE_WEBREQUEST_CURL_DEFAULT (based)
|
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_WEBREQUEST_CURL "use wxWebRequest libcurl backend" ${wxUSE_WEBREQUEST_CURL_DEFAULT})
|
||||||
|
|
||||||
wx_option(wxUSE_ZIPSTREAM "use wxZip streams")
|
wx_option(wxUSE_ZIPSTREAM "use wxZip streams")
|
||||||
|
92
configure
vendored
92
configure
vendored
@@ -1138,6 +1138,7 @@ enable_ipv6
|
|||||||
enable_ole
|
enable_ole
|
||||||
enable_dataobj
|
enable_dataobj
|
||||||
enable_webrequest
|
enable_webrequest
|
||||||
|
enable_webrequestcurl
|
||||||
enable_ipc
|
enable_ipc
|
||||||
enable_baseevtloop
|
enable_baseevtloop
|
||||||
enable_epollloop
|
enable_epollloop
|
||||||
@@ -2081,6 +2082,7 @@ Optional Features:
|
|||||||
--enable-ole use OLE classes (Win32 only)
|
--enable-ole use OLE classes (Win32 only)
|
||||||
--enable-dataobj use data object classes
|
--enable-dataobj use data object classes
|
||||||
--enable-webrequest use wxWebRequest
|
--enable-webrequest use wxWebRequest
|
||||||
|
--enable-webrequest-curl use libcurl with wxWebRequest
|
||||||
--enable-ipc use interprocess communication (wxSocket etc.)
|
--enable-ipc use interprocess communication (wxSocket etc.)
|
||||||
--enable-baseevtloop use event loop in console programs too
|
--enable-baseevtloop use event loop in console programs too
|
||||||
--enable-epollloop use wxEpollDispatcher class (Linux only)
|
--enable-epollloop use wxEpollDispatcher class (Linux only)
|
||||||
@@ -6550,6 +6552,35 @@ fi
|
|||||||
eval "$wx_cv_use_webrequest"
|
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=
|
enablestring=
|
||||||
defaultval=$wxUSE_ALL_FEATURES
|
defaultval=$wxUSE_ALL_FEATURES
|
||||||
@@ -23764,6 +23795,67 @@ if test "$wxUSE_LIBMSPACK" != "no"; then
|
|||||||
fi
|
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=
|
||||||
TOOLKIT_INCLUDE=
|
TOOLKIT_INCLUDE=
|
||||||
|
21
configure.in
21
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(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(dataobj, [ --enable-dataobj use data object classes], wxUSE_DATAOBJ)
|
||||||
WX_ARG_FEATURE(webrequest, [ --enable-webrequest use wxWebRequest], wxUSE_WEBREQUEST)
|
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)
|
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)
|
AC_DEFINE(wxUSE_LIBMSPACK)
|
||||||
fi
|
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 ----------------------------------------------------------------
|
||||||
dnl search for toolkit (widget sets)
|
dnl search for toolkit (widget sets)
|
||||||
|
@@ -12,7 +12,100 @@
|
|||||||
|
|
||||||
#if wxUSE_WEBREQUEST_CURL
|
#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:
|
||||||
|
explicit wxWebAuthChallengeCURL(Source source, wxWebRequestCURL& request);
|
||||||
|
|
||||||
|
bool Init();
|
||||||
|
|
||||||
|
void SetCredentials(const wxString& user, const wxString& password) wxOVERRIDE;
|
||||||
|
|
||||||
|
private:
|
||||||
|
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<wxWebResponseCURL> m_response;
|
||||||
|
wxScopedPtr<wxWebAuthChallengeCURL> 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<wxWebRequestCURL&>(m_request).GetHandle(); }
|
||||||
|
|
||||||
|
wxDECLARE_NO_COPY_CLASS(wxWebResponseCURL);
|
||||||
|
};
|
||||||
|
|
||||||
|
class WXDLLIMPEXP_NET wxWebSessionCURL: public wxWebSession, private wxThreadHelper
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
wxWebSessionCURL();
|
wxWebSessionCURL();
|
||||||
@@ -21,7 +114,25 @@ public:
|
|||||||
|
|
||||||
wxWebRequest* CreateRequest(const wxString& url, int id = wxID_ANY) wxOVERRIDE;
|
wxWebRequest* CreateRequest(const wxString& url, int id = wxID_ANY) wxOVERRIDE;
|
||||||
|
|
||||||
|
bool StartRequest(wxWebRequestCURL& request);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
wxThread::ExitCode Entry() wxOVERRIDE;
|
||||||
|
|
||||||
private:
|
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);
|
wxDECLARE_NO_COPY_CLASS(wxWebSessionCURL);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -20,20 +20,455 @@
|
|||||||
|
|
||||||
#include "wx/webrequest_curl.h"
|
#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<wxWebResponseCURL*>(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<wxWebResponseCURL*>(userdata)->AddHeaderData(buffer, size * nitems);
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
wxWebResponseCURL::wxWebResponseCURL(wxWebRequest& request) :
|
||||||
|
wxWebResponse(request)
|
||||||
|
{
|
||||||
|
curl_easy_setopt(GetHandle(), CURLOPT_WRITEDATA, static_cast<void*>(this));
|
||||||
|
curl_easy_setopt(GetHandle(), CURLOPT_HEADERDATA, static_cast<void*>(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<wxWebRequestCURL*>(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<void*>(this));
|
||||||
|
// Set URL to handle
|
||||||
|
curl_easy_setopt(m_handle, CURLOPT_URL, static_cast<const char*>(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<void*>(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<curl_off_t>(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<curl_off_t>(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<const char*>(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<wxWebSessionCURL&>(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<const char*>(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()
|
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)
|
wxWebRequest* wxWebSessionCURL::CreateRequest(const wxString& url, int id)
|
||||||
{
|
{
|
||||||
wxFAIL_MSG("not implemented");
|
if ( !m_handle )
|
||||||
return NULL;
|
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
|
#endif // wxUSE_WEBREQUEST_CURL
|
||||||
|
Reference in New Issue
Block a user