JD2022-TU1/main/extern/Camcam/LIBS/Net/http_client_curl.cpp

779 lines
No EOL
21 KiB
C++

#include "SCENE.H"
#ifdef ONLINE_MODE
//#pragma optimize("",off)
//#include "stdafx.h"
#define CURL_STATICLIB 1
#include <curl/curl.h>
#include <windows.h>
#include <winhttp.h> // requires recent Windows SDK, tested with v6.1
#include <process.h>
#include "http_client_curl.h"
#pragma comment(lib, "winhttp.lib")
#define _Curl (CURL *)_CurlStruct
#ifdef USE_OPENSSL
#include "openssl/crypto.h"
#include <windows.h>
struct CRYPTO_dynlock_value
{ MUTEX_TYPE mutex;
};
static MUTEX_TYPE *mutex_buf;
static struct CRYPTO_dynlock_value *dyn_create_function(const char *file, int line)
{ struct CRYPTO_dynlock_value *value;
value = (struct CRYPTO_dynlock_value*)malloc(sizeof(struct CRYPTO_dynlock_value));
if (value)
MUTEX_SETUP(value->mutex);
return value;
}
static void dyn_lock_function(int mode, struct CRYPTO_dynlock_value *l, const char *file, int line)
{ if (mode & CRYPTO_LOCK)
MUTEX_LOCK(l->mutex);
else
MUTEX_UNLOCK(l->mutex);
}
static void dyn_destroy_function(struct CRYPTO_dynlock_value *l, const char *file, int line)
{ MUTEX_CLEANUP(l->mutex);
free(l);
}
void locking_function(int mode, int n, const char *file, int line)
{ if (mode & CRYPTO_LOCK)
MUTEX_LOCK(mutex_buf[n]);
else
MUTEX_UNLOCK(mutex_buf[n]);
}
unsigned long id_function()
{ return (unsigned long)THREAD_ID;
}
bool CRYPTO_thread_setup()
{
mutex_buf = (MUTEX_TYPE*)malloc(CRYPTO_num_locks() * sizeof(MUTEX_TYPE));
if (!mutex_buf)
return false;
for (int i = 0; i < CRYPTO_num_locks(); i++)
MUTEX_SETUP(mutex_buf[i]);
CRYPTO_set_id_callback(id_function);
CRYPTO_set_locking_callback(locking_function);
CRYPTO_set_dynlock_create_callback(dyn_create_function);
CRYPTO_set_dynlock_lock_callback(dyn_lock_function);
CRYPTO_set_dynlock_destroy_callback(dyn_destroy_function);
return true;
}
void CRYPTO_thread_cleanup()
{
int i;
if (!mutex_buf)
return;
CRYPTO_set_id_callback(NULL);
CRYPTO_set_locking_callback(NULL);
CRYPTO_set_dynlock_create_callback(NULL);
CRYPTO_set_dynlock_lock_callback(NULL);
CRYPTO_set_dynlock_destroy_callback(NULL);
for (i = 0; i < CRYPTO_num_locks(); i++)
MUTEX_CLEANUP(mutex_buf[i]);
free(mutex_buf);
mutex_buf = NULL;
}
#endif //USE_OPENSSL
// From CamCam utilities
void SaveDBGInfo(char *text);
#define _CRT_SECURE_NO_WARNINGS
#define VARGS_TO_STR(_str, _format, _size) \
char _strbuf[_size]; \
va_list _args; \
va_start(_args, _format); \
int _res = _vsnprintf(_strbuf, _size-1, _format, _args); \
if ((_res == -1) || (_res == _size-1)) \
{ \
_strbuf[_size-1] = '\0'; \
} \
va_end(_args); \
_str = _strbuf
void logStr(const char *format, ...)
{
char *str;
const int maxLineSize = 512;
VARGS_TO_STR(str, format, maxLineSize);
if (strlen(str)<maxLineSize-1)
strcat(str, "\n");
else
str[maxLineSize-2] = '\n'; // end-2:'\n', end-1:'\0'
SaveDBGInfo(str);
}
std::string printfToStr(const char *format, ...)
{
std::string str;
VARGS_TO_STR(str, format, 1024);
return str;
}
UEString::UEString(const char *src, bool encode, CHttpClient *client)
{
if (encode)
_Str = curl_easy_escape((CURL*)(client->getCurlStruct()), src, 0);
else
_Str = curl_easy_unescape((CURL*)(client->getCurlStruct()), src, 0, NULL);
}
UEString::~UEString()
{
curl_free((void*)_Str);
}
#undef _CRT_SECURE_NO_WARNINGS
// CURL callbacks
size_t onDataReceivedCallback(void *buffer, size_t size, size_t nmemb, void *pHttpClient)
{
CHttpClient * httpClient = static_cast<CHttpClient*>(pHttpClient);
httpClient->onDataReceived((char*)buffer, size*nmemb);
//ifPrepareLuaFunction(GameMessageReceive)
//{
// callPreparedLuaCallback(GameMessageReceive, 0);
//}
return size*nmemb;
}
size_t onHeaderReceivedCallback( void *buffer, size_t size, size_t nmemb, void *pHttpClient)
{
CHttpClient * httpClient = static_cast<CHttpClient*>(pHttpClient);
httpClient->onHeaderReceived((char*)buffer, size*nmemb);
return size*nmemb;
}
int onProgressCallback(void *pHttpClient, double dltotal, double dlnow, double ultotal, double ulnow)
{
CHttpClient * httpClient = static_cast<CHttpClient*>(pHttpClient);
return httpClient->onProgress(dltotal, dlnow, ultotal, ulnow);
}
int CHttpClient::_InstanceCount = 0;
MUTEX_TYPE CHttpClient::_MutexInstanceCount = GET_MUTEX_SETUP;
// ***************************************************************************
bool CHttpClient::init()
{
if (_Initialized)
return true;
ctassert(MY_CURL_ERROR_SIZE == CURL_ERROR_SIZE);
ctassert(ErrorInvalidFile == CURLE_READ_ERROR);
// Global init
MUTEX_LOCK(_MutexInstanceCount);
if (_InstanceCount==0)
{
#ifdef USE_OPENSSL
if (!CRYPTO_thread_setup())
logStr("WRN: Could not setup crypto locking functions");
#endif
curl_global_init(CURL_GLOBAL_ALL);
}
++_InstanceCount;
MUTEX_UNLOCK(_MutexInstanceCount);
curl_version_info_data *vdata = curl_version_info(CURLVERSION_NOW);
//logStr("Libcurl v%s", vdata->version);
if ((vdata->features & CURL_VERSION_SSL) == 0)
logStr("WRN: SSL not supported");
_Curl = curl_easy_init();
if(_Curl == NULL)
return false;
_CookiesList.clear();
_Initialized = true;
return true;
}
// ***************************************************************************
void CHttpClient::setProxy(const char *ip_port)
{
curl_easy_setopt(_Curl, CURLOPT_PROXY, ip_port);
}
// ***************************************************************************
void CHttpClient::setUserAgent(const char *userAgent)
{
_UserAgentStr.clear();
_UserAgentStr.appendStrCat(userAgent, MaxUserAgentChars);
}
// ***************************************************************************
bool CHttpClient::setCredentials(const char *user, const char *password)
{
_AuthStr.clear();
if ((user == NULL) || (user[0] == '\0'))
return true;
_AuthStr.appendStrCat(user, MaxUserChars);
_AuthStr.appendStrCat(":", 1);
_AuthStr.appendStrCat(password, MaxPasswordChars);
return true;
}
// ***************************************************************************
bool CHttpClient::setCredentials(const char *userPassword)
{
_AuthStr.clear();
if ((userPassword == NULL) || (userPassword[0] == '\0'))
return true;
_AuthStr.appendStrCat(userPassword, MaxUserChars+1+MaxPasswordChars);
return true;
}
// ***************************************************************************
bool CHttpClient::setCookie(const char *cookieName, const char *cookieValue)
{
//_CookieStr.clear();
if ((cookieName == NULL) || (cookieName[0] == '\0'))
return true;
if(_CookiesList.find(std::string(cookieName)) != _CookiesList.end())
{
_CookiesList.erase(_CookiesList.find(std::string(cookieName)));
}
_CookiesList.insert( std::make_pair (std::string(cookieName), std::string(cookieValue)));
//_CookieStr.appendStrCat(cookieName, MaxCookieNameChars);
//_CookieStr.appendStrCat("=", 1);
//_CookieStr.appendStrCat(cookieValue, MaxCookieValueChars);
return true;
}
// ***************************************************************************
void CHttpClient::resetCookie()
{
_CookieStr.clear();
_CookiesList.clear();
}
//const char *CAFilename = "./ssl_ca_cert.pem";
// ***************************************************************************
bool CHttpClient::setVerifyServer(bool verify, const char *certicatesFilename)
{
curl_easy_setopt(_Curl, CURLOPT_SSL_VERIFYHOST, verify ? 2 : 0); // set to compare the actual server hostname with the hostname specified in the certificate coming from the server
curl_easy_setopt(_Curl, CURLOPT_SSL_VERIFYPEER, verify ? 1 : 0); // set to check that the certificate coming from the server is valid (needs local certificate to check against)
//curl_easy_setopt(_Curl, CURLOPT_SSL_CTX_FUNCTION, *sslctx_function); // would allow to provide the CA in memory instead of using CURLOPT_CAINFO, but needs to include and link OpenSSL
curl_easy_setopt(_Curl, CURLOPT_CAINFO, certicatesFilename); // only needed if the default OpenSSL CA certificates are not sufficient to validate the server certificate
//curl_easy_setopt(_Curl, CURLOPT_CAPATH, NULL);
//curl_easy_setopt(_Curl, CURLOPT_SSLCERTTYPE, "PEM");
return true;
}
// ***************************************************************************
bool CHttpClient::sendRequest(const char *pageURL, const char *paramStr, bool isPostRequest, bool wantHeader, bool verbose)
{
_Headers.clear();
_ReceiveBuffer.clear();
//HttpPage().swap(_ReceiveBuffer);
if (verbose)
curl_easy_setopt(_Curl, CURLOPT_VERBOSE, 1);
if (!_UserAgentStr.empty())
{
curl_easy_setopt(_Curl, CURLOPT_USERAGENT, _UserAgentStr.c_str());
}
// Authentication
if (!_AuthStr.empty())
{
curl_easy_setopt(_Curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
curl_easy_setopt(_Curl, CURLOPT_USERPWD, _AuthStr.c_str());
curl_easy_setopt(_Curl, CURLOPT_UNRESTRICTED_AUTH, 1);
}
if ((paramStr == NULL) || (paramStr[0] == '\0'))
{
// Just set URL
curl_easy_setopt(_Curl, CURLOPT_URL, pageURL);
curl_easy_setopt(_Curl, CURLOPT_POST, false);
}
else
{
if (isPostRequest)
{
// Set URL and post params
curl_easy_setopt(_Curl, CURLOPT_URL, pageURL);
curl_easy_setopt(_Curl, CURLOPT_POST, true);
curl_easy_setopt(_Curl, CURLOPT_POSTFIELDS, paramStr);
}
else
{
// Append params to URL
SimpleString<MaxURLChars> urlWithParams;
urlWithParams.appendStrCat(pageURL, MaxPageURLChars);
urlWithParams.appendStrCat("?", 1);
urlWithParams.appendStrCat(paramStr, MaxURLParamChars);
curl_easy_setopt(_Curl, CURLOPT_HTTPGET, true);
curl_easy_setopt(_Curl, CURLOPT_URL, urlWithParams.c_str());
}
}
// Cookie
if (!_CookiesList.empty())
{
// curl_easy_setopt(_Curl, CURLOPT_COOKIEFILE, "C:\c.txt");//_CookieStr.c_str());
// Make Cookies
std::string listC("");
for (CookiesList::iterator it = _CookiesList.begin(); it != _CookiesList.end(); ++ it)
{
listC = listC + it->first + std::string("=") + it->second + std::string(";");
}
//logStr("Cookies CURL=%s", listC.c_str());
curl_easy_setopt(_Curl, CURLOPT_COOKIE, listC.c_str());
}
if (wantHeader)
{
// Include the header in the response
curl_easy_setopt(_Curl, CURLOPT_HEADER, 1);
}
// Register the receive callback
curl_easy_setopt(_Curl, CURLOPT_WRITEFUNCTION, onDataReceivedCallback);
curl_easy_setopt(_Curl, CURLOPT_WRITEDATA, this);
curl_easy_setopt(_Curl, CURLOPT_HEADERFUNCTION, onHeaderReceivedCallback);
curl_easy_setopt(_Curl, CURLOPT_WRITEHEADER, this);
// Register the progress callback (this make the requests interruptable)
curl_easy_setopt(_Curl, CURLOPT_NOPROGRESS, FALSE);
curl_easy_setopt(_Curl, CURLOPT_PROGRESSFUNCTION, onProgressCallback);
curl_easy_setopt(_Curl, CURLOPT_PROGRESSDATA, this);
curl_easy_setopt(_Curl, CURLOPT_ERRORBUFFER, _CurlErrorString.Buf);
// Redirection options
if(_WantRedirection)
{
curl_easy_setopt(_Curl, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(_Curl, CURLOPT_MAXREDIRS, _MaxRedirection);
}
else
{
curl_easy_setopt(_Curl, CURLOPT_FOLLOWLOCATION, 0);
}
curl_easy_setopt(_Curl, CURLOPT_POST301, 1); // aka CURLOPT_POSTREDIR in newer versions of Curl
curl_easy_setopt(_Curl, CURLOPT_UNRESTRICTED_AUTH, 1);
curl_easy_setopt(_Curl, CURLOPT_AUTOREFERER, 1);
// Send
_RequestCode = curl_easy_perform(_Curl);
if (_RequestCode != 0)
{
if (verbose)
logStr("WRN: %s", _CurlErrorString.c_str());
return false;
}
// Get result
curl_easy_getinfo(_Curl, CURLINFO_RESPONSE_CODE, &_RequestCode);
if (verbose)
logStr("Response Code: %u", _RequestCode);
return true;
}
// ***************************************************************************
bool CHttpClient::addMultipartParam(const char *field, const MultipartParam& value)
{
switch (value.Source)
{
case CHttpClient::ParamCString:
return (curl_formadd((curl_httppost**)&_FirstParamStruct, (curl_httppost**)&_LastParamStruct,
CURLFORM_COPYNAME, field,
CURLFORM_COPYCONTENTS, value.Str,
CURLFORM_END) == 0);
//break;
case CHttpClient::ParamLoadFile:
return (curl_formadd((curl_httppost**)&_FirstParamStruct, (curl_httppost**)&_LastParamStruct,
CURLFORM_COPYNAME, field,
CURLFORM_FILE, value.Str,
CURLFORM_END) == 0);
//break;
default:;
}
return false;
}
// ***************************************************************************
bool CHttpClient::sendMultipartRequest(const char *pageURL, bool wantHeader, bool verbose)
{
_Headers.clear();
_ReceiveBuffer.clear();
if (verbose)
curl_easy_setopt(_Curl, CURLOPT_VERBOSE, 1);
if (!_UserAgentStr.empty())
{
curl_easy_setopt(_Curl, CURLOPT_USERAGENT, _UserAgentStr.c_str());
}
// Authentication
if (!_AuthStr.empty())
{
curl_easy_setopt(_Curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
curl_easy_setopt(_Curl, CURLOPT_USERPWD, _AuthStr.c_str());
}
// URL and params
curl_easy_setopt(_Curl, CURLOPT_URL, pageURL);
curl_easy_setopt(_Curl, CURLOPT_HTTPPOST, (curl_httppost *)_FirstParamStruct);
// Cookie
if (!_CookieStr.empty())
curl_easy_setopt(_Curl, CURLOPT_COOKIE, _CookieStr.c_str());
if (wantHeader)
{
// Include the header in the response
curl_easy_setopt(_Curl, CURLOPT_HEADER, 1);
}
// Register the receive callback
curl_easy_setopt(_Curl, CURLOPT_WRITEFUNCTION, onDataReceivedCallback);
curl_easy_setopt(_Curl, CURLOPT_WRITEDATA, this);
curl_easy_setopt(_Curl, CURLOPT_HEADERFUNCTION, onHeaderReceivedCallback);
curl_easy_setopt(_Curl, CURLOPT_WRITEHEADER, this);
// Register the progress callback (this make the requests interruptable)
curl_easy_setopt(_Curl, CURLOPT_NOPROGRESS, FALSE);
curl_easy_setopt(_Curl, CURLOPT_PROGRESSFUNCTION, onProgressCallback);
curl_easy_setopt(_Curl, CURLOPT_PROGRESSDATA, this);
ctassert(MY_CURL_ERROR_SIZE == CURL_ERROR_SIZE);
curl_easy_setopt(_Curl, CURLOPT_ERRORBUFFER, _CurlErrorString.Buf);
// Send
_RequestCode = curl_easy_perform(_Curl);
curl_formfree((curl_httppost *)_FirstParamStruct);
_FirstParamStruct = NULL;
_LastParamStruct = NULL;
if (_RequestCode != 0)
{
if (verbose)
logStr("WRN: %s", _CurlErrorString.c_str());
return false;
}
// Get result
curl_easy_getinfo(_Curl, CURLINFO_RESPONSE_CODE, &_RequestCode);
if (verbose)
logStr("Response Code: %u", _RequestCode);
return true;
}
// ***************************************************************************
void CHttpClient::onDataReceived(char * buffer, size_t size)
{
#ifdef DYNALLOC_HTTPCLIENT
_ReceiveBuffer.insert(_ReceiveBuffer.end(), buffer, buffer+size);
#else
_ReceiveBuffer.appendBinary(buffer, size);
#endif
}
// ***************************************************************************
void CHttpClient::onHeaderReceived(char * buffer, size_t size)
{
// Parse and store into map
std::string s(buffer, buffer+size);
std::string::size_type p = s.find(":");
if (p != std::string::npos)
{
// Ex: "Content-Type" -> "text/html"
std::string::size_type q = p+1;
while (q<s.size() && s[q]==' ')
++q; // skip blank chars after ':'
_Headers[s.substr(0, p)] = s.substr(q, s.rfind("\r\n")-q);
}
else
{
// Ex: "HTTP/1.1 200 OK" -> ""
_Headers[s.substr(0, s.rfind("\r\n"))] = std::string();
}
}
// ***************************************************************************
int CHttpClient::onProgress(double dltotal, double dlnow, double ultotal, double ulnow)
{
#ifdef SIMULATE_SLOW_UPLOAD
if (ultotal != 0)
Sleep(1000);
#endif
_DLTotal = dltotal;
_DLNow = dlnow;
_ULTotal = ultotal;
_ULNow = ulnow;
return (isAborting() ? 1 : 0);
}
// ***************************************************************************
#ifndef USER_MODE
unsigned int CHttpClient::getMemoryUsage() const
{
MUTEX_LOCK(_MutexInstanceCount);
unsigned int size = 0;
size += sizeof(*this);
size += sizeof(char) * (MaxUserAgentChars + MaxAuthChars + MaxCookieChars + MY_CURL_ERROR_SIZE + 1);
// sizeof _Headers
for(HeaderMap::const_iterator it = _Headers.begin(); it != _Headers.end(); ++ it)
{
size += sizeof(std::string::value_type) * (it->first.capacity() + it->second.capacity());
}
size += _ReceiveBuffer.capacity() * sizeof(std::string::value_type);
MUTEX_UNLOCK(_MutexInstanceCount);
return size;
}
#endif
// ***************************************************************************
const HttpPage& CHttpClient::getResponsePage(bool verbose) const
{
if (verbose)
logStr("Accessing %u bytes", _ReceiveBuffer.size());
return _ReceiveBuffer;
}
// ***************************************************************************
HttpPage& CHttpClient::getAndEditResponsePage(bool verbose)
{
if (verbose)
logStr("Accessing/editing %u bytes", _ReceiveBuffer.size());
return _ReceiveBuffer;
}
// ***************************************************************************
void BackgroundTaskRun(void *instance)
{
(static_cast<CBackgroundTask*>(instance))->run();
}
// ***************************************************************************
bool CBackgroundTask::start()
{
_IsRunning = true;
_beginthread(BackgroundTaskRun, 0, this);
return true;
}
// ***************************************************************************
void CBackgroundTask::waitForExit()
{
while (_IsRunning)
{
Sleep(10);
}
}
// ***************************************************************************
void CHttpClient::release()
{
curl_easy_cleanup(_Curl);
_Initialized = false;
// Global cleanup
MUTEX_LOCK(_MutexInstanceCount);
--_InstanceCount;
if (_InstanceCount == 0)
{
curl_global_cleanup();
#ifdef USE_OPENSSL
CRYPTO_thread_cleanup();
#endif
}
MUTEX_UNLOCK(_MutexInstanceCount);
}
// ***************************************************************************
CHttpClient::~CHttpClient()
{
if (_Initialized)
release();
}
// ***************************************************************************
bool CHttpClient::nextTryAutoConfigureProxy(const char *url, void* hSession)
{
// Windows-specific code (needs XP SP1 or newer)
// If previous calls could not deduce the proxy, abandon
if (_CurrentPacm == PacmFailed)
{
logStr(__FUNCTION__"-error: could not determine proxy");
if (hSession)
WinHttpCloseHandle(hSession);
return false;
}
// A WinHttp session is needed for certain calls
if (!hSession)
{
hSession = WinHttpOpen(NULL, WINHTTP_ACCESS_TYPE_NO_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
if (!hSession)
return false;
}
BOOL res = false;
switch (_CurrentPacm)
{
case PacmDirectConnection:
{
const char *curlProxy = getProxy();
if ((curlProxy == NULL) || (*curlProxy != NULL)) // try only if a proxy is set, because we get here only when a connection failed
{
logStr(__FUNCTION__"-info: trying direct connection...");
setProxy("");
res = true;
}
}
break;
case PacmHostname:
case PacmWPADURL:
// WPAD protocol not configured => try to get settings from IE as a fall-back
logStr(__FUNCTION__"-info: reading IE proxy config...");
WINHTTP_CURRENT_USER_IE_PROXY_CONFIG ieCfg;
res = WinHttpGetIEProxyConfigForCurrentUser(&ieCfg);
if (res)
{
res = false;
if ((_CurrentPacm == PacmHostname) && ieCfg.lpszProxy)
{
logStr(__FUNCTION__"-info: using proxy hostname...");
char proxyAddr [2048];
wcstombs(proxyAddr, ieCfg.lpszProxy, 2047);
setProxy(proxyAddr);
res = true;
// ideally, should take ieCfg.lpszProxyBypass into account
}
else if ((_CurrentPacm == PacmWPADURL) && ieCfg.lpszAutoConfigUrl)
{
logStr(__FUNCTION__"-info: trying WPAD proxy auto-config from URL...");
res = setProxyFromWPAD((void*)hSession, url, ieCfg.lpszAutoConfigUrl);
}
}
if (ieCfg.lpszProxy)
GlobalFree(ieCfg.lpszProxy);
if (ieCfg.lpszAutoConfigUrl)
GlobalFree(ieCfg.lpszAutoConfigUrl);
if (ieCfg.lpszProxyBypass)
GlobalFree(ieCfg.lpszProxyBypass);
break;
case PacmDNS:
// Try DNS-based auto-detection (using 'wpad' host), not DHCP-based (said to have issues)
logStr(__FUNCTION__"-info: trying WPAD proxy auto-detection...");
res = setProxyFromWPAD((void*)hSession, url, L"http://wpad/wpad.dat");
break;
case PacmFullAuto:
// Try full auto-detection (including DHCP) as a last resort
logStr(__FUNCTION__"-info: trying full proxy auto-detection...");
res = setProxyFromWPAD((void*)hSession, url, NULL);
break;
default:
_CurrentPacm = PacmBeforeFailed;
}
++_CurrentPacm; // set-up for next (potential) call
if (res)
{
// Return success to try connecting
logStr(__FUNCTION__"-info: proxy set");
WinHttpCloseHandle(hSession);
return true;
}
else
{
// Try next proxy auto-config method
return nextTryAutoConfigureProxy(url, hSession);
}
}
// ***************************************************************************
bool CHttpClient::setProxyFromWPAD(void *hSession, const char *url, const wchar_t *wpadwURL)
{
// Windows-specific code, adapted from Google Chromium (needs XP SP1 or newer)
WINHTTP_AUTOPROXY_OPTIONS options = {0};
options.fAutoLogonIfChallenged = TRUE;
if (wpadwURL)
{
options.dwFlags = WINHTTP_AUTOPROXY_CONFIG_URL;
options.lpszAutoConfigUrl = wpadwURL;
}
else
{
options.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT,
options.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A;
}
WINHTTP_PROXY_INFO info = {0};
wchar_t wurl[2048];
mbstowcs(wurl, url, 2047);
BOOL res = WinHttpGetProxyForUrl(hSession, wurl, &options, &info);
if (res)
{
// Set proxy
res = true;
switch (info.dwAccessType)
{
case WINHTTP_ACCESS_TYPE_NO_PROXY:
setProxy("");
break;
case WINHTTP_ACCESS_TYPE_NAMED_PROXY:
char proxyAddr [2048];
wcstombs(proxyAddr, info.lpszProxy, 2047);
setProxy(proxyAddr);
break;
default:
res = false;
}
}
// Clean-up
if (info.lpszProxy)
GlobalFree(info.lpszProxy);
if (info.lpszProxyBypass)
GlobalFree(info.lpszProxyBypass);
return (bool)res;
}
// ***************************************************************************
const char *CHttpClient::getProxy() const
{
return curl_easy_getopt_proxy(_Curl);
}
#endif // ONLINE_MODE