工具项目

HttpServer.cpp 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. /*
  2. * Copyright: JessMA Open Source (ldcsaa@gmail.com)
  3. *
  4. * Author : Bruce Liang
  5. * Website : http://www.jessma.org
  6. * Project : https://github.com/ldcsaa
  7. * Blog : http://www.cnblogs.com/ldcsaa
  8. * Wiki : http://www.oschina.net/p/hp-socket
  9. * QQ Group : 75375912, 44636872
  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 "stdafx.h"
  24. #include "HttpServer.h"
  25. #ifdef _HTTP_SUPPORT
  26. template<class T, USHORT default_port> BOOL CHttpServerT<T, default_port>::Start(LPCTSTR lpszBindAddress, USHORT usPort)
  27. {
  28. BOOL isOK = __super::Start(lpszBindAddress, usPort);
  29. if(isOK) VERIFY(m_thCleaner.Start(this, &CHttpServerT::CleanerThreadProc));
  30. return isOK;
  31. }
  32. template<class T, USHORT default_port> BOOL CHttpServerT<T, default_port>::CheckParams()
  33. {
  34. if ((m_enLocalVersion != HV_1_1 && m_enLocalVersion != HV_1_0) ||
  35. (m_dwReleaseDelay < MIN_HTTP_RELEASE_DELAY || m_dwReleaseDelay > MAX_HTTP_RELEASE_DELAY))
  36. {
  37. SetLastError(SE_INVALID_PARAM, __FUNCTION__, ERROR_INVALID_PARAMETER);
  38. return FALSE;
  39. }
  40. return __super::CheckParams();
  41. }
  42. template<class T, USHORT default_port> void CHttpServerT<T, default_port>::PrepareStart()
  43. {
  44. __super::PrepareStart();
  45. m_objPool.SetHttpObjLockTime(GetFreeSocketObjLockTime());
  46. m_objPool.SetHttpObjPoolSize(GetFreeSocketObjPool());
  47. m_objPool.SetHttpObjPoolHold(GetFreeSocketObjHold());
  48. m_objPool.Prepare();
  49. }
  50. 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)
  51. {
  52. WSABUF szBuffer[2];
  53. CStringA strHeader;
  54. ::MakeStatusLine(m_enLocalVersion, usStatusCode, lpszDesc, strHeader);
  55. ::MakeHeaderLines(lpHeaders, iHeaderCount, nullptr, iLength, FALSE, IsKeepAlive(dwConnID), nullptr, 0, strHeader);
  56. ::MakeHttpPacket(strHeader, pData, iLength, szBuffer);
  57. return SendPackets(dwConnID, szBuffer, 2);
  58. }
  59. 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)
  60. {
  61. CAtlFile file;
  62. CAtlFileMapping<> fmap;
  63. HRESULT hr = ::ReadSmallFile(CA2T(lpszFileName), file, fmap);
  64. if(FAILED(hr))
  65. {
  66. ::SetLastError(HRESULT_CODE(hr));
  67. return FALSE;
  68. }
  69. return SendResponse(dwConnID, usStatusCode, lpszDesc, lpHeaders, iHeaderCount, (BYTE*)(char*)fmap, (int)fmap.GetMappingSize());
  70. }
  71. template<class T, USHORT default_port> BOOL CHttpServerT<T, default_port>::Release(CONNID dwConnID)
  72. {
  73. if(!HasStarted())
  74. return FALSE;
  75. THttpObj* pHttpObj = FindHttpObj(dwConnID);
  76. if(pHttpObj == nullptr || pHttpObj->HasReleased())
  77. return FALSE;
  78. pHttpObj->Release();
  79. m_lsDyingQueue.PushBack(TDyingConnection::Construct(dwConnID));
  80. return TRUE;
  81. }
  82. template<class T, USHORT default_port> BOOL CHttpServerT<T, default_port>::SendWSMessage(CONNID dwConnID, BOOL bFinal, BYTE iReserved, BYTE iOperationCode, const BYTE lpszMask[4], BYTE* pData, int iLength, ULONGLONG ullBodyLen)
  83. {
  84. WSABUF szBuffer[2];
  85. BYTE szHeader[HTTP_MAX_WS_HEADER_LEN];
  86. if(!::MakeWSPacket(bFinal, iReserved, iOperationCode, lpszMask, pData, iLength, ullBodyLen, szHeader, szBuffer))
  87. return FALSE;
  88. return SendPackets(dwConnID, szBuffer, 2);
  89. }
  90. template<class T, USHORT default_port> UINT CHttpServerT<T, default_port>::CleanerThreadProc(PVOID pv)
  91. {
  92. TRACE("---------------> Connection Cleaner Thread 0x%08X started <---------------\n", ::GetCurrentThreadId());
  93. DWORD dwRetValue = 0;
  94. DWORD dwInterval = max(MIN_HTTP_RELEASE_CHECK_INTERVAL, (m_dwReleaseDelay - MIN_HTTP_RELEASE_DELAY / 2));
  95. while(HasStarted())
  96. {
  97. dwRetValue = ::WaitForSingleObject(m_evCleaner, dwInterval);
  98. if(dwRetValue == WAIT_TIMEOUT)
  99. KillDyingConnection();
  100. else if(dwRetValue == WAIT_OBJECT_0)
  101. break;
  102. else
  103. ASSERT(FALSE);
  104. }
  105. ReleaseDyingConnection();
  106. TRACE("---------------> Connection Cleaner Thread 0x%08X stoped <---------------\n", ::GetCurrentThreadId());
  107. return 0;
  108. }
  109. template<class T, USHORT default_port> void CHttpServerT<T, default_port>::KillDyingConnection()
  110. {
  111. TDyingConnection* pDyingConn = nullptr;
  112. TDyingConnection* pFirstDyingConn = nullptr;
  113. DWORD now = ::TimeGetTime();
  114. while(m_lsDyingQueue.UnsafePeekFront(&pDyingConn))
  115. {
  116. if((int)(now - pDyingConn->killTime) < (int)m_dwReleaseDelay)
  117. break;
  118. BOOL bDisconnect = TRUE;
  119. BOOL bDestruct = TRUE;
  120. VERIFY(m_lsDyingQueue.UnsafePopFront(&pDyingConn));
  121. int iPending;
  122. if(!GetPendingDataLength(pDyingConn->connID, iPending))
  123. bDisconnect = FALSE;
  124. else if(iPending > 0)
  125. {
  126. bDisconnect = FALSE;
  127. bDestruct = FALSE;
  128. }
  129. if(bDisconnect)
  130. Disconnect(pDyingConn->connID, TRUE);
  131. if(bDestruct)
  132. {
  133. TDyingConnection::Destruct(pDyingConn);
  134. if(pFirstDyingConn == pDyingConn)
  135. pFirstDyingConn = nullptr;
  136. }
  137. else
  138. {
  139. m_lsDyingQueue.PushBack(pDyingConn);
  140. if(pFirstDyingConn == nullptr)
  141. pFirstDyingConn = pDyingConn;
  142. else if(pFirstDyingConn == pDyingConn)
  143. break;
  144. }
  145. }
  146. }
  147. template<class T, USHORT default_port> void CHttpServerT<T, default_port>::ReleaseDyingConnection()
  148. {
  149. TDyingConnection* pDyingConn = nullptr;
  150. while(m_lsDyingQueue.UnsafePopFront(&pDyingConn))
  151. TDyingConnection::Destruct(pDyingConn);
  152. VERIFY(m_lsDyingQueue.IsEmpty());
  153. }
  154. template<class T, USHORT default_port> EnHandleResult CHttpServerT<T, default_port>::DoFireAccept(TSocketObj* pSocketObj)
  155. {
  156. EnHandleResult result = __super::DoFireAccept(pSocketObj);
  157. if(result != HR_ERROR)
  158. {
  159. THttpObj* pHttpObj = m_objPool.PickFreeHttpObj(this, pSocketObj);
  160. VERIFY(SetConnectionReserved(pSocketObj, pHttpObj));
  161. }
  162. return result;
  163. }
  164. template<class T, USHORT default_port> EnHandleResult CHttpServerT<T, default_port>::DoFireHandShake(TSocketObj* pSocketObj)
  165. {
  166. EnHandleResult result = __super::DoFireHandShake(pSocketObj);
  167. if(result == HR_ERROR)
  168. {
  169. THttpObj* pHttpObj = FindHttpObj(pSocketObj);
  170. VERIFY(pHttpObj);
  171. m_objPool.PutFreeHttpObj(pHttpObj);
  172. SetConnectionReserved(pSocketObj, nullptr);
  173. }
  174. return result;
  175. }
  176. template<class T, USHORT default_port> EnHandleResult CHttpServerT<T, default_port>::DoFireReceive(TSocketObj* pSocketObj, const BYTE* pData, int iLength)
  177. {
  178. THttpObj* pHttpObj = FindHttpObj(pSocketObj);
  179. ASSERT(pHttpObj);
  180. if(pHttpObj->HasReleased())
  181. return HR_ERROR;
  182. return pHttpObj->Execute(pData, iLength);
  183. }
  184. template<class T, USHORT default_port> EnHandleResult CHttpServerT<T, default_port>::DoFireClose(TSocketObj* pSocketObj, EnSocketOperation enOperation, int iErrorCode)
  185. {
  186. EnHandleResult result = __super::DoFireClose(pSocketObj, enOperation, iErrorCode);
  187. THttpObj* pHttpObj = FindHttpObj(pSocketObj);
  188. if(pHttpObj != nullptr)
  189. m_objPool.PutFreeHttpObj(pHttpObj);
  190. return result;
  191. }
  192. template<class T, USHORT default_port> EnHandleResult CHttpServerT<T, default_port>::DoFireShutdown()
  193. {
  194. EnHandleResult result = __super::DoFireShutdown();
  195. m_objPool.Clear();
  196. WaitForCleanerThreadEnd();
  197. return result;
  198. }
  199. template<class T, USHORT default_port> void CHttpServerT<T, default_port>::WaitForCleanerThreadEnd()
  200. {
  201. if(m_thCleaner.IsRunning())
  202. {
  203. m_evCleaner.Set();
  204. VERIFY(m_thCleaner.Join(TRUE));
  205. m_evCleaner.Reset();
  206. }
  207. }
  208. template<class T, USHORT default_port> BOOL CHttpServerT<T, default_port>::IsUpgrade(CONNID dwConnID)
  209. {
  210. THttpObj* pHttpObj = FindHttpObj(dwConnID);
  211. if(pHttpObj == nullptr)
  212. return FALSE;
  213. return pHttpObj->IsUpgrade();
  214. }
  215. template<class T, USHORT default_port> BOOL CHttpServerT<T, default_port>::IsKeepAlive(CONNID dwConnID)
  216. {
  217. THttpObj* pHttpObj = FindHttpObj(dwConnID);
  218. if(pHttpObj == nullptr)
  219. return FALSE;
  220. return pHttpObj->IsKeepAlive();
  221. }
  222. template<class T, USHORT default_port> USHORT CHttpServerT<T, default_port>::GetVersion(CONNID dwConnID)
  223. {
  224. THttpObj* pHttpObj = FindHttpObj(dwConnID);
  225. if(pHttpObj == nullptr)
  226. return 0;
  227. return pHttpObj->GetVersion();
  228. }
  229. template<class T, USHORT default_port> LPCSTR CHttpServerT<T, default_port>::GetHost(CONNID dwConnID)
  230. {
  231. THttpObj* pHttpObj = FindHttpObj(dwConnID);
  232. if(pHttpObj == nullptr)
  233. return nullptr;
  234. return pHttpObj->GetHost();
  235. }
  236. template<class T, USHORT default_port> ULONGLONG CHttpServerT<T, default_port>::GetContentLength(CONNID dwConnID)
  237. {
  238. THttpObj* pHttpObj = FindHttpObj(dwConnID);
  239. if(pHttpObj == nullptr)
  240. return 0;
  241. return pHttpObj->GetContentLength();
  242. }
  243. template<class T, USHORT default_port> LPCSTR CHttpServerT<T, default_port>::GetContentType(CONNID dwConnID)
  244. {
  245. THttpObj* pHttpObj = FindHttpObj(dwConnID);
  246. if(pHttpObj == nullptr)
  247. return nullptr;
  248. return pHttpObj->GetContentType();
  249. }
  250. template<class T, USHORT default_port> LPCSTR CHttpServerT<T, default_port>::GetContentEncoding(CONNID dwConnID)
  251. {
  252. THttpObj* pHttpObj = FindHttpObj(dwConnID);
  253. if(pHttpObj == nullptr)
  254. return nullptr;
  255. return pHttpObj->GetContentEncoding();
  256. }
  257. template<class T, USHORT default_port> LPCSTR CHttpServerT<T, default_port>::GetTransferEncoding(CONNID dwConnID)
  258. {
  259. THttpObj* pHttpObj = FindHttpObj(dwConnID);
  260. if(pHttpObj == nullptr)
  261. return nullptr;
  262. return pHttpObj->GetTransferEncoding();
  263. }
  264. template<class T, USHORT default_port> EnHttpUpgradeType CHttpServerT<T, default_port>::GetUpgradeType(CONNID dwConnID)
  265. {
  266. THttpObj* pHttpObj = FindHttpObj(dwConnID);
  267. if(pHttpObj == nullptr)
  268. return HUT_NONE;
  269. return pHttpObj->GetUpgradeType();
  270. }
  271. template<class T, USHORT default_port> USHORT CHttpServerT<T, default_port>::GetParseErrorCode(CONNID dwConnID, LPCSTR* lpszErrorDesc)
  272. {
  273. THttpObj* pHttpObj = FindHttpObj(dwConnID);
  274. if(pHttpObj == nullptr)
  275. return 0;
  276. return pHttpObj->GetParseErrorCode(lpszErrorDesc);
  277. }
  278. template<class T, USHORT default_port> BOOL CHttpServerT<T, default_port>::GetHeader(CONNID dwConnID, LPCSTR lpszName, LPCSTR* lpszValue)
  279. {
  280. THttpObj* pHttpObj = FindHttpObj(dwConnID);
  281. if(pHttpObj == nullptr)
  282. return FALSE;
  283. return pHttpObj->GetHeader(lpszName, lpszValue);
  284. }
  285. template<class T, USHORT default_port> BOOL CHttpServerT<T, default_port>::GetHeaders(CONNID dwConnID, LPCSTR lpszName, LPCSTR lpszValue[], DWORD& dwCount)
  286. {
  287. THttpObj* pHttpObj = FindHttpObj(dwConnID);
  288. if(pHttpObj == nullptr)
  289. return FALSE;
  290. return pHttpObj->GetHeaders(lpszName, lpszValue, dwCount);
  291. }
  292. template<class T, USHORT default_port> BOOL CHttpServerT<T, default_port>::GetAllHeaders(CONNID dwConnID, THeader lpHeaders[], DWORD& dwCount)
  293. {
  294. THttpObj* pHttpObj = FindHttpObj(dwConnID);
  295. if(pHttpObj == nullptr)
  296. return FALSE;
  297. return pHttpObj->GetAllHeaders(lpHeaders, dwCount);
  298. }
  299. template<class T, USHORT default_port> BOOL CHttpServerT<T, default_port>::GetAllHeaderNames(CONNID dwConnID, LPCSTR lpszName[], DWORD& dwCount)
  300. {
  301. THttpObj* pHttpObj = FindHttpObj(dwConnID);
  302. if(pHttpObj == nullptr)
  303. return FALSE;
  304. return pHttpObj->GetAllHeaderNames(lpszName, dwCount);
  305. }
  306. template<class T, USHORT default_port> BOOL CHttpServerT<T, default_port>::GetCookie(CONNID dwConnID, LPCSTR lpszName, LPCSTR* lpszValue)
  307. {
  308. THttpObj* pHttpObj = FindHttpObj(dwConnID);
  309. if(pHttpObj == nullptr)
  310. return FALSE;
  311. return pHttpObj->GetCookie(lpszName, lpszValue);
  312. }
  313. template<class T, USHORT default_port> BOOL CHttpServerT<T, default_port>::GetAllCookies(CONNID dwConnID, TCookie lpCookies[], DWORD& dwCount)
  314. {
  315. THttpObj* pHttpObj = FindHttpObj(dwConnID);
  316. if(pHttpObj == nullptr)
  317. return FALSE;
  318. return pHttpObj->GetAllCookies(lpCookies, dwCount);
  319. }
  320. template<class T, USHORT default_port> USHORT CHttpServerT<T, default_port>::GetUrlFieldSet(CONNID dwConnID)
  321. {
  322. THttpObj* pHttpObj = FindHttpObj(dwConnID);
  323. if(pHttpObj == nullptr)
  324. return 0;
  325. return pHttpObj->GetUrlFieldSet();
  326. }
  327. template<class T, USHORT default_port> LPCSTR CHttpServerT<T, default_port>::GetUrlField(CONNID dwConnID, EnHttpUrlField enField)
  328. {
  329. THttpObj* pHttpObj = FindHttpObj(dwConnID);
  330. if(pHttpObj == nullptr)
  331. return nullptr;
  332. return pHttpObj->GetUrlField(enField);
  333. }
  334. template<class T, USHORT default_port> LPCSTR CHttpServerT<T, default_port>::GetMethod(CONNID dwConnID)
  335. {
  336. THttpObj* pHttpObj = FindHttpObj(dwConnID);
  337. if(pHttpObj == nullptr)
  338. return nullptr;
  339. return pHttpObj->GetMethod();
  340. }
  341. 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)
  342. {
  343. THttpObj* pHttpObj = FindHttpObj(dwConnID);
  344. if(pHttpObj == nullptr)
  345. return FALSE;
  346. return pHttpObj->GetWSMessageState(lpbFinal, lpiReserved, lpiOperationCode, lpszMask, lpullBodyLen, lpullBodyRemain);
  347. }
  348. template<class T, USHORT default_port> inline typename CHttpServerT<T, default_port>::THttpObj* CHttpServerT<T, default_port>::FindHttpObj(CONNID dwConnID)
  349. {
  350. THttpObj* pHttpObj = nullptr;
  351. GetConnectionReserved(dwConnID, (PVOID*)&pHttpObj);
  352. return pHttpObj;
  353. }
  354. template<class T, USHORT default_port> inline typename CHttpServerT<T, default_port>::THttpObj* CHttpServerT<T, default_port>::FindHttpObj(TSocketObj* pSocketObj)
  355. {
  356. THttpObj* pHttpObj = nullptr;
  357. GetConnectionReserved(pSocketObj, (PVOID*)&pHttpObj);
  358. return pHttpObj;
  359. }
  360. // ------------------------------------------------------------------------------------------------------------- //
  361. template class CHttpServerT<CTcpServer, HTTP_DEFAULT_PORT>;
  362. #ifdef _SSL_SUPPORT
  363. #include "SSLServer.h"
  364. template class CHttpServerT<CSSLServer, HTTPS_DEFAULT_PORT>;
  365. #endif
  366. #endif