2
0

WinHttpClient.h 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842
  1. /**
  2. * Copyright 2008-2010 Cheng Shi. All rights reserved.
  3. * Email: shicheng107@hotmail.com
  4. */
  5. #ifndef WINHTTPCLIENT_H
  6. #define WINHTTPCLIENT_H
  7. #pragma comment(lib, "Winhttp.lib")
  8. #include "RegExp.h"
  9. #include "StringProcess.h"
  10. #include <comutil.h>
  11. #include <windows.h>
  12. #include <Winhttp.h>
  13. #include <string>
  14. using namespace std;
  15. typedef bool (*PROGRESSPROC)(double);
  16. static const unsigned int INT_RETRYTIMES = 3;
  17. static wchar_t *SZ_AGENT = L"WinHttpClient";
  18. static const int INT_BUFFERSIZE = 10240; // Initial 10 KB temporary buffer, double if it is not enough.
  19. class WinHttpClient
  20. {
  21. public:
  22. inline WinHttpClient(const wstring &url, PROGRESSPROC progressProc = NULL);
  23. inline ~WinHttpClient(void);
  24. // It is a synchronized method and may take a long time to finish.
  25. inline bool SendHttpRequest(const wstring &httpVerb = L"GET", bool disableAutoRedirect = false);
  26. inline wstring GetResponseHeader(void);
  27. inline wstring GetResponseContent(void);
  28. inline wstring GetResponseCharset(void);
  29. inline wstring GetResponseStatusCode(void);
  30. inline wstring GetResponseLocation(void);
  31. inline wstring GetRequestHost(void);
  32. inline const BYTE *GetRawResponseContent(void);
  33. inline unsigned int GetRawResponseContentLength(void);
  34. inline unsigned int GetRawResponseReceivedContentLength(void);
  35. inline bool SaveResponseToFile(const wstring &filePath);
  36. inline wstring GetResponseCookies(void);
  37. inline bool SetAdditionalRequestCookies(const wstring &cookies);
  38. inline bool SetAdditionalDataToSend(BYTE *data, unsigned int dataSize);
  39. inline bool UpdateUrl(const wstring &url);
  40. inline bool ResetAdditionalDataToSend(void);
  41. inline bool SetAdditionalRequestHeaders(const wstring &additionalRequestHeaders);
  42. inline bool SetRequireValidSslCertificates(bool require);
  43. inline bool SetProxy(const wstring &proxy);
  44. inline DWORD GetLastError(void);
  45. inline bool SetUserAgent(const wstring &userAgent);
  46. inline bool SetForceCharset(const wstring &charset);
  47. inline bool SetProxyUsername(const wstring &username);
  48. inline bool SetProxyPassword(const wstring &password);
  49. inline bool SetTimeouts(unsigned int resolveTimeout = 0,
  50. unsigned int connectTimeout = 60000,
  51. unsigned int sendTimeout = 30000,
  52. unsigned int receiveTimeout = 30000);
  53. private:
  54. inline WinHttpClient(const WinHttpClient &other);
  55. inline WinHttpClient &operator =(const WinHttpClient &other);
  56. inline bool SetProgress(unsigned int byteCountReceived);
  57. HINTERNET m_sessionHandle;
  58. bool m_requireValidSsl;
  59. wstring m_requestURL;
  60. wstring m_requestHost;
  61. wstring m_responseHeader;
  62. wstring m_responseContent;
  63. wstring m_responseCharset;
  64. BYTE *m_pResponse;
  65. unsigned int m_responseByteCountReceived; // Up to 4GB.
  66. PROGRESSPROC m_pfProcessProc;
  67. unsigned int m_responseByteCount;
  68. wstring m_responseCookies;
  69. wstring m_additionalRequestCookies;
  70. BYTE *m_pDataToSend;
  71. unsigned int m_dataToSendSize;
  72. wstring m_additionalRequestHeaders;
  73. wstring m_proxy;
  74. DWORD m_dwLastError;
  75. wstring m_statusCode;
  76. wstring m_userAgent;
  77. bool m_bForceCharset;
  78. wstring m_proxyUsername;
  79. wstring m_proxyPassword;
  80. wstring m_location;
  81. unsigned int m_resolveTimeout;
  82. unsigned int m_connectTimeout;
  83. unsigned int m_sendTimeout;
  84. unsigned int m_receiveTimeout;
  85. };
  86. WinHttpClient::WinHttpClient(const wstring &url, PROGRESSPROC progressProc)
  87. : m_requestURL(url),
  88. m_sessionHandle(NULL),
  89. m_requireValidSsl(false),
  90. m_responseHeader(L""),
  91. m_responseContent(L""),
  92. m_responseCharset(L""),
  93. m_requestHost(L""),
  94. m_pResponse(NULL),
  95. m_responseByteCountReceived(0),
  96. m_pfProcessProc(progressProc),
  97. m_responseByteCount(0),
  98. m_responseCookies(L""),
  99. m_additionalRequestCookies(L""),
  100. m_pDataToSend(NULL),
  101. m_dataToSendSize(0),
  102. m_proxy(L""),
  103. m_dwLastError(0),
  104. m_statusCode(L""),
  105. m_userAgent(SZ_AGENT),
  106. m_bForceCharset(false),
  107. m_proxyUsername(L""),
  108. m_proxyPassword(L""),
  109. m_location(L""),
  110. m_resolveTimeout(0),
  111. m_connectTimeout(60000),
  112. m_sendTimeout(30000),
  113. m_receiveTimeout(30000)
  114. {
  115. }
  116. WinHttpClient::~WinHttpClient(void)
  117. {
  118. if (m_pResponse != NULL)
  119. {
  120. delete[] m_pResponse;
  121. }
  122. if (m_pDataToSend != NULL)
  123. {
  124. delete[] m_pDataToSend;
  125. }
  126. if (m_sessionHandle != NULL)
  127. {
  128. ::WinHttpCloseHandle(m_sessionHandle);
  129. }
  130. }
  131. bool WinHttpClient::SendHttpRequest(const wstring &httpVerb, bool disableAutoRedirect)
  132. {
  133. if (m_requestURL.size() <= 0)
  134. {
  135. m_dwLastError = ERROR_PATH_NOT_FOUND;
  136. return false;
  137. }
  138. // Make verb uppercase.
  139. wstring verb = httpVerb;
  140. if (_wcsicmp(verb.c_str(), L"GET") == 0)
  141. {
  142. verb = L"GET";
  143. }
  144. else if (_wcsicmp(verb.c_str(), L"POST") == 0)
  145. {
  146. verb = L"POST";
  147. }
  148. else
  149. {
  150. m_dwLastError = ERROR_INVALID_PARAMETER;
  151. return false;
  152. }
  153. bool bRetVal = true;
  154. if (m_sessionHandle == NULL)
  155. {
  156. m_sessionHandle = ::WinHttpOpen(m_userAgent.c_str(),
  157. WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
  158. WINHTTP_NO_PROXY_NAME,
  159. WINHTTP_NO_PROXY_BYPASS,
  160. 0);
  161. if (m_sessionHandle == NULL)
  162. {
  163. m_dwLastError = ::GetLastError();
  164. return false;
  165. }
  166. }
  167. ::WinHttpSetTimeouts(m_sessionHandle,
  168. m_resolveTimeout,
  169. m_connectTimeout,
  170. m_sendTimeout,
  171. m_receiveTimeout);
  172. wchar_t szHostName[MAX_PATH] = L"";
  173. wchar_t szURLPath[MAX_PATH * 5] = L"";
  174. URL_COMPONENTS urlComp;
  175. memset(&urlComp, 0, sizeof(urlComp));
  176. urlComp.dwStructSize = sizeof(urlComp);
  177. urlComp.lpszHostName = szHostName;
  178. urlComp.dwHostNameLength = MAX_PATH;
  179. urlComp.lpszUrlPath = szURLPath;
  180. urlComp.dwUrlPathLength = MAX_PATH * 5;
  181. urlComp.dwSchemeLength = 1; // None zero
  182. if (::WinHttpCrackUrl(m_requestURL.c_str(), m_requestURL.size(), 0, &urlComp))
  183. {
  184. m_requestHost = szHostName;
  185. HINTERNET hConnect = NULL;
  186. hConnect = ::WinHttpConnect(m_sessionHandle, szHostName, urlComp.nPort, 0);
  187. if (hConnect != NULL)
  188. {
  189. DWORD dwOpenRequestFlag = (urlComp.nScheme == INTERNET_SCHEME_HTTPS) ? WINHTTP_FLAG_SECURE : 0;
  190. HINTERNET hRequest = NULL;
  191. hRequest = ::WinHttpOpenRequest(hConnect,
  192. verb.c_str(),
  193. urlComp.lpszUrlPath,
  194. NULL,
  195. WINHTTP_NO_REFERER,
  196. WINHTTP_DEFAULT_ACCEPT_TYPES,
  197. dwOpenRequestFlag);
  198. if (hRequest != NULL)
  199. {
  200. // If HTTPS, then client is very susceptable to invalid certificates
  201. // Easiest to accept anything for now
  202. if (!m_requireValidSsl && urlComp.nScheme == INTERNET_SCHEME_HTTPS)
  203. {
  204. DWORD options = SECURITY_FLAG_IGNORE_CERT_CN_INVALID
  205. | SECURITY_FLAG_IGNORE_CERT_DATE_INVALID
  206. | SECURITY_FLAG_IGNORE_UNKNOWN_CA;
  207. ::WinHttpSetOption(hRequest,
  208. WINHTTP_OPTION_SECURITY_FLAGS,
  209. (LPVOID)&options,
  210. sizeof(DWORD));
  211. }
  212. bool bGetReponseSucceed = false;
  213. unsigned int iRetryTimes = 0;
  214. // Retry for several times if fails.
  215. while (!bGetReponseSucceed && iRetryTimes++ < INT_RETRYTIMES)
  216. {
  217. if (m_additionalRequestHeaders.size() > 0)
  218. {
  219. if (!::WinHttpAddRequestHeaders(hRequest, m_additionalRequestHeaders.c_str(), m_additionalRequestHeaders.size(), WINHTTP_ADDREQ_FLAG_COALESCE_WITH_SEMICOLON))
  220. {
  221. m_dwLastError = ::GetLastError();
  222. }
  223. }
  224. if (m_additionalRequestCookies.size() > 0)
  225. {
  226. wstring cookies = L"Cookie: ";
  227. cookies += m_additionalRequestCookies;
  228. if (!::WinHttpAddRequestHeaders(hRequest, cookies.c_str(), cookies.size(), WINHTTP_ADDREQ_FLAG_COALESCE_WITH_SEMICOLON))
  229. {
  230. m_dwLastError = ::GetLastError();
  231. }
  232. }
  233. if (m_proxy.size() > 0)
  234. {
  235. WINHTTP_PROXY_INFO proxyInfo;
  236. memset(&proxyInfo, 0, sizeof(proxyInfo));
  237. proxyInfo.dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
  238. wchar_t szProxy[MAX_PATH] = L"";
  239. wcscpy_s(szProxy, MAX_PATH, m_proxy.c_str());
  240. proxyInfo.lpszProxy = szProxy;
  241. if (!::WinHttpSetOption(hRequest, WINHTTP_OPTION_PROXY, &proxyInfo, sizeof(proxyInfo)))
  242. {
  243. m_dwLastError = ::GetLastError();
  244. }
  245. if (m_proxyUsername.size() > 0)
  246. {
  247. if (!::WinHttpSetOption(hRequest, WINHTTP_OPTION_PROXY_USERNAME, (LPVOID)m_proxyUsername.c_str(), m_proxyUsername.size() * sizeof(wchar_t)))
  248. {
  249. m_dwLastError = ::GetLastError();
  250. }
  251. if (m_proxyPassword.size() > 0)
  252. {
  253. if (!::WinHttpSetOption(hRequest, WINHTTP_OPTION_PROXY_PASSWORD, (LPVOID)m_proxyPassword.c_str(), m_proxyPassword.size() * sizeof(wchar_t)))
  254. {
  255. m_dwLastError = ::GetLastError();
  256. }
  257. }
  258. }
  259. }
  260. if (disableAutoRedirect)
  261. {
  262. DWORD dwDisableFeature = WINHTTP_DISABLE_REDIRECTS;
  263. if (!::WinHttpSetOption(hRequest, WINHTTP_OPTION_DISABLE_FEATURE, &dwDisableFeature, sizeof(dwDisableFeature)))
  264. {
  265. m_dwLastError = ::GetLastError();
  266. }
  267. }
  268. bool bSendRequestSucceed = false;
  269. if (::WinHttpSendRequest(hRequest,
  270. WINHTTP_NO_ADDITIONAL_HEADERS,
  271. 0,
  272. WINHTTP_NO_REQUEST_DATA,
  273. 0,
  274. 0,
  275. NULL))
  276. {
  277. bSendRequestSucceed = true;
  278. }
  279. else
  280. {
  281. // Query the proxy information from IE setting and set the proxy if any.
  282. WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxyConfig;
  283. memset(&proxyConfig, 0, sizeof(proxyConfig));
  284. if (::WinHttpGetIEProxyConfigForCurrentUser(&proxyConfig))
  285. {
  286. if (proxyConfig.lpszAutoConfigUrl != NULL)
  287. {
  288. WINHTTP_AUTOPROXY_OPTIONS autoProxyOptions;
  289. memset(&autoProxyOptions, 0, sizeof(autoProxyOptions));
  290. autoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT | WINHTTP_AUTOPROXY_CONFIG_URL;
  291. autoProxyOptions.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP;
  292. autoProxyOptions.lpszAutoConfigUrl = proxyConfig.lpszAutoConfigUrl;
  293. autoProxyOptions.fAutoLogonIfChallenged = TRUE;
  294. autoProxyOptions.dwReserved = 0;
  295. autoProxyOptions.lpvReserved = NULL;
  296. WINHTTP_PROXY_INFO proxyInfo;
  297. memset(&proxyInfo, 0, sizeof(proxyInfo));
  298. if (::WinHttpGetProxyForUrl(m_sessionHandle, m_requestURL.c_str(), &autoProxyOptions, &proxyInfo))
  299. {
  300. if (::WinHttpSetOption(hRequest, WINHTTP_OPTION_PROXY, &proxyInfo, sizeof(proxyInfo)))
  301. {
  302. if (::WinHttpSendRequest(hRequest,
  303. WINHTTP_NO_ADDITIONAL_HEADERS,
  304. 0,
  305. WINHTTP_NO_REQUEST_DATA,
  306. 0,
  307. 0,
  308. NULL))
  309. {
  310. bSendRequestSucceed = true;
  311. }
  312. }
  313. if (proxyInfo.lpszProxy != NULL)
  314. {
  315. ::GlobalFree(proxyInfo.lpszProxy);
  316. }
  317. if (proxyInfo.lpszProxyBypass != NULL)
  318. {
  319. ::GlobalFree(proxyInfo.lpszProxyBypass);
  320. }
  321. }
  322. else
  323. {
  324. m_dwLastError = ::GetLastError();
  325. }
  326. }
  327. else if (proxyConfig.lpszProxy != NULL)
  328. {
  329. WINHTTP_PROXY_INFO proxyInfo;
  330. memset(&proxyInfo, 0, sizeof(proxyInfo));
  331. proxyInfo.dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
  332. wchar_t szProxy[MAX_PATH] = L"";
  333. wcscpy_s(szProxy, MAX_PATH, proxyConfig.lpszProxy);
  334. proxyInfo.lpszProxy = szProxy;
  335. if (proxyConfig.lpszProxyBypass != NULL)
  336. {
  337. wchar_t szProxyBypass[MAX_PATH] = L"";
  338. wcscpy_s(szProxyBypass, MAX_PATH, proxyConfig.lpszProxyBypass);
  339. proxyInfo.lpszProxyBypass = szProxyBypass;
  340. }
  341. if (!::WinHttpSetOption(hRequest, WINHTTP_OPTION_PROXY, &proxyInfo, sizeof(proxyInfo)))
  342. {
  343. m_dwLastError = ::GetLastError();
  344. }
  345. }
  346. if (proxyConfig.lpszAutoConfigUrl != NULL)
  347. {
  348. ::GlobalFree(proxyConfig.lpszAutoConfigUrl);
  349. }
  350. if (proxyConfig.lpszProxy != NULL)
  351. {
  352. ::GlobalFree(proxyConfig.lpszProxy);
  353. }
  354. if (proxyConfig.lpszProxyBypass != NULL)
  355. {
  356. ::GlobalFree(proxyConfig.lpszProxyBypass);
  357. }
  358. }
  359. else
  360. {
  361. m_dwLastError = ::GetLastError();
  362. }
  363. }
  364. if (bSendRequestSucceed)
  365. {
  366. if (m_pDataToSend != NULL)
  367. {
  368. DWORD dwWritten = 0;
  369. if (!::WinHttpWriteData(hRequest,
  370. m_pDataToSend,
  371. m_dataToSendSize,
  372. &dwWritten))
  373. {
  374. m_dwLastError = ::GetLastError();
  375. }
  376. }
  377. if (::WinHttpReceiveResponse(hRequest, NULL))
  378. {
  379. DWORD dwSize = 0;
  380. BOOL bResult = FALSE;
  381. bResult = ::WinHttpQueryHeaders(hRequest,
  382. WINHTTP_QUERY_RAW_HEADERS_CRLF,
  383. WINHTTP_HEADER_NAME_BY_INDEX,
  384. NULL,
  385. &dwSize,
  386. WINHTTP_NO_HEADER_INDEX);
  387. if (bResult || (!bResult && (::GetLastError() == ERROR_INSUFFICIENT_BUFFER)))
  388. {
  389. wchar_t *szHeader = new wchar_t[dwSize];
  390. if (szHeader != NULL)
  391. {
  392. memset(szHeader, 0, dwSize* sizeof(wchar_t));
  393. if (::WinHttpQueryHeaders(hRequest,
  394. WINHTTP_QUERY_RAW_HEADERS_CRLF,
  395. WINHTTP_HEADER_NAME_BY_INDEX,
  396. szHeader,
  397. &dwSize,
  398. WINHTTP_NO_HEADER_INDEX))
  399. {
  400. m_responseHeader.assign(szHeader);
  401. vector<wstring> result;
  402. wstring regExp = L"";
  403. if (!m_bForceCharset)
  404. {
  405. regExp = L"charset={[A-Za-z0-9\\-_]+}";
  406. if (ParseRegExp(regExp, false, 1, m_responseHeader, result) && result.size() > 0)
  407. {
  408. m_responseCharset = result[0];
  409. }
  410. }
  411. regExp = L"Content-Length: {[0-9]+}";
  412. if (ParseRegExp(regExp, false, 1, m_responseHeader, result) && result.size() > 0)
  413. {
  414. m_responseByteCount = (unsigned int)_wtoi(result[0].c_str());
  415. }
  416. regExp = L"Location: {[0-9]+}";
  417. if (ParseRegExp(regExp, false, 1, m_responseHeader, result) && result.size() > 0)
  418. {
  419. m_location = result[0];
  420. }
  421. regExp = L"Set-Cookie:\\b*{.+?}\\n";
  422. if (ParseRegExp(regExp, false, 1, m_responseHeader, result) && result.size() > 0)
  423. {
  424. for (vector<wstring>::size_type i = 0; i < result.size(); i++)
  425. {
  426. m_responseCookies += result[i];
  427. if (i != result.size() - 1)
  428. {
  429. m_responseCookies += L"; ";
  430. }
  431. }
  432. m_responseCookies = Trim(m_responseCookies, L" ");
  433. if (m_responseCookies.size() > 0 && m_responseCookies[m_responseCookies.size() - 1] != L';')
  434. {
  435. m_responseCookies += L";";
  436. }
  437. }
  438. }
  439. delete[] szHeader;
  440. }
  441. }
  442. dwSize = 0;
  443. bResult = ::WinHttpQueryHeaders(hRequest,
  444. WINHTTP_QUERY_STATUS_CODE,
  445. WINHTTP_HEADER_NAME_BY_INDEX,
  446. NULL,
  447. &dwSize,
  448. WINHTTP_NO_HEADER_INDEX);
  449. if (bResult || (!bResult && (::GetLastError() == ERROR_INSUFFICIENT_BUFFER)))
  450. {
  451. wchar_t *szStatusCode = new wchar_t[dwSize];
  452. if (szStatusCode != NULL)
  453. {
  454. memset(szStatusCode, 0, dwSize* sizeof(wchar_t));
  455. if (::WinHttpQueryHeaders(hRequest,
  456. WINHTTP_QUERY_STATUS_CODE,
  457. WINHTTP_HEADER_NAME_BY_INDEX,
  458. szStatusCode,
  459. &dwSize,
  460. WINHTTP_NO_HEADER_INDEX))
  461. {
  462. m_statusCode = szStatusCode;
  463. }
  464. delete[] szStatusCode;
  465. }
  466. }
  467. unsigned int iMaxBufferSize = INT_BUFFERSIZE;
  468. unsigned int iCurrentBufferSize = 0;
  469. if (m_pResponse != NULL)
  470. {
  471. delete[] m_pResponse;
  472. m_pResponse = NULL;
  473. }
  474. m_pResponse = new BYTE[iMaxBufferSize];
  475. if (m_pResponse == NULL)
  476. {
  477. bRetVal = false;
  478. break;
  479. }
  480. memset(m_pResponse, 0, iMaxBufferSize);
  481. do
  482. {
  483. dwSize = 0;
  484. if (::WinHttpQueryDataAvailable(hRequest, &dwSize))
  485. {
  486. SetProgress(iCurrentBufferSize);
  487. BYTE *pResponse = new BYTE[dwSize + 1];
  488. if (pResponse != NULL)
  489. {
  490. memset(pResponse, 0, (dwSize + 1)*sizeof(BYTE));
  491. DWORD dwRead = 0;
  492. if (::WinHttpReadData(hRequest,
  493. pResponse,
  494. dwSize,
  495. &dwRead))
  496. {
  497. if (dwRead + iCurrentBufferSize > iMaxBufferSize)
  498. {
  499. BYTE *pOldBuffer = m_pResponse;
  500. m_pResponse = new BYTE[iMaxBufferSize * 2];
  501. if (m_pResponse == NULL)
  502. {
  503. m_pResponse = pOldBuffer;
  504. bRetVal = false;
  505. break;
  506. }
  507. iMaxBufferSize *= 2;
  508. memset(m_pResponse, 0, iMaxBufferSize);
  509. memcpy(m_pResponse, pOldBuffer, iCurrentBufferSize);
  510. delete[] pOldBuffer;
  511. }
  512. memcpy(m_pResponse + iCurrentBufferSize, pResponse, dwRead);
  513. iCurrentBufferSize += dwRead;
  514. }
  515. delete[] pResponse;
  516. }
  517. }
  518. else
  519. {
  520. m_dwLastError = ::GetLastError();
  521. }
  522. }
  523. while (dwSize > 0);
  524. SetProgress(iCurrentBufferSize);
  525. m_responseByteCountReceived = iCurrentBufferSize;
  526. UINT codePage = CP_ACP;
  527. DWORD dwFlag = MB_PRECOMPOSED;
  528. if (_wcsnicmp(m_responseCharset.c_str(), L"utf-8", 5) == 0)
  529. {
  530. codePage = CP_UTF8;
  531. dwFlag = 0;
  532. }
  533. int iLength = ::MultiByteToWideChar(codePage,
  534. dwFlag,
  535. (LPCSTR)m_pResponse,
  536. m_responseByteCountReceived + 1,
  537. NULL,
  538. 0);
  539. if (iLength <= 0)
  540. {
  541. // Use CP_ACP if UTF-8 fail
  542. codePage = CP_ACP;
  543. dwFlag = MB_PRECOMPOSED;
  544. iLength = ::MultiByteToWideChar(codePage,
  545. dwFlag,
  546. (LPCSTR)m_pResponse,
  547. m_responseByteCountReceived + 1,
  548. NULL,
  549. 0);
  550. }
  551. if (iLength > 0)
  552. {
  553. wchar_t *wideChar = new wchar_t[iLength];
  554. if (wideChar != NULL)
  555. {
  556. memset(wideChar, 0, iLength * sizeof(wchar_t));
  557. iLength = ::MultiByteToWideChar(codePage,
  558. dwFlag,
  559. (LPCSTR)m_pResponse,
  560. m_responseByteCountReceived + 1,
  561. wideChar,
  562. iLength);
  563. if (iLength > 0)
  564. {
  565. m_responseContent = wideChar;
  566. }
  567. delete[] wideChar;
  568. }
  569. }
  570. bGetReponseSucceed = true;
  571. // If the resposne html web page size is less than 200, retry.
  572. if (verb == L"GET" && !disableAutoRedirect)
  573. {
  574. wstring regExp = L"{<html>}";
  575. vector<wstring> result;
  576. if (ParseRegExp(regExp, false, 1, m_responseContent, result) && result.size() > 0)
  577. {
  578. regExp = L"{</html>}";
  579. if (!ParseRegExp(regExp, false, 1, m_responseContent, result) || result.size() <= 0)
  580. {
  581. m_dwLastError = ERROR_INVALID_DATA;
  582. bGetReponseSucceed = false;
  583. }
  584. }
  585. }
  586. }
  587. else
  588. {
  589. m_dwLastError = ::GetLastError();
  590. }
  591. }
  592. } // while
  593. if (!bGetReponseSucceed)
  594. {
  595. bRetVal = false;
  596. }
  597. ::WinHttpCloseHandle(hRequest);
  598. }
  599. ::WinHttpCloseHandle(hConnect);
  600. }
  601. }
  602. return bRetVal;
  603. }
  604. wstring WinHttpClient::GetResponseHeader(void)
  605. {
  606. return m_responseHeader;
  607. }
  608. wstring WinHttpClient::GetResponseContent(void)
  609. {
  610. return m_responseContent;
  611. }
  612. wstring WinHttpClient::GetResponseCharset(void)
  613. {
  614. return m_responseCharset;
  615. }
  616. wstring WinHttpClient::GetRequestHost(void)
  617. {
  618. return m_requestHost;
  619. }
  620. bool WinHttpClient::SaveResponseToFile(const wstring &filePath)
  621. {
  622. if (m_pResponse == NULL || m_responseByteCountReceived <= 0)
  623. {
  624. return false;
  625. }
  626. FILE *f = NULL;
  627. int iResult = _wfopen_s(&f, filePath.c_str(), L"wb");
  628. if (iResult == 0 && f != NULL)
  629. {
  630. fwrite(m_pResponse, m_responseByteCountReceived, 1, f);
  631. fclose(f);
  632. return true;
  633. }
  634. return false;
  635. }
  636. bool WinHttpClient::SetProgress(unsigned int byteCountReceived)
  637. {
  638. bool bReturn = false;
  639. if (m_pfProcessProc != NULL && m_responseByteCount > 0)
  640. {
  641. double dProgress = (double)byteCountReceived * 100 / m_responseByteCount;
  642. m_pfProcessProc(dProgress);
  643. bReturn = true;
  644. }
  645. return bReturn;
  646. }
  647. wstring WinHttpClient::GetResponseCookies(void)
  648. {
  649. return m_responseCookies;
  650. }
  651. bool WinHttpClient::SetAdditionalRequestCookies(const wstring &cookies)
  652. {
  653. m_additionalRequestCookies = cookies;
  654. return true;
  655. }
  656. bool WinHttpClient::SetAdditionalDataToSend(BYTE *data, unsigned int dataSize)
  657. {
  658. if (data == NULL || dataSize < 0)
  659. {
  660. return false;
  661. }
  662. if (m_pDataToSend != NULL)
  663. {
  664. delete[] m_pDataToSend;
  665. }
  666. m_pDataToSend = NULL;
  667. m_pDataToSend = new BYTE[dataSize];
  668. if (m_pDataToSend != NULL)
  669. {
  670. memcpy(m_pDataToSend, data, dataSize);
  671. m_dataToSendSize = dataSize;
  672. return true;
  673. }
  674. return false;
  675. }
  676. // Reset additional data fields
  677. bool WinHttpClient::ResetAdditionalDataToSend(void)
  678. {
  679. if (m_pDataToSend != NULL)
  680. {
  681. delete[] m_pDataToSend;
  682. }
  683. m_pDataToSend = NULL;
  684. m_dataToSendSize = 0;
  685. return true;
  686. }
  687. // Allow us to reset the url on subsequent requests
  688. bool WinHttpClient::UpdateUrl(const wstring &url)
  689. {
  690. m_requestURL = url;
  691. ResetAdditionalDataToSend();
  692. return true;
  693. }
  694. bool WinHttpClient::SetAdditionalRequestHeaders(const wstring &additionalRequestHeaders)
  695. {
  696. m_additionalRequestHeaders = additionalRequestHeaders;
  697. return true;
  698. }
  699. bool WinHttpClient::SetProxy(const wstring &proxy)
  700. {
  701. m_proxy = proxy;
  702. return true;
  703. }
  704. // If we don't require valid SSL Certs then accept any
  705. // certificate on an SSL connection
  706. bool WinHttpClient::SetRequireValidSslCertificates(bool require)
  707. {
  708. m_requireValidSsl = require;
  709. return true;
  710. }
  711. const BYTE *WinHttpClient::GetRawResponseContent(void)
  712. {
  713. return m_pResponse;
  714. }
  715. unsigned int WinHttpClient::GetRawResponseContentLength(void)
  716. {
  717. return m_responseByteCount;
  718. }
  719. unsigned int WinHttpClient::GetRawResponseReceivedContentLength(void)
  720. {
  721. return m_responseByteCountReceived;
  722. }
  723. DWORD WinHttpClient::GetLastError(void)
  724. {
  725. return m_dwLastError;
  726. }
  727. wstring WinHttpClient::GetResponseStatusCode(void)
  728. {
  729. return m_statusCode;
  730. }
  731. bool WinHttpClient::SetUserAgent(const wstring &userAgent)
  732. {
  733. m_userAgent = userAgent;
  734. return true;
  735. }
  736. bool WinHttpClient::SetForceCharset(const wstring &charset)
  737. {
  738. m_responseCharset = charset;
  739. return true;
  740. }
  741. bool WinHttpClient::SetProxyUsername(const wstring &username)
  742. {
  743. m_proxyUsername = username;
  744. return true;
  745. }
  746. bool WinHttpClient::SetProxyPassword(const std::wstring &password)
  747. {
  748. m_proxyPassword = password;
  749. return true;
  750. }
  751. wstring WinHttpClient::GetResponseLocation(void)
  752. {
  753. return m_location;
  754. }
  755. bool WinHttpClient::SetTimeouts(unsigned int resolveTimeout,
  756. unsigned int connectTimeout,
  757. unsigned int sendTimeout,
  758. unsigned int receiveTimeout)
  759. {
  760. m_resolveTimeout = resolveTimeout;
  761. m_connectTimeout = connectTimeout;
  762. m_sendTimeout = sendTimeout;
  763. m_receiveTimeout = receiveTimeout;
  764. return true;
  765. }
  766. #endif // WINHTTPCLIENT_H