HttpServer.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615
  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 "HttpServer.h"
  24. #ifdef _HTTP_SUPPORT
  25. template<class T, USHORT default_port> BOOL CHttpServerT<T, default_port>::Start(LPCTSTR lpszBindAddress, USHORT usPort)
  26. {
  27. BOOL isOK = __super::Start(lpszBindAddress, usPort);
  28. if(isOK) VERIFY(m_thCleaner.Start(this, &CHttpServerT::CleanerThreadProc));
  29. return isOK;
  30. }
  31. template<class T, USHORT default_port> BOOL CHttpServerT<T, default_port>::CheckParams()
  32. {
  33. if ((m_enLocalVersion != HV_1_1 && m_enLocalVersion != HV_1_0) ||
  34. (m_dwReleaseDelay < MIN_HTTP_RELEASE_DELAY || m_dwReleaseDelay > MAX_HTTP_RELEASE_DELAY))
  35. {
  36. SetLastError(SE_INVALID_PARAM, __FUNCTION__, ERROR_INVALID_PARAMETER);
  37. return FALSE;
  38. }
  39. return __super::CheckParams();
  40. }
  41. template<class T, USHORT default_port> void CHttpServerT<T, default_port>::PrepareStart()
  42. {
  43. __super::PrepareStart();
  44. m_objPool.SetHttpObjLockTime(GetFreeSocketObjLockTime());
  45. m_objPool.SetHttpObjPoolSize(GetFreeSocketObjPool());
  46. m_objPool.SetHttpObjPoolHold(GetFreeSocketObjHold());
  47. m_objPool.Prepare();
  48. }
  49. template<class T, USHORT default_port> BOOL CHttpServerT<T, default_port>::SendResponse(CONNID dwConnID, USHORT usStatusCode, LPCSTR lpszDesc, const THeader lpHeaders[], int iHeaderCount, const BYTE* pData, int iLength)
  50. {
  51. WSABUF szBuffer[2];
  52. CStringA strHeader;
  53. ::MakeStatusLine(m_enLocalVersion, usStatusCode, lpszDesc, strHeader);
  54. ::MakeHeaderLines(lpHeaders, iHeaderCount, nullptr, iLength, FALSE, IsKeepAlive(dwConnID), nullptr, 0, strHeader);
  55. ::MakeHttpPacket(strHeader, pData, iLength, szBuffer);
  56. return SendPackets(dwConnID, szBuffer, 2);
  57. }
  58. template<class T, USHORT default_port> BOOL CHttpServerT<T, default_port>::SendLocalFile(CONNID dwConnID, LPCSTR lpszFileName, USHORT usStatusCode, LPCSTR lpszDesc, const THeader lpHeaders[], int iHeaderCount)
  59. {
  60. CFile file;
  61. CFileMapping fmap;
  62. HRESULT hr = ::ReadSmallFile(CA2T(lpszFileName), file, fmap);
  63. if(FAILED(hr))
  64. {
  65. ::SetLastError(hr);
  66. return FALSE;
  67. }
  68. return SendResponse(dwConnID, usStatusCode, lpszDesc, lpHeaders, iHeaderCount, (BYTE*)fmap, (int)fmap.Size());
  69. }
  70. template<class T, USHORT default_port> BOOL CHttpServerT<T, default_port>::SendChunkData(CONNID dwConnID, const BYTE* pData, int iLength, LPCSTR lpszExtensions)
  71. {
  72. char szLen[12];
  73. WSABUF bufs[5];
  74. int iCount = MakeChunkPackage(pData, iLength, lpszExtensions, szLen, bufs);
  75. return SendPackets(dwConnID, bufs, iCount);
  76. }
  77. template<class T, USHORT default_port> BOOL CHttpServerT<T, default_port>::Release(CONNID dwConnID)
  78. {
  79. if(!HasStarted())
  80. return FALSE;
  81. THttpObj* pHttpObj = FindHttpObj(dwConnID);
  82. if(pHttpObj == nullptr || pHttpObj->HasReleased())
  83. return FALSE;
  84. pHttpObj->Release();
  85. m_lsDyingQueue.PushBack(TDyingConnection::Construct(dwConnID));
  86. return TRUE;
  87. }
  88. template<class T, USHORT default_port> BOOL CHttpServerT<T, default_port>::SendWSMessage(CONNID dwConnID, BOOL bFinal, BYTE iReserved, BYTE iOperationCode, const BYTE* pData, int iLength, ULONGLONG ullBodyLen)
  89. {
  90. WSABUF szBuffer[2];
  91. BYTE szHeader[HTTP_MAX_WS_HEADER_LEN];
  92. if(!::MakeWSPacket(bFinal, iReserved, iOperationCode, nullptr, (BYTE*)pData, iLength, ullBodyLen, szHeader, szBuffer))
  93. return FALSE;
  94. return SendPackets(dwConnID, szBuffer, 2);
  95. }
  96. template<class T, USHORT default_port> UINT CHttpServerT<T, default_port>::CleanerThreadProc(PVOID pv)
  97. {
  98. TRACE("---------------> Connection Cleaner Thread 0x%08X started <---------------", SELF_THREAD_ID);
  99. pollfd pfd = {m_evCleaner.GetFD(), POLLIN};
  100. DWORD dwInterval = MAX(MIN_HTTP_RELEASE_CHECK_INTERVAL, (m_dwReleaseDelay - MIN_HTTP_RELEASE_DELAY / 2));
  101. while(HasStarted())
  102. {
  103. int rs = (int)::PollForSingleObject(pfd, dwInterval);
  104. ASSERT(rs >= TIMEOUT);
  105. if(rs < TIMEOUT)
  106. ERROR_ABORT();
  107. if(rs == TIMEOUT)
  108. KillDyingConnection();
  109. else if(rs == 1)
  110. {
  111. m_evCleaner.Reset();
  112. goto END_DETECTOR;
  113. }
  114. else
  115. ASSERT(FALSE);
  116. }
  117. END_DETECTOR:
  118. ReleaseDyingConnection();
  119. VERIFY(!HasStarted());
  120. TRACE("---------------> Connection Cleaner Thread 0x%08X stoped <---------------", SELF_THREAD_ID);
  121. return 0;
  122. }
  123. template<class T, USHORT default_port> void CHttpServerT<T, default_port>::KillDyingConnection()
  124. {
  125. TDyingConnection* pDyingConn = nullptr;
  126. TDyingConnection* pFirstDyingConn = nullptr;
  127. DWORD now = ::TimeGetTime();
  128. while(m_lsDyingQueue.UnsafePeekFront(&pDyingConn))
  129. {
  130. if((int)(now - pDyingConn->killTime) < (int)m_dwReleaseDelay)
  131. break;
  132. BOOL bDisconnect = TRUE;
  133. BOOL bDestruct = TRUE;
  134. VERIFY(m_lsDyingQueue.UnsafePopFront(&pDyingConn));
  135. int iPending;
  136. if(!GetPendingDataLength(pDyingConn->connID, iPending))
  137. bDisconnect = FALSE;
  138. else if(iPending > 0)
  139. {
  140. bDisconnect = FALSE;
  141. bDestruct = FALSE;
  142. }
  143. if(bDisconnect)
  144. Disconnect(pDyingConn->connID, TRUE);
  145. if(bDestruct)
  146. {
  147. TDyingConnection::Destruct(pDyingConn);
  148. if(pFirstDyingConn == pDyingConn)
  149. pFirstDyingConn = nullptr;
  150. }
  151. else
  152. {
  153. m_lsDyingQueue.PushBack(pDyingConn);
  154. if(pFirstDyingConn == nullptr)
  155. pFirstDyingConn = pDyingConn;
  156. else if(pFirstDyingConn == pDyingConn)
  157. break;
  158. }
  159. }
  160. }
  161. template<class T, USHORT default_port> void CHttpServerT<T, default_port>::ReleaseDyingConnection()
  162. {
  163. TDyingConnection* pDyingConn = nullptr;
  164. while(m_lsDyingQueue.UnsafePopFront(&pDyingConn))
  165. TDyingConnection::Destruct(pDyingConn);
  166. VERIFY(m_lsDyingQueue.IsEmpty());
  167. }
  168. template<class T, USHORT default_port> EnHandleResult CHttpServerT<T, default_port>::FireAccept(TSocketObj* pSocketObj)
  169. {
  170. return m_bHttpAutoStart ? __super::FireAccept(pSocketObj) : __super::DoFireAccept(pSocketObj);
  171. }
  172. template<class T, USHORT default_port> EnHandleResult CHttpServerT<T, default_port>::DoFireAccept(TSocketObj* pSocketObj)
  173. {
  174. THttpObj* pHttpObj = DoStartHttp(pSocketObj);
  175. EnHandleResult result = __super::DoFireAccept(pSocketObj);
  176. if(result == HR_ERROR)
  177. {
  178. m_objPool.PutFreeHttpObj(pHttpObj);
  179. SetConnectionReserved(pSocketObj, nullptr);
  180. }
  181. return result;
  182. }
  183. template<class T, USHORT default_port> EnHandleResult CHttpServerT<T, default_port>::DoFireHandShake(TSocketObj* pSocketObj)
  184. {
  185. EnHandleResult result = __super::DoFireHandShake(pSocketObj);
  186. if(result == HR_ERROR)
  187. {
  188. THttpObj* pHttpObj = FindHttpObj(pSocketObj);
  189. if(pHttpObj != nullptr)
  190. {
  191. m_objPool.PutFreeHttpObj(pHttpObj);
  192. SetConnectionReserved(pSocketObj, nullptr);
  193. }
  194. }
  195. return result;
  196. }
  197. template<class T, USHORT default_port> EnHandleResult CHttpServerT<T, default_port>::DoFireReceive(TSocketObj* pSocketObj, const BYTE* pData, int iLength)
  198. {
  199. THttpObj* pHttpObj = FindHttpObj(pSocketObj);
  200. if(pHttpObj == nullptr)
  201. return DoFireSuperReceive(pSocketObj, pData, iLength);
  202. else
  203. {
  204. if(pHttpObj->HasReleased())
  205. return HR_ERROR;
  206. return pHttpObj->Execute(pData, iLength);
  207. }
  208. }
  209. template<class T, USHORT default_port> EnHandleResult CHttpServerT<T, default_port>::DoFireClose(TSocketObj* pSocketObj, EnSocketOperation enOperation, int iErrorCode)
  210. {
  211. EnHandleResult result = __super::DoFireClose(pSocketObj, enOperation, iErrorCode);
  212. THttpObj* pHttpObj = FindHttpObj(pSocketObj);
  213. if(pHttpObj != nullptr)
  214. {
  215. m_objPool.PutFreeHttpObj(pHttpObj);
  216. SetConnectionReserved(pSocketObj, nullptr);
  217. }
  218. return result;
  219. }
  220. template<class T, USHORT default_port> EnHandleResult CHttpServerT<T, default_port>::DoFireShutdown()
  221. {
  222. EnHandleResult result = __super::DoFireShutdown();
  223. m_objPool.Clear();
  224. WaitForCleanerThreadEnd();
  225. return result;
  226. }
  227. template<class T, USHORT default_port> void CHttpServerT<T, default_port>::ReleaseGCSocketObj(BOOL bForce)
  228. {
  229. __super::ReleaseGCSocketObj(bForce);
  230. #ifdef USE_EXTERNAL_GC
  231. m_objPool.ReleaseGCHttpObj(bForce);
  232. #endif
  233. }
  234. template<class T, USHORT default_port> void CHttpServerT<T, default_port>::WaitForCleanerThreadEnd()
  235. {
  236. if(m_thCleaner.IsRunning())
  237. {
  238. m_evCleaner.Set();
  239. m_thCleaner.Join();
  240. m_evCleaner.Reset();
  241. }
  242. }
  243. template<class T, USHORT default_port> BOOL CHttpServerT<T, default_port>::IsUpgrade(CONNID dwConnID)
  244. {
  245. THttpObj* pHttpObj = FindHttpObj(dwConnID);
  246. if(pHttpObj == nullptr)
  247. return FALSE;
  248. return pHttpObj->IsUpgrade();
  249. }
  250. template<class T, USHORT default_port> BOOL CHttpServerT<T, default_port>::IsKeepAlive(CONNID dwConnID)
  251. {
  252. THttpObj* pHttpObj = FindHttpObj(dwConnID);
  253. if(pHttpObj == nullptr)
  254. return FALSE;
  255. return pHttpObj->IsKeepAlive();
  256. }
  257. template<class T, USHORT default_port> USHORT CHttpServerT<T, default_port>::GetVersion(CONNID dwConnID)
  258. {
  259. THttpObj* pHttpObj = FindHttpObj(dwConnID);
  260. if(pHttpObj == nullptr)
  261. return 0;
  262. return pHttpObj->GetVersion();
  263. }
  264. template<class T, USHORT default_port> LPCSTR CHttpServerT<T, default_port>::GetHost(CONNID dwConnID)
  265. {
  266. THttpObj* pHttpObj = FindHttpObj(dwConnID);
  267. if(pHttpObj == nullptr)
  268. return nullptr;
  269. return pHttpObj->GetHost();
  270. }
  271. template<class T, USHORT default_port> ULONGLONG CHttpServerT<T, default_port>::GetContentLength(CONNID dwConnID)
  272. {
  273. THttpObj* pHttpObj = FindHttpObj(dwConnID);
  274. if(pHttpObj == nullptr)
  275. return 0;
  276. return pHttpObj->GetContentLength();
  277. }
  278. template<class T, USHORT default_port> LPCSTR CHttpServerT<T, default_port>::GetContentType(CONNID dwConnID)
  279. {
  280. THttpObj* pHttpObj = FindHttpObj(dwConnID);
  281. if(pHttpObj == nullptr)
  282. return nullptr;
  283. return pHttpObj->GetContentType();
  284. }
  285. template<class T, USHORT default_port> LPCSTR CHttpServerT<T, default_port>::GetContentEncoding(CONNID dwConnID)
  286. {
  287. THttpObj* pHttpObj = FindHttpObj(dwConnID);
  288. if(pHttpObj == nullptr)
  289. return nullptr;
  290. return pHttpObj->GetContentEncoding();
  291. }
  292. template<class T, USHORT default_port> LPCSTR CHttpServerT<T, default_port>::GetTransferEncoding(CONNID dwConnID)
  293. {
  294. THttpObj* pHttpObj = FindHttpObj(dwConnID);
  295. if(pHttpObj == nullptr)
  296. return nullptr;
  297. return pHttpObj->GetTransferEncoding();
  298. }
  299. template<class T, USHORT default_port> EnHttpUpgradeType CHttpServerT<T, default_port>::GetUpgradeType(CONNID dwConnID)
  300. {
  301. THttpObj* pHttpObj = FindHttpObj(dwConnID);
  302. if(pHttpObj == nullptr)
  303. return HUT_NONE;
  304. return pHttpObj->GetUpgradeType();
  305. }
  306. template<class T, USHORT default_port> USHORT CHttpServerT<T, default_port>::GetParseErrorCode(CONNID dwConnID, LPCSTR* lpszErrorDesc)
  307. {
  308. THttpObj* pHttpObj = FindHttpObj(dwConnID);
  309. if(pHttpObj == nullptr)
  310. return 0;
  311. return pHttpObj->GetParseErrorCode(lpszErrorDesc);
  312. }
  313. template<class T, USHORT default_port> BOOL CHttpServerT<T, default_port>::GetHeader(CONNID dwConnID, LPCSTR lpszName, LPCSTR* lpszValue)
  314. {
  315. THttpObj* pHttpObj = FindHttpObj(dwConnID);
  316. if(pHttpObj == nullptr)
  317. return FALSE;
  318. return pHttpObj->GetHeader(lpszName, lpszValue);
  319. }
  320. template<class T, USHORT default_port> BOOL CHttpServerT<T, default_port>::GetHeaders(CONNID dwConnID, LPCSTR lpszName, LPCSTR lpszValue[], DWORD& dwCount)
  321. {
  322. THttpObj* pHttpObj = FindHttpObj(dwConnID);
  323. if(pHttpObj == nullptr)
  324. return FALSE;
  325. return pHttpObj->GetHeaders(lpszName, lpszValue, dwCount);
  326. }
  327. template<class T, USHORT default_port> BOOL CHttpServerT<T, default_port>::GetAllHeaders(CONNID dwConnID, THeader lpHeaders[], DWORD& dwCount)
  328. {
  329. THttpObj* pHttpObj = FindHttpObj(dwConnID);
  330. if(pHttpObj == nullptr)
  331. return FALSE;
  332. return pHttpObj->GetAllHeaders(lpHeaders, dwCount);
  333. }
  334. template<class T, USHORT default_port> BOOL CHttpServerT<T, default_port>::GetAllHeaderNames(CONNID dwConnID, LPCSTR lpszName[], DWORD& dwCount)
  335. {
  336. THttpObj* pHttpObj = FindHttpObj(dwConnID);
  337. if(pHttpObj == nullptr)
  338. return FALSE;
  339. return pHttpObj->GetAllHeaderNames(lpszName, dwCount);
  340. }
  341. template<class T, USHORT default_port> BOOL CHttpServerT<T, default_port>::GetCookie(CONNID dwConnID, LPCSTR lpszName, LPCSTR* lpszValue)
  342. {
  343. THttpObj* pHttpObj = FindHttpObj(dwConnID);
  344. if(pHttpObj == nullptr)
  345. return FALSE;
  346. return pHttpObj->GetCookie(lpszName, lpszValue);
  347. }
  348. template<class T, USHORT default_port> BOOL CHttpServerT<T, default_port>::GetAllCookies(CONNID dwConnID, TCookie lpCookies[], DWORD& dwCount)
  349. {
  350. THttpObj* pHttpObj = FindHttpObj(dwConnID);
  351. if(pHttpObj == nullptr)
  352. return FALSE;
  353. return pHttpObj->GetAllCookies(lpCookies, dwCount);
  354. }
  355. template<class T, USHORT default_port> USHORT CHttpServerT<T, default_port>::GetUrlFieldSet(CONNID dwConnID)
  356. {
  357. THttpObj* pHttpObj = FindHttpObj(dwConnID);
  358. if(pHttpObj == nullptr)
  359. return 0;
  360. return pHttpObj->GetUrlFieldSet();
  361. }
  362. template<class T, USHORT default_port> LPCSTR CHttpServerT<T, default_port>::GetUrlField(CONNID dwConnID, EnHttpUrlField enField)
  363. {
  364. THttpObj* pHttpObj = FindHttpObj(dwConnID);
  365. if(pHttpObj == nullptr)
  366. return nullptr;
  367. return pHttpObj->GetUrlField(enField);
  368. }
  369. template<class T, USHORT default_port> LPCSTR CHttpServerT<T, default_port>::GetMethod(CONNID dwConnID)
  370. {
  371. THttpObj* pHttpObj = FindHttpObj(dwConnID);
  372. if(pHttpObj == nullptr)
  373. return nullptr;
  374. return pHttpObj->GetMethod();
  375. }
  376. template<class T, USHORT default_port> BOOL CHttpServerT<T, default_port>::GetWSMessageState(CONNID dwConnID, BOOL* lpbFinal, BYTE* lpiReserved, BYTE* lpiOperationCode, LPCBYTE* lpszMask, ULONGLONG* lpullBodyLen, ULONGLONG* lpullBodyRemain)
  377. {
  378. THttpObj* pHttpObj = FindHttpObj(dwConnID);
  379. if(pHttpObj == nullptr)
  380. return FALSE;
  381. return pHttpObj->GetWSMessageState(lpbFinal, lpiReserved, lpiOperationCode, lpszMask, lpullBodyLen, lpullBodyRemain);
  382. }
  383. template<class T, USHORT default_port> inline typename CHttpServerT<T, default_port>::THttpObj* CHttpServerT<T, default_port>::FindHttpObj(CONNID dwConnID)
  384. {
  385. THttpObj* pHttpObj = nullptr;
  386. GetConnectionReserved(dwConnID, (PVOID*)&pHttpObj);
  387. return pHttpObj;
  388. }
  389. template<class T, USHORT default_port> inline typename CHttpServerT<T, default_port>::THttpObj* CHttpServerT<T, default_port>::FindHttpObj(TSocketObj* pSocketObj)
  390. {
  391. THttpObj* pHttpObj = nullptr;
  392. GetConnectionReserved(pSocketObj, (PVOID*)&pHttpObj);
  393. return pHttpObj;
  394. }
  395. template<class T, USHORT default_port> BOOL CHttpServerT<T, default_port>::StartHttp(CONNID dwConnID)
  396. {
  397. if(IsHttpAutoStart())
  398. {
  399. ::SetLastError(ERROR_INVALID_OPERATION);
  400. return FALSE;
  401. }
  402. TSocketObj* pSocketObj = FindSocketObj(dwConnID);
  403. if(!TSocketObj::IsValid(pSocketObj))
  404. {
  405. ::SetLastError(ERROR_OBJECT_NOT_FOUND);
  406. return FALSE;
  407. }
  408. return StartHttp(pSocketObj);
  409. }
  410. template<class T, USHORT default_port> BOOL CHttpServerT<T, default_port>::StartHttp(TSocketObj* pSocketObj)
  411. {
  412. if(!pSocketObj->HasConnected())
  413. {
  414. ::SetLastError(ERROR_INVALID_STATE);
  415. return FALSE;
  416. }
  417. CReentrantCriSecLock locallock(pSocketObj->csSend);
  418. if(!TSocketObj::IsValid(pSocketObj))
  419. {
  420. ::SetLastError(ERROR_OBJECT_NOT_FOUND);
  421. return FALSE;
  422. }
  423. if(!pSocketObj->HasConnected())
  424. {
  425. ::SetLastError(ERROR_INVALID_STATE);
  426. return FALSE;
  427. }
  428. THttpObj* pHttpObj = FindHttpObj(pSocketObj);
  429. if(pHttpObj != nullptr)
  430. {
  431. ::SetLastError(ERROR_ALREADY_INITIALIZED);
  432. return FALSE;
  433. }
  434. DoStartHttp(pSocketObj);
  435. if(!IsSecure())
  436. FireHandShake(pSocketObj);
  437. else
  438. {
  439. #ifdef _SSL_SUPPORT
  440. if(IsSSLAutoHandShake())
  441. StartSSLHandShake(pSocketObj);
  442. #endif
  443. }
  444. return TRUE;
  445. }
  446. template<class T, USHORT default_port> typename CHttpServerT<T, default_port>::THttpObj* CHttpServerT<T, default_port>::DoStartHttp(TSocketObj* pSocketObj)
  447. {
  448. THttpObj* pHttpObj = m_objPool.PickFreeHttpObj(this, pSocketObj);
  449. VERIFY(SetConnectionReserved(pSocketObj, pHttpObj));
  450. return pHttpObj;
  451. }
  452. // ------------------------------------------------------------------------------------------------------------- //
  453. template class CHttpServerT<CTcpServer, HTTP_DEFAULT_PORT>;
  454. #ifdef _SSL_SUPPORT
  455. #include "SSLServer.h"
  456. template class CHttpServerT<CSSLServer, HTTPS_DEFAULT_PORT>;
  457. #endif
  458. #endif