HttpClient.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598
  1. /*
  2. * Copyright: JessMA Open Source (ldcsaa@gmail.com)
  3. *
  4. * Author : Bruce Liang
  5. * Website : https://github.com/ldcsaa
  6. * Project : https://github.com/ldcsaa/HP-Socket
  7. * Blog : http://www.cnblogs.com/ldcsaa
  8. * Wiki : http://www.oschina.net/p/hp-socket
  9. * QQ Group : 44636872, 75375912
  10. *
  11. * Licensed under the Apache License, Version 2.0 (the "License");
  12. * you may not use this file except in compliance with the License.
  13. * You may obtain a copy of the License at
  14. *
  15. * http://www.apache.org/licenses/LICENSE-2.0
  16. *
  17. * Unless required by applicable law or agreed to in writing, software
  18. * distributed under the License is distributed on an "AS IS" BASIS,
  19. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  20. * See the License for the specific language governing permissions and
  21. * limitations under the License.
  22. */
  23. #include "HttpClient.h"
  24. #ifdef _HTTP_SUPPORT
  25. template<class R, class T, USHORT default_port> BOOL CHttpClientT<R, T, default_port>::CheckParams()
  26. {
  27. if(m_enLocalVersion != HV_1_1 && m_enLocalVersion != HV_1_0)
  28. {
  29. SetLastError(SE_INVALID_PARAM, __FUNCTION__, ERROR_INVALID_PARAMETER);
  30. return FALSE;
  31. }
  32. return __super::CheckParams();
  33. }
  34. template<class R, class T, USHORT default_port> BOOL CHttpClientT<R, T, default_port>::SendRequest(LPCSTR lpszMethod, LPCSTR lpszPath, const THeader lpHeaders[], int iHeaderCount, const BYTE* pBody, int iLength)
  35. {
  36. USES_CONVERSION;
  37. WSABUF szBuffer[2];
  38. CStringA strHeader;
  39. LPCSTR lpszHost = nullptr;
  40. USHORT usPort = 0;
  41. BOOL bConnect = (stricmp(lpszMethod, HTTP_METHOD_CONNECT) == 0);
  42. if(!bConnect)
  43. {
  44. GetRemoteHost(&lpszHost, &usPort);
  45. if(usPort == default_port) usPort = 0;
  46. }
  47. CStringA strPath;
  48. ::AdjustRequestPath(bConnect, lpszPath, strPath);
  49. m_objHttp.SetRequestPath(lpszMethod, strPath);
  50. m_objHttp.ReloadCookies();
  51. ::MakeRequestLine(lpszMethod, strPath, m_enLocalVersion, strHeader);
  52. ::MakeHeaderLines(lpHeaders, iHeaderCount, &m_objHttp.GetCookieMap(), iLength, TRUE, -1, lpszHost, usPort, strHeader);
  53. ::MakeHttpPacket(strHeader, pBody, iLength, szBuffer);
  54. return SendPackets(szBuffer, 2);
  55. }
  56. template<class R, class T, USHORT default_port> BOOL CHttpClientT<R, T, default_port>::SendLocalFile(LPCSTR lpszFileName, LPCSTR lpszMethod, LPCSTR lpszPath, const THeader lpHeaders[], int iHeaderCount)
  57. {
  58. CFile file;
  59. CFileMapping fmap;
  60. HRESULT hr = ::ReadSmallFile(CA2T(lpszFileName), file, fmap);
  61. if(FAILED(hr))
  62. {
  63. ::SetLastError(hr);
  64. return FALSE;
  65. }
  66. return SendRequest(lpszMethod, lpszPath, lpHeaders, iHeaderCount, (BYTE*)fmap, (int)fmap.Size());
  67. }
  68. template<class R, class T, USHORT default_port> BOOL CHttpClientT<R, T, default_port>::SendChunkData(const BYTE* pData, int iLength, LPCSTR lpszExtensions)
  69. {
  70. char szLen[12];
  71. WSABUF bufs[5];
  72. int iCount = MakeChunkPackage(pData, iLength, lpszExtensions, szLen, bufs);
  73. return SendPackets(bufs, iCount);
  74. }
  75. template<class R, class T, USHORT default_port> BOOL CHttpClientT<R, T, default_port>::SendWSMessage(BOOL bFinal, BYTE iReserved, BYTE iOperationCode, const BYTE lpszMask[4], const BYTE* pData, int iLength, ULONGLONG ullBodyLen)
  76. {
  77. ASSERT(lpszMask);
  78. WSABUF szBuffer[2];
  79. BYTE szHeader[HTTP_MAX_WS_HEADER_LEN];
  80. unique_ptr<BYTE[]> szData = make_unique<BYTE[]>(iLength);
  81. memcpy(szData.get(), pData, iLength);
  82. if(!::MakeWSPacket(bFinal, iReserved, iOperationCode, lpszMask, szData.get(), iLength, ullBodyLen, szHeader, szBuffer))
  83. return FALSE;
  84. return SendPackets(szBuffer, 2);
  85. }
  86. template<class R, class T, USHORT default_port> BOOL CHttpClientT<R, T, default_port>::StartHttp()
  87. {
  88. if(IsHttpAutoStart())
  89. {
  90. ::SetLastError(ERROR_INVALID_OPERATION);
  91. return FALSE;
  92. }
  93. if(!IsConnected())
  94. {
  95. ::SetLastError(ERROR_INVALID_STATE);
  96. return FALSE;
  97. }
  98. CReentrantCriSecLock locallock(m_csHttp);
  99. if(!IsConnected())
  100. {
  101. ::SetLastError(ERROR_INVALID_STATE);
  102. return FALSE;
  103. }
  104. if(m_objHttp.IsValid())
  105. {
  106. ::SetLastError(ERROR_ALREADY_INITIALIZED);
  107. return FALSE;
  108. }
  109. DoStartHttp();
  110. if(!IsSecure())
  111. FireHandShake();
  112. else
  113. {
  114. #ifdef _SSL_SUPPORT
  115. if(IsSSLAutoHandShake())
  116. StartSSLHandShakeNoCheck();
  117. #endif
  118. }
  119. return TRUE;
  120. }
  121. // ------------------------------------------------------------------------------------------------------------- //
  122. template<class T, USHORT default_port> BOOL CHttpSyncClientT<T, default_port>::Start(LPCTSTR lpszRemoteAddress, USHORT usPort, BOOL bAsyncConnect, LPCTSTR lpszBindAddress, USHORT usLocalPort)
  123. {
  124. CleanupRequestResult();
  125. if(!__super::Start(lpszRemoteAddress, usPort, TRUE, lpszBindAddress, usLocalPort))
  126. return FALSE;
  127. BOOL isOK = WaitForEvent(m_dwConnectTimeout);
  128. if(!isOK || m_enProgress != HSRP_DONE)
  129. {
  130. int ec = m_enProgress == HSRP_WAITING ? ERROR_TIMEDOUT : ERROR_CONNREFUSED;
  131. if(!isOK) Stop();
  132. SetLastError(SE_CONNECT_SERVER, __FUNCTION__, ec);
  133. return FALSE;
  134. }
  135. return TRUE;
  136. }
  137. template<class T, USHORT default_port> BOOL CHttpSyncClientT<T, default_port>::SendRequest(LPCSTR lpszMethod, LPCSTR lpszPath, const THeader lpHeaders[], int iHeaderCount, const BYTE* pBody, int iLength)
  138. {
  139. CleanupRequestResult();
  140. if(!__super::SendRequest(lpszMethod, lpszPath, lpHeaders, iHeaderCount, pBody, iLength))
  141. return FALSE;
  142. BOOL isOK = WaitForEvent(m_dwRequestTimeout);
  143. if(!isOK || m_enProgress != HSRP_DONE)
  144. {
  145. int ec = m_enProgress == HSRP_WAITING ? ERROR_TIMEDOUT :
  146. (m_enProgress == HSRP_CLOSE ? ERROR_CONNABORTED : ERROR_INVALID_DATA);
  147. if(!isOK) Stop();
  148. SetLastError(SE_DATA_SEND, __FUNCTION__, ec);
  149. return FALSE;
  150. }
  151. return TRUE;
  152. }
  153. template<class T, USHORT default_port> BOOL CHttpSyncClientT<T, default_port>::SendWSMessage(BOOL bFinal, BYTE iReserved, BYTE iOperationCode, const BYTE lpszMask[4], const BYTE* pData, int iLength, ULONGLONG ullBodyLen)
  154. {
  155. CleanupRequestResult();
  156. if(!__super::SendWSMessage(bFinal, iReserved, iOperationCode, lpszMask, pData, iLength, ullBodyLen))
  157. return FALSE;
  158. BOOL isOK = WaitForEvent(m_dwRequestTimeout);
  159. if(!isOK || m_enProgress != HSRP_DONE)
  160. {
  161. int ec = m_enProgress == HSRP_WAITING ? ERROR_TIMEDOUT :
  162. (m_enProgress == HSRP_CLOSE ? ERROR_CONNABORTED : ERROR_INVALID_DATA);
  163. if(!isOK) Stop();
  164. SetLastError(SE_DATA_SEND, __FUNCTION__, ec);
  165. return FALSE;
  166. }
  167. return TRUE;
  168. }
  169. template<class T, USHORT default_port> BOOL CHttpSyncClientT<T, default_port>::OpenUrl(LPCSTR lpszMethod, LPCSTR lpszUrl, const THeader lpHeaders[], int iHeaderCount, const BYTE* pBody, int iLength, BOOL bForceReconnect)
  170. {
  171. BOOL bHttps;
  172. USHORT usPort;
  173. CStringA strHost;
  174. CStringA strPath;
  175. if(!IsHttpAutoStart())
  176. {
  177. SetLastError(SE_INVALID_PARAM, __FUNCTION__, ERROR_NOT_SUPPORTED);
  178. return FALSE;
  179. }
  180. if(!::ParseUrl(lpszUrl, bHttps, strHost, usPort, strPath))
  181. {
  182. SetLastError(SE_CONNECT_SERVER, __FUNCTION__, ERROR_ADDRNOTAVAIL);
  183. return FALSE;
  184. }
  185. if((bHttps && default_port == HTTP_DEFAULT_PORT) || (!bHttps && default_port == HTTPS_DEFAULT_PORT))
  186. {
  187. SetLastError(SE_CONNECT_SERVER, __FUNCTION__, ERROR_PROTO);
  188. return FALSE;
  189. }
  190. if(HasStarted())
  191. {
  192. BOOL bNeedStop = bForceReconnect;
  193. if(!bNeedStop)
  194. {
  195. LPCSTR lpszHost = nullptr;
  196. USHORT usPort2 = 0;
  197. GetRemoteHost(&lpszHost, &usPort2);
  198. if(usPort != usPort2)
  199. bNeedStop = TRUE;
  200. else
  201. {
  202. HP_SCOPE_HOST host(CA2T((LPCSTR)strHost));
  203. if(lstricmp(host.name, CA2T(lpszHost)) != 0)
  204. bNeedStop = TRUE;
  205. }
  206. }
  207. if(bNeedStop) Stop();
  208. }
  209. EnServiceState state = GetState();
  210. if(state != SS_STARTED)
  211. {
  212. if(state == SS_STARTING)
  213. {
  214. do
  215. {
  216. ::WaitFor(10);
  217. state = GetState();
  218. } while(state != SS_STARTED && state != SS_STOPPED);
  219. }
  220. else
  221. {
  222. while(state != SS_STOPPED)
  223. {
  224. ::WaitFor(10);
  225. state = GetState();
  226. }
  227. Start(CA2T(strHost), usPort, FALSE, nullptr);
  228. state = GetState();
  229. }
  230. if(state == SS_STOPPED)
  231. return FALSE;
  232. }
  233. if(iLength < 0 && !::IsStrEmptyA((LPCSTR)pBody))
  234. return SendLocalFile((LPCSTR)pBody, lpszMethod, strPath, lpHeaders, iHeaderCount);
  235. return SendRequest(lpszMethod, strPath, lpHeaders, iHeaderCount, pBody, iLength);
  236. }
  237. template<class T, USHORT default_port> BOOL CHttpSyncClientT<T, default_port>::CleanupRequestResult()
  238. {
  239. m_pHttpObj = &m_objHttp;
  240. m_enProgress = HSRP_WAITING;
  241. m_szBuffer.Free();
  242. m_objHttp2.Reset();
  243. m_evWait.Reset();
  244. return TRUE;
  245. }
  246. template<class T, USHORT default_port> void CHttpSyncClientT<T, default_port>::SetRequestEvent(EnHttpSyncRequestProgress enProgress, BOOL bCopyHttpObj)
  247. {
  248. if(m_enProgress != HSRP_WAITING)
  249. return;
  250. m_enProgress = enProgress;
  251. if(bCopyHttpObj)
  252. {
  253. m_objHttp2.CopyData(m_objHttp);
  254. m_objHttp2.CopyWSContext(m_objHttp);
  255. m_pHttpObj = &m_objHttp2;
  256. }
  257. m_evWait.Set();
  258. }
  259. template<class T, USHORT default_port> BOOL CHttpSyncClientT<T, default_port>::WaitForEvent(DWORD dwWait)
  260. {
  261. LONG lTimeout = INFINITE;
  262. if(dwWait != 0)
  263. lTimeout = (LONG)dwWait;
  264. return (m_evWait.Wait(lTimeout) > TIMEOUT);
  265. }
  266. template<class T, USHORT default_port> BOOL CHttpSyncClientT<T, default_port>::GetResponseBody(LPCBYTE* lpszBody, int* iLength)
  267. {
  268. ASSERT(lpszBody && iLength);
  269. *lpszBody = m_szBuffer.Ptr();
  270. *iLength = (int)m_szBuffer.Size();
  271. return TRUE;
  272. }
  273. template<class T, USHORT default_port> EnHandleResult CHttpSyncClientT<T, default_port>::OnHandShake(ITcpClient* pSender, CONNID dwConnID)
  274. {
  275. EnHandleResult rs = HR_OK;
  276. if(m_pListener2 != nullptr)
  277. rs = m_pListener2->OnHandShake(pSender, dwConnID);
  278. if(rs != HR_ERROR)
  279. SetRequestEvent(HSRP_DONE, FALSE);
  280. return rs;
  281. }
  282. template<class T, USHORT default_port> EnHandleResult CHttpSyncClientT<T, default_port>::OnClose(ITcpClient* pSender, CONNID dwConnID, EnSocketOperation enOperation, int iErrorCode)
  283. {
  284. EnHandleResult rs = HR_OK;
  285. if(m_pListener2 != nullptr)
  286. rs = m_pListener2->OnClose(pSender, dwConnID, enOperation, iErrorCode);
  287. SetRequestEvent(HSRP_CLOSE);
  288. return rs;
  289. }
  290. template<class T, USHORT default_port> EnHttpParseResult CHttpSyncClientT<T, default_port>::OnBody(IHttpClient* pSender, CONNID dwConnID, const BYTE* pData, int iLength)
  291. {
  292. EnHttpParseResult rs = HPR_OK;
  293. if(m_pListener2 != nullptr)
  294. rs = m_pListener2->OnBody(pSender, dwConnID, pData, iLength);
  295. if(rs != HPR_ERROR)
  296. m_szBuffer.Cat(pData, iLength);
  297. return rs;
  298. }
  299. template<class T, USHORT default_port> EnHttpParseResult CHttpSyncClientT<T, default_port>::OnMessageComplete(IHttpClient* pSender, CONNID dwConnID)
  300. {
  301. EnHttpParseResult rs = HPR_OK;
  302. if(m_pListener2 != nullptr)
  303. rs = m_pListener2->OnMessageComplete(pSender, dwConnID);
  304. if(rs != HPR_ERROR)
  305. {
  306. if(GetUpgradeType() == HUT_NONE)
  307. SetRequestEvent(HSRP_DONE);
  308. }
  309. return rs;
  310. }
  311. template<class T, USHORT default_port> EnHttpParseResult CHttpSyncClientT<T, default_port>::OnUpgrade(IHttpClient* pSender, CONNID dwConnID, EnHttpUpgradeType enUpgradeType)
  312. {
  313. EnHttpParseResult rs = HPR_OK;
  314. if(m_pListener2 != nullptr)
  315. rs = m_pListener2->OnUpgrade(pSender, dwConnID, enUpgradeType);
  316. if(rs != HPR_ERROR)
  317. {
  318. if(enUpgradeType == HUT_WEB_SOCKET)
  319. {
  320. SetRequestEvent(HSRP_DONE);
  321. rs = HPR_OK;
  322. }
  323. else
  324. {
  325. SetRequestEvent(HSRP_ERROR);
  326. rs = HPR_ERROR;
  327. }
  328. }
  329. return rs;
  330. }
  331. template<class T, USHORT default_port> EnHttpParseResult CHttpSyncClientT<T, default_port>::OnParseError(IHttpClient* pSender, CONNID dwConnID, int iErrorCode, LPCSTR lpszErrorDesc)
  332. {
  333. EnHttpParseResult rs = HPR_OK;
  334. if(m_pListener2 != nullptr)
  335. rs = m_pListener2->OnParseError(pSender, dwConnID, iErrorCode, lpszErrorDesc);
  336. SetRequestEvent(HSRP_ERROR);
  337. return rs;
  338. }
  339. template<class T, USHORT default_port> EnHandleResult CHttpSyncClientT<T, default_port>::OnWSMessageBody(IHttpClient* pSender, CONNID dwConnID, const BYTE* pData, int iLength)
  340. {
  341. EnHandleResult rs = HR_OK;
  342. if(m_pListener2 != nullptr)
  343. rs = m_pListener2->OnWSMessageBody(pSender, dwConnID, pData, iLength);
  344. if(rs != HR_ERROR)
  345. m_szBuffer.Cat(pData, iLength);
  346. return rs;
  347. }
  348. template<class T, USHORT default_port> EnHandleResult CHttpSyncClientT<T, default_port>::OnWSMessageComplete(IHttpClient* pSender, CONNID dwConnID)
  349. {
  350. EnHandleResult rs = HR_OK;
  351. if(m_pListener2 != nullptr)
  352. rs = m_pListener2->OnWSMessageComplete(pSender, dwConnID);
  353. if(rs != HR_ERROR)
  354. SetRequestEvent(HSRP_DONE);
  355. return rs;
  356. }
  357. template<class T, USHORT default_port> EnHandleResult CHttpSyncClientT<T, default_port>::OnPrepareConnect(ITcpClient* pSender, CONNID dwConnID, SOCKET socket)
  358. {
  359. EnHandleResult rs = HR_OK;
  360. if(m_pListener2 != nullptr)
  361. return m_pListener2->OnPrepareConnect(pSender, dwConnID, socket);
  362. return rs;
  363. }
  364. template<class T, USHORT default_port> EnHandleResult CHttpSyncClientT<T, default_port>::OnConnect(ITcpClient* pSender, CONNID dwConnID)
  365. {
  366. EnHandleResult rs = HR_OK;
  367. if(m_pListener2 != nullptr)
  368. return m_pListener2->OnConnect(pSender, dwConnID);
  369. return rs;
  370. }
  371. template<class T, USHORT default_port> EnHandleResult CHttpSyncClientT<T, default_port>::OnSend(ITcpClient* pSender, CONNID dwConnID, const BYTE* pData, int iLength)
  372. {
  373. EnHandleResult rs = HR_OK;
  374. if(m_pListener2 != nullptr)
  375. return m_pListener2->OnSend(pSender, dwConnID, pData, iLength);
  376. return rs;
  377. }
  378. template<class T, USHORT default_port> EnHandleResult CHttpSyncClientT<T, default_port>::OnReceive(ITcpClient* pSender, CONNID dwConnID, const BYTE* pData, int iLength)
  379. {
  380. EnHandleResult rs = HR_OK;
  381. if(m_pListener2 != nullptr)
  382. return m_pListener2->OnReceive(pSender, dwConnID, pData, iLength);
  383. return rs;
  384. }
  385. template<class T, USHORT default_port> EnHttpParseResult CHttpSyncClientT<T, default_port>::OnMessageBegin(IHttpClient* pSender, CONNID dwConnID)
  386. {
  387. EnHttpParseResult rs = HPR_OK;
  388. if(m_pListener2 != nullptr)
  389. rs = m_pListener2->OnMessageBegin(pSender, dwConnID);
  390. return rs;
  391. }
  392. template<class T, USHORT default_port> EnHttpParseResult CHttpSyncClientT<T, default_port>::OnStatusLine(IHttpClient* pSender, CONNID dwConnID, USHORT usStatusCode, LPCSTR lpszDesc)
  393. {
  394. EnHttpParseResult rs = HPR_OK;
  395. if(m_pListener2 != nullptr)
  396. rs = m_pListener2->OnStatusLine(pSender, dwConnID, usStatusCode, lpszDesc);
  397. return rs;
  398. }
  399. template<class T, USHORT default_port> EnHttpParseResult CHttpSyncClientT<T, default_port>::OnHeader(IHttpClient* pSender, CONNID dwConnID, LPCSTR lpszName, LPCSTR lpszValue)
  400. {
  401. EnHttpParseResult rs = HPR_OK;
  402. if(m_pListener2 != nullptr)
  403. rs = m_pListener2->OnHeader(pSender, dwConnID, lpszName, lpszValue);
  404. return rs;
  405. }
  406. template<class T, USHORT default_port> EnHttpParseResult CHttpSyncClientT<T, default_port>::OnHeadersComplete(IHttpClient* pSender, CONNID dwConnID)
  407. {
  408. EnHttpParseResult rs = HPR_OK;
  409. if(m_pListener2 != nullptr)
  410. rs = m_pListener2->OnHeadersComplete(pSender, dwConnID);
  411. return rs;
  412. }
  413. template<class T, USHORT default_port> EnHttpParseResult CHttpSyncClientT<T, default_port>::OnChunkHeader(IHttpClient* pSender, CONNID dwConnID, int iLength)
  414. {
  415. EnHttpParseResult rs = HPR_OK;
  416. if(m_pListener2 != nullptr)
  417. rs = m_pListener2->OnChunkHeader(pSender, dwConnID, iLength);
  418. return rs;
  419. }
  420. template<class T, USHORT default_port> EnHttpParseResult CHttpSyncClientT<T, default_port>::OnChunkComplete(IHttpClient* pSender, CONNID dwConnID)
  421. {
  422. EnHttpParseResult rs = HPR_OK;
  423. if(m_pListener2 != nullptr)
  424. rs = m_pListener2->OnChunkComplete(pSender, dwConnID);
  425. return rs;
  426. }
  427. template<class T, USHORT default_port> EnHandleResult CHttpSyncClientT<T, default_port>::OnWSMessageHeader(IHttpClient* pSender, CONNID dwConnID, BOOL bFinal, BYTE iReserved, BYTE iOperationCode, const BYTE lpszMask[4], ULONGLONG ullBodyLen)
  428. {
  429. EnHandleResult rs = HR_OK;
  430. if(m_pListener2 != nullptr)
  431. rs = m_pListener2->OnWSMessageHeader(pSender, dwConnID, bFinal, iReserved, iOperationCode, lpszMask, ullBodyLen);
  432. return rs;
  433. }
  434. // ------------------------------------------------------------------------------------------------------------- //
  435. template class CHttpClientT<IHttpRequester, CTcpClient, HTTP_DEFAULT_PORT>;
  436. template class CHttpSyncClientT<CTcpClient, HTTP_DEFAULT_PORT>;
  437. #ifdef _SSL_SUPPORT
  438. #include "SSLClient.h"
  439. template class CHttpClientT<IHttpRequester, CSSLClient, HTTPS_DEFAULT_PORT>;
  440. template class CHttpSyncClientT<CSSLClient, HTTPS_DEFAULT_PORT>;
  441. #endif
  442. #endif