开源的socket服务端客户端,支持C# C++

HttpHelper.h 30KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272
  1. /*
  2. * Copyright: JessMA Open Source (ldcsaa@gmail.com)
  3. *
  4. * Version : 4.1.3
  5. * Author : Bruce Liang
  6. * Website : http://www.jessma.org
  7. * Project : https://github.com/ldcsaa
  8. * Blog : http://www.cnblogs.com/ldcsaa
  9. * Wiki : http://www.oschina.net/p/hp-socket
  10. * QQ Group : 75375912
  11. *
  12. * Licensed under the Apache License, Version 2.0 (the "License");
  13. * you may not use this file except in compliance with the License.
  14. * You may obtain a copy of the License at
  15. *
  16. * http://www.apache.org/licenses/LICENSE-2.0
  17. *
  18. * Unless required by applicable law or agreed to in writing, software
  19. * distributed under the License is distributed on an "AS IS" BASIS,
  20. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  21. * See the License for the specific language governing permissions and
  22. * limitations under the License.
  23. */
  24. #pragma once
  25. #include "SocketHelper.h"
  26. #include "../../Common/Src/http/http_parser.h"
  27. #include "../../Common/Src/zlib/zutil.h"
  28. /************************************************************************
  29. 名称:HTTP 全局常量
  30. 描述:声明 HTTP 组件的公共全局常量
  31. ************************************************************************/
  32. #define HTTP_DEFAULT_PORT 80
  33. #define HTTPS_DEFAULT_PORT 443
  34. #define HTTP_SCHEMA "http://"
  35. #define HTTPS_SCHEMA "https://"
  36. #define HTTP_CRLF "\r\n"
  37. #define HTTP_NV_SEPARATOR_CHAR '='
  38. #define HTTP_PORT_SEPARATOR_CHAR ':'
  39. #define HTTP_PATH_SEPARATOR_CHAR '/'
  40. #define HTTP_PATH_SEPARATOR "/"
  41. #define HTTP_HEADER_SEPARATOR ": "
  42. #define HTTP_COOKIE_TOKENIZE "; "
  43. #define HTTP_1_0_STR "HTTP/1.0"
  44. #define HTTP_1_1_STR "HTTP/1.1"
  45. #define HTTP_HEADER_HOST "Host"
  46. #define HTTP_HEADER_COOKIE "Cookie"
  47. #define HTTP_HEADER_SET_COOKIE "Set-Cookie"
  48. #define HTTP_HEADER_CONTENT_TYPE "Content-Type"
  49. #define HTTP_HEADER_CONTENT_LENGTH "Content-Length"
  50. #define HTTP_HEADER_CONTENT_ENCODING "Content-Encoding"
  51. #define HTTP_HEADER_TRANSFER_ENCODING "Transfer-Encoding"
  52. #define HTTP_HEADER_UPGRADE "Upgrade"
  53. #define HTTP_HEADER_VALUE_WEB_SOCKET "WebSocket"
  54. #define HTTP_METHOD_POST "POST"
  55. #define HTTP_METHOD_PUT "PUT"
  56. #define HTTP_METHOD_PATCH "PATCH"
  57. #define HTTP_METHOD_GET "GET"
  58. #define HTTP_METHOD_DELETE "DELETE"
  59. #define HTTP_METHOD_HEAD "HEAD"
  60. #define HTTP_METHOD_TRACE "TRACE"
  61. #define HTTP_METHOD_OPTIONS "OPTIONS"
  62. #define HTTP_METHOD_CONNECT "CONNECT"
  63. #define HTTP_MIN_WS_HEADER_LEN 2
  64. #define HTTP_MAX_WS_HEADER_LEN 14
  65. extern const DWORD MIN_HTTP_RELEASE_CHECK_INTERVAL;
  66. extern const DWORD MIN_HTTP_RELEASE_DELAY;
  67. extern const DWORD MAX_HTTP_RELEASE_DELAY;
  68. extern const DWORD DEFAULT_HTTP_RELEASE_DELAY;
  69. extern const EnHttpVersion DEFAULT_HTTP_VERSION;
  70. extern const DWORD DEFAULT_HTTP_SYNC_CONNECT_TIMEOUT;
  71. extern const DWORD DEFAULT_HTTP_SYNC_REQUEST_TIMEOUT;
  72. // ------------------------------------------------------------------------------------------------------------- //
  73. enum EnHttpSyncRequestProgress
  74. {
  75. HSRP_DONE,
  76. HSRP_WAITING,
  77. HSRP_ERROR,
  78. HSRP_CLOSE
  79. };
  80. struct TDyingConnection
  81. {
  82. CONNID connID;
  83. DWORD killTime;
  84. TDyingConnection(CONNID id, DWORD kt = 0)
  85. : connID (id)
  86. , killTime (kt == 0 ? ::TimeGetTime() : kt)
  87. {
  88. }
  89. static TDyingConnection* Construct(CONNID id, DWORD kt = 0) {return new TDyingConnection(id, kt);}
  90. static void Destruct(TDyingConnection* pObj) {if(pObj) delete pObj;}
  91. };
  92. struct str_hash_func
  93. {
  94. struct hash
  95. {
  96. size_t operator() (const char* p) const
  97. {
  98. return hash_value(p);
  99. }
  100. };
  101. struct equal_to
  102. {
  103. bool operator () (const char* p1, const char* p2) const
  104. {
  105. return strcmp(p1, p2) == 0;
  106. }
  107. };
  108. };
  109. struct cstringa_hash_func
  110. {
  111. struct hash
  112. {
  113. size_t operator() (const CStringA& str) const
  114. {
  115. size_t s = hash_value((LPCSTR)str);
  116. return s;
  117. }
  118. };
  119. struct equal_to
  120. {
  121. bool operator () (const CStringA& strA, const CStringA& strB) const
  122. {
  123. return strA == strB;
  124. }
  125. };
  126. };
  127. typedef unordered_multimap<CStringA, CStringA,
  128. cstringa_hash_func::hash, cstringa_hash_func::equal_to> THeaderMap;
  129. typedef THeaderMap::const_iterator THeaderMapCI;
  130. typedef THeaderMap::iterator THeaderMapI;
  131. typedef unordered_map<CStringA, CStringA,
  132. cstringa_hash_func::hash, cstringa_hash_func::equal_to> TCookieMap;
  133. typedef TCookieMap::const_iterator TCookieMapCI;
  134. typedef TCookieMap::iterator TCookieMapI;
  135. // ------------------------------------------------------------------------------------------------------------- //
  136. struct TBaseWSHeader
  137. {
  138. public:
  139. BOOL fin()
  140. {
  141. return (data >> 7) & 0x1;
  142. }
  143. void set_fin(BOOL v)
  144. {
  145. data |= ((v ? 1 : 0) << 7);
  146. }
  147. BYTE rsv()
  148. {
  149. return (data >> 4) & 0x7;
  150. }
  151. void set_rsv(BYTE v)
  152. {
  153. data |= ((v & 0x7) << 4);
  154. }
  155. BYTE code()
  156. {
  157. return data & 0xF;
  158. }
  159. void set_code(BYTE v)
  160. {
  161. data |= (v & 0xF);
  162. }
  163. BOOL mask()
  164. {
  165. return (data >> 15) & 0x1;
  166. }
  167. void set_mask(BOOL v)
  168. {
  169. data |= ((v ? 1 : 0) << 15);
  170. }
  171. BYTE len()
  172. {
  173. return (data >> 8) & 0x7F;
  174. }
  175. void set_len(BYTE v)
  176. {
  177. data |= ((v & 0x7F) << 8);
  178. }
  179. USHORT extlen()
  180. {
  181. return ntohs(data >> 16);
  182. }
  183. void set_extlen(USHORT v)
  184. {
  185. data |= (htons(v) << 16);
  186. }
  187. TBaseWSHeader(const BYTE* p, BOOL bZero = FALSE)
  188. : data(*(UINT*)p)
  189. {
  190. if(bZero) data = 0;
  191. }
  192. private:
  193. UINT& data;
  194. };
  195. template<class T> struct TWSContext
  196. {
  197. public:
  198. EnHandleResult Parse(const BYTE* pData, int iLength)
  199. {
  200. ASSERT(pData != nullptr && iLength > 0);
  201. EnHandleResult hr = HR_OK;
  202. BYTE* pTemp = (BYTE*)pData;
  203. int iRemain = iLength;
  204. int iMin = 0;
  205. while(iRemain > 0)
  206. {
  207. if(m_bHeader)
  208. {
  209. iMin = min(m_iHeaderRemain, iRemain);
  210. memcpy(m_szHeader + m_iHeaderLen - m_iHeaderRemain, pTemp, iMin);
  211. m_iHeaderRemain -= iMin;
  212. if(m_iHeaderRemain == 0)
  213. {
  214. TBaseWSHeader bh(m_szHeader);
  215. int iLen = bh.len();
  216. int iExtLen = iLen < 126 ? 0 : (iLen == 126 ? 2 : 8);
  217. int iMaskLen = bh.mask() ? 4 : 0;
  218. int iRealHeaderLen = HTTP_MIN_WS_HEADER_LEN + iExtLen + iMaskLen;
  219. if(m_iHeaderLen < iRealHeaderLen)
  220. {
  221. m_iHeaderRemain = iRealHeaderLen - m_iHeaderLen;
  222. m_iHeaderLen = iRealHeaderLen;
  223. }
  224. else
  225. {
  226. m_ullBodyLen = iExtLen == 0 ? iLen : (iExtLen == 2 ? bh.extlen() : NToH64(*(ULONGLONG*)(m_szHeader + HTTP_MIN_WS_HEADER_LEN)));
  227. m_ullBodyRemain = m_ullBodyLen;
  228. m_lpszMask = iMaskLen > 0 ? m_szHeader + HTTP_MIN_WS_HEADER_LEN + iExtLen : nullptr;
  229. hr = m_pHttpObj->on_ws_message_header(bh.fin(), bh.rsv(), bh.code(), m_lpszMask, m_ullBodyLen);
  230. if(hr == HR_ERROR)
  231. break;
  232. if(m_ullBodyLen > 0)
  233. m_bHeader = FALSE;
  234. else
  235. {
  236. hr = CompleteMessage();
  237. if(hr == HR_ERROR)
  238. break;
  239. }
  240. }
  241. }
  242. }
  243. else
  244. {
  245. iMin = (int)min(m_ullBodyRemain, (ULONGLONG)iRemain);
  246. if(m_lpszMask)
  247. {
  248. int iFactor = (m_ullBodyLen - m_ullBodyRemain) & 0x03;
  249. for(int i = 0; i < iMin; i++)
  250. pTemp[i] = pTemp[i] ^ m_lpszMask[(i + iFactor) & 0x03];
  251. }
  252. m_ullBodyRemain -= iMin;
  253. EnHandleResult hr = m_pHttpObj->on_ws_message_body(pTemp, iMin);
  254. if(hr == HR_ERROR)
  255. break;
  256. if(m_ullBodyRemain == 0)
  257. {
  258. hr = CompleteMessage();
  259. if(hr == HR_ERROR)
  260. break;
  261. }
  262. }
  263. pTemp += iMin;
  264. iRemain -= iMin;
  265. }
  266. return HR_OK;
  267. }
  268. BOOL GetMessageState(BOOL* lpbFinal, BYTE* lpiReserved, BYTE* lpiOperationCode, LPCBYTE* lpszMask, ULONGLONG* lpullBodyLen, ULONGLONG* lpullBodyRemain)
  269. {
  270. TBaseWSHeader bh(m_szHeader);
  271. if(lpbFinal) *lpbFinal = bh.fin();
  272. if(lpiReserved) *lpiReserved = bh.rsv();
  273. if(lpiOperationCode) *lpiOperationCode = bh.code();
  274. if(lpszMask) *lpszMask = m_lpszMask;
  275. if(lpullBodyLen) *lpullBodyLen = m_ullBodyLen;
  276. if(lpullBodyRemain) *lpullBodyRemain = m_ullBodyRemain;
  277. return TRUE;
  278. }
  279. BOOL CopyData(const TWSContext& src)
  280. {
  281. if(&src == this)
  282. return FALSE;
  283. memcpy(m_szHeader, src.m_szHeader, HTTP_MAX_WS_HEADER_LEN);
  284. if(src.m_lpszMask)
  285. m_lpszMask = m_szHeader + (src.m_lpszMask - src.m_szHeader);
  286. else
  287. m_lpszMask = nullptr;
  288. m_ullBodyLen = src.m_ullBodyLen;
  289. m_ullBodyRemain = src.m_ullBodyRemain;
  290. return TRUE;
  291. }
  292. public:
  293. TWSContext(T* pHttpObj) : m_pHttpObj(pHttpObj)
  294. {
  295. Reset();
  296. }
  297. private:
  298. EnHandleResult CompleteMessage()
  299. {
  300. EnHandleResult hr = m_pHttpObj->on_ws_message_complete();
  301. Reset();
  302. return hr;
  303. }
  304. void Reset()
  305. {
  306. m_bHeader = TRUE;
  307. m_lpszMask = nullptr;
  308. m_iHeaderLen = HTTP_MIN_WS_HEADER_LEN;
  309. m_iHeaderRemain = HTTP_MIN_WS_HEADER_LEN;
  310. m_ullBodyLen = 0;
  311. m_ullBodyRemain = 0;
  312. }
  313. private:
  314. T* m_pHttpObj;
  315. BYTE m_szHeader[HTTP_MAX_WS_HEADER_LEN];
  316. const BYTE* m_lpszMask;
  317. BOOL m_bHeader;
  318. int m_iHeaderLen;
  319. int m_iHeaderRemain;
  320. ULONGLONG m_ullBodyLen;
  321. ULONGLONG m_ullBodyRemain;
  322. };
  323. // ------------------------------------------------------------------------------------------------------------- //
  324. /* Http 上下文结构 */
  325. template<class T, class S> struct THttpObjT
  326. {
  327. public:
  328. EnHandleResult Execute(const BYTE* pData, int iLength)
  329. {
  330. ASSERT(pData != nullptr && iLength > 0);
  331. if(m_parser.upgrade)
  332. {
  333. if(m_enUpgrade == HUT_WEB_SOCKET)
  334. return m_pwsContext->Parse(pData, iLength);
  335. else
  336. return m_pContext->DoFireSuperReceive(m_pSocket, pData, iLength);
  337. }
  338. EnHandleResult hr = HR_OK;
  339. int iPased = (int)::http_parser_execute(&m_parser, &sm_settings, (LPCSTR)pData, iLength);
  340. if(m_parser.upgrade)
  341. hr = Upgrade(pData, iLength, iPased);
  342. else if(m_parser.http_errno != HPE_OK)
  343. {
  344. m_pContext->FireParseError(m_pSocket, m_parser.http_errno, ::http_errno_description(HTTP_PARSER_ERRNO(&m_parser)));
  345. hr = HR_ERROR;
  346. }
  347. else
  348. ASSERT(iPased == iLength);
  349. return hr;
  350. }
  351. static int on_message_begin(http_parser* p)
  352. {
  353. THttpObjT* pSelf = Self(p);
  354. pSelf->ResetHeaderState(FALSE);
  355. return pSelf->m_pContext->FireMessageBegin(pSelf->m_pSocket);
  356. }
  357. static int on_url(http_parser* p, const char* at, size_t length)
  358. {
  359. EnHttpParseResult hpr = HPR_OK;
  360. THttpObjT* pSelf = Self(p);
  361. pSelf->AppendBuffer(at, length);
  362. if(p->state != s_req_http_start)
  363. return hpr;
  364. hpr = pSelf->ParseUrl();
  365. if(hpr == HPR_OK)
  366. hpr = pSelf->m_pContext->FireRequestLine(pSelf->m_pSocket, ::http_method_str((http_method)p->method), pSelf->GetBuffer());
  367. pSelf->ResetBuffer();
  368. return hpr;
  369. }
  370. static int on_status(http_parser* p, const char* at, size_t length)
  371. {
  372. EnHttpParseResult hpr = HPR_OK;
  373. THttpObjT* pSelf = Self(p);
  374. pSelf->AppendBuffer(at, length);
  375. if(p->state != s_res_line_almost_done)
  376. return hpr;
  377. hpr = pSelf->m_pContext->FireStatusLine(pSelf->m_pSocket, p->status_code, pSelf->GetBuffer());
  378. pSelf->ResetBuffer();
  379. return hpr;
  380. }
  381. static int on_header_field(http_parser* p, const char* at, size_t length)
  382. {
  383. EnHttpParseResult hpr = HPR_OK;
  384. THttpObjT* pSelf = Self(p);
  385. pSelf->AppendBuffer(at, length);
  386. if(p->state != s_header_value_discard_ws)
  387. return hpr;
  388. pSelf->m_strCurHeader = pSelf->GetBuffer();
  389. pSelf->ResetBuffer();
  390. return hpr;
  391. }
  392. static int on_header_value(http_parser* p, const char* at, size_t length)
  393. {
  394. EnHttpParseResult hpr = HPR_OK;
  395. THttpObjT* pSelf = Self(p);
  396. pSelf->AppendBuffer(at, length);
  397. if(p->state != s_header_almost_done && p->state != s_header_field_start)
  398. return hpr;
  399. if(pSelf->m_bRequest && pSelf->m_strCurHeader == HTTP_HEADER_COOKIE)
  400. hpr = pSelf->ParseCookie();
  401. else
  402. {
  403. pSelf->m_headers.emplace(move(THeaderMap::value_type(pSelf->m_strCurHeader, pSelf->GetBuffer())));
  404. hpr = pSelf->m_pContext->FireHeader(pSelf->m_pSocket, pSelf->m_strCurHeader, pSelf->GetBuffer());
  405. }
  406. pSelf->ResetBuffer();
  407. return hpr;
  408. }
  409. static int on_headers_complete(http_parser* p)
  410. {
  411. THttpObjT* pSelf = Self(p);
  412. pSelf->CheckUpgrade();
  413. pSelf->ResetHeaderBuffer();
  414. return pSelf->m_pContext->FireHeadersComplete(pSelf->m_pSocket);
  415. }
  416. static int on_body(http_parser* p, const char* at, size_t length)
  417. {
  418. THttpObjT* pSelf = Self(p);
  419. return pSelf->m_pContext->FireBody(pSelf->m_pSocket, (const BYTE*)at, (int)length);
  420. }
  421. static int on_chunk_header(http_parser* p)
  422. {
  423. THttpObjT* pSelf = Self(p);
  424. if(p->state == s_chunk_data || p->state == s_header_field_start)
  425. return pSelf->m_pContext->FireChunkHeader(pSelf->m_pSocket, (int)p->content_length);
  426. return HPR_OK;
  427. }
  428. static int on_chunk_complete(http_parser* p)
  429. {
  430. THttpObjT* pSelf = Self(p);
  431. if(p->state == s_headers_done || p->state == s_message_done)
  432. return pSelf->m_pContext->FireChunkComplete(pSelf->m_pSocket);
  433. return HPR_OK;
  434. }
  435. static int on_message_complete(http_parser* p)
  436. {
  437. THttpObjT* pSelf = Self(p);
  438. EnHttpParseResult hpr = pSelf->m_pContext->FireMessageComplete(pSelf->m_pSocket);
  439. return hpr;
  440. }
  441. EnHandleResult on_ws_message_header(BOOL bFinal, BYTE iReserved, BYTE iOperationCode, const BYTE lpszMask[4], ULONGLONG ullBodyLen)
  442. {
  443. return m_pContext->FireWSMessageHeader(m_pSocket, bFinal, iReserved, iOperationCode, lpszMask, ullBodyLen);
  444. }
  445. EnHandleResult on_ws_message_body(const BYTE* pData, int iLength)
  446. {
  447. return m_pContext->FireWSMessageBody(m_pSocket, pData, iLength);
  448. }
  449. EnHandleResult on_ws_message_complete()
  450. {
  451. return m_pContext->FireWSMessageComplete(m_pSocket);
  452. }
  453. private:
  454. EnHandleResult Upgrade(const BYTE* pData, int iLength, int iPased)
  455. {
  456. ASSERT(m_parser.upgrade);
  457. if(m_pContext->FireUpgrade(m_pSocket, m_enUpgrade) != HPR_OK)
  458. return HR_ERROR;
  459. ResetHeaderState();
  460. if(m_enUpgrade == HUT_WEB_SOCKET)
  461. m_pwsContext = new TWSContext<THttpObjT<T, S>>(this);
  462. if(iPased < iLength)
  463. return Execute(pData + iPased, iLength - iPased);
  464. return HR_OK;
  465. }
  466. void CheckUpgrade()
  467. {
  468. if(!m_parser.upgrade)
  469. return;
  470. if(m_bRequest && m_parser.method == HTTP_CONNECT)
  471. m_enUpgrade = HUT_HTTP_TUNNEL;
  472. else
  473. {
  474. LPCSTR lpszValue;
  475. if(GetHeader(HTTP_HEADER_UPGRADE, &lpszValue) && _stricmp(HTTP_HEADER_VALUE_WEB_SOCKET, lpszValue) == 0)
  476. m_enUpgrade = HUT_WEB_SOCKET;
  477. else
  478. m_enUpgrade = HUT_UNKNOWN;
  479. }
  480. }
  481. EnHttpParseResult ParseUrl()
  482. {
  483. http_parser_url url = {0};
  484. BOOL isConnect = m_parser.method == HTTP_CONNECT;
  485. int rs = ::http_parser_parse_url(m_strBuffer, m_strBuffer.GetLength(), isConnect, &url);
  486. if(rs != HPE_OK)
  487. {
  488. m_parser.http_errno = HPE_INVALID_URL;
  489. return HPR_ERROR;
  490. }
  491. m_usUrlFieldSet = url.field_set;
  492. LPCSTR lpszBuffer = (LPCSTR)m_strBuffer;
  493. for(int i = 0; i < UF_MAX; i++)
  494. {
  495. if((url.field_set & (1 << i)) != 0)
  496. m_pstrUrlFileds[i].SetString((lpszBuffer + url.field_data[i].off), url.field_data[i].len);
  497. }
  498. return HPR_OK;
  499. }
  500. EnHttpParseResult ParseCookie()
  501. {
  502. int i = 0;
  503. do
  504. {
  505. CStringA tk = m_strBuffer.Tokenize(HTTP_COOKIE_TOKENIZE, i);
  506. if(i != -1)
  507. {
  508. int j = tk.Find(HTTP_NV_SEPARATOR_CHAR);
  509. if(j <= 0)
  510. {
  511. m_parser.http_errno = HPE_INVALID_HEADER_TOKEN;
  512. return HPR_ERROR;
  513. }
  514. m_cookies.emplace(move(TCookieMap::value_type(tk.Left(j), tk.Mid(j + 1))));
  515. }
  516. } while(i != -1);
  517. return HPR_OK;
  518. }
  519. public:
  520. DWORD GetFreeTime() const {return m_dwFreeTime;}
  521. void SetFree() {m_dwFreeTime = ::TimeGetTime();}
  522. BOOL IsUpgrade() {return m_parser.upgrade;}
  523. BOOL IsKeepAlive() {return ::http_should_keep_alive(&m_parser);}
  524. USHORT GetVersion() {return MAKEWORD(m_parser.http_major, m_parser.http_minor);}
  525. ULONGLONG GetContentLength() {return m_parser.content_length;}
  526. LPCSTR GetMethod() {return ::http_method_str((http_method)(m_parser.method));}
  527. USHORT GetUrlFieldSet() {return m_usUrlFieldSet;}
  528. USHORT GetStatusCode() {return m_parser.status_code;}
  529. EnHttpUpgradeType GetUpgradeType() {return m_enUpgrade;}
  530. THeaderMap& GetHeaderMap() {return m_headers;}
  531. TCookieMap& GetCookieMap() {return m_cookies;}
  532. BOOL HasReleased() {return m_bReleased;}
  533. void Release() {m_bReleased = TRUE;}
  534. LPCSTR GetContentType()
  535. {
  536. LPCSTR lpszValue = nullptr;
  537. GetHeader(HTTP_HEADER_CONTENT_TYPE, &lpszValue);
  538. return lpszValue;
  539. }
  540. LPCSTR GetContentEncoding()
  541. {
  542. LPCSTR lpszValue = nullptr;
  543. GetHeader(HTTP_HEADER_CONTENT_ENCODING, &lpszValue);
  544. return lpszValue;
  545. }
  546. LPCSTR GetTransferEncoding()
  547. {
  548. LPCSTR lpszValue = nullptr;
  549. GetHeader(HTTP_HEADER_TRANSFER_ENCODING, &lpszValue);
  550. return lpszValue;
  551. }
  552. LPCSTR GetHost()
  553. {
  554. LPCSTR lpszValue = nullptr;
  555. GetHeader(HTTP_HEADER_HOST, &lpszValue);
  556. return lpszValue;
  557. }
  558. USHORT GetParseErrorCode(LPCSTR* lpszErrorDesc = nullptr)
  559. {
  560. if(lpszErrorDesc)
  561. *lpszErrorDesc = ::http_errno_description(HTTP_PARSER_ERRNO(&m_parser));
  562. return m_parser.http_errno;
  563. }
  564. LPCSTR GetUrlField(EnHttpUrlField enField)
  565. {
  566. ASSERT(m_pstrUrlFileds && enField < HUF_MAX);
  567. if(m_pstrUrlFileds && enField < HUF_MAX)
  568. return (LPCSTR)m_pstrUrlFileds[enField];
  569. return nullptr;
  570. }
  571. BOOL GetHeader(LPCSTR lpszName, LPCSTR* lpszValue)
  572. {
  573. ASSERT(lpszName);
  574. BOOL isOK = FALSE;
  575. THeaderMapCI it = m_headers.find(lpszName);
  576. if(it != m_headers.end())
  577. {
  578. *lpszValue = it->second;
  579. isOK = TRUE;
  580. }
  581. return isOK;
  582. }
  583. BOOL GetHeaders(LPCSTR lpszName, LPCSTR lpszValue[], DWORD& dwCount)
  584. {
  585. ASSERT(lpszName);
  586. if(lpszValue == nullptr || dwCount == 0)
  587. {
  588. dwCount = (DWORD)m_headers.count(lpszName);
  589. return FALSE;
  590. }
  591. pair<THeaderMapCI, THeaderMapCI> range = m_headers.equal_range(lpszName);
  592. THeaderMapCI it = range.first;
  593. DWORD dwIndex = 0;
  594. while(it != range.second)
  595. {
  596. if(dwIndex < dwCount)
  597. lpszValue[dwIndex] = it->second;
  598. ++dwIndex;
  599. ++it;
  600. }
  601. BOOL isOK = (dwIndex > 0 && dwIndex <= dwCount);
  602. dwCount = dwIndex;
  603. return isOK;
  604. }
  605. BOOL GetAllHeaders(THeader lpHeaders[], DWORD& dwCount)
  606. {
  607. DWORD dwSize = (DWORD)m_headers.size();
  608. if(lpHeaders == nullptr || dwCount == 0 || dwSize == 0 || dwSize > dwCount)
  609. {
  610. dwCount = dwSize;
  611. return FALSE;
  612. }
  613. DWORD dwIndex = 0;
  614. for(THeaderMapCI it = m_headers.begin(), end = m_headers.end(); it != end; ++it, ++dwIndex)
  615. {
  616. lpHeaders[dwIndex].name = it->first;
  617. lpHeaders[dwIndex].value = it->second;
  618. }
  619. dwCount = dwSize;
  620. return TRUE;
  621. }
  622. BOOL GetAllHeaderNames(LPCSTR lpszName[], DWORD& dwCount)
  623. {
  624. DWORD dwSize = (DWORD)m_headers.size();
  625. if(lpszName == nullptr || dwCount == 0 || dwSize == 0 || dwSize > dwCount)
  626. {
  627. dwCount = dwSize;
  628. return FALSE;
  629. }
  630. DWORD dwIndex = 0;
  631. for(THeaderMapCI it = m_headers.begin(), end = m_headers.end(); it != end; ++it, ++dwIndex)
  632. lpszName[dwIndex] = it->first;
  633. dwCount = dwSize;
  634. return TRUE;
  635. }
  636. BOOL AddCookie(LPCSTR lpszName, LPCSTR lpszValue, BOOL bRelpace = TRUE)
  637. {
  638. ASSERT(lpszName);
  639. if(bRelpace)
  640. DeleteCookie(lpszName);
  641. return m_cookies.emplace(TCookieMap::value_type(lpszName, lpszValue)).second;
  642. }
  643. BOOL DeleteCookie(LPCSTR lpszName)
  644. {
  645. ASSERT(lpszName);
  646. return m_cookies.erase(lpszName) > 0;
  647. }
  648. void DeleteAllCookies()
  649. {
  650. m_cookies.clear();
  651. }
  652. BOOL GetCookie(LPCSTR lpszName, LPCSTR* lpszValue)
  653. {
  654. ASSERT(lpszName);
  655. BOOL isOK = FALSE;
  656. TCookieMapCI it = m_cookies.find(lpszName);
  657. if(it != m_cookies.end())
  658. {
  659. *lpszValue = it->second;
  660. isOK = TRUE;
  661. }
  662. return isOK;
  663. }
  664. BOOL GetAllCookies(TCookie lpCookies[], DWORD& dwCount)
  665. {
  666. DWORD dwSize = (DWORD)m_cookies.size();
  667. if(lpCookies == nullptr || dwCount == 0 || dwSize == 0 || dwSize > dwCount)
  668. {
  669. dwCount = dwSize;
  670. return FALSE;
  671. }
  672. DWORD dwIndex = 0;
  673. for(TCookieMapCI it = m_cookies.begin(), end = m_cookies.end(); it != end; ++it, ++dwIndex)
  674. {
  675. lpCookies[dwIndex].name = it->first;
  676. lpCookies[dwIndex].value = it->second;
  677. }
  678. dwCount = dwSize;
  679. return TRUE;
  680. }
  681. BOOL GetWSMessageState(BOOL* lpbFinal, BYTE* lpiReserved, BYTE* lpiOperationCode, LPCBYTE* lpszMask, ULONGLONG* lpullBodyLen, ULONGLONG* lpullBodyRemain)
  682. {
  683. if(!m_pwsContext)
  684. return FALSE;
  685. return m_pwsContext->GetMessageState(lpbFinal, lpiReserved, lpiOperationCode, lpszMask, lpullBodyLen, lpullBodyRemain);
  686. }
  687. public:
  688. THttpObjT (BOOL bRequest, T* pContext, S* pSocket)
  689. : m_pContext (pContext)
  690. , m_pSocket (pSocket)
  691. , m_bRequest (bRequest)
  692. , m_bReleased (FALSE)
  693. , m_dwFreeTime (0)
  694. , m_usUrlFieldSet (0)
  695. , m_pstrUrlFileds (nullptr)
  696. , m_enUpgrade (HUT_NONE)
  697. , m_pwsContext (nullptr)
  698. {
  699. if(m_bRequest)
  700. m_pstrUrlFileds = new CStringA[HUF_MAX];
  701. ResetParser();
  702. }
  703. ~THttpObjT()
  704. {
  705. if(m_pstrUrlFileds)
  706. delete[] m_pstrUrlFileds;
  707. ReleaseWSContext();
  708. }
  709. static THttpObjT* Construct(BOOL bRequest, T* pContext, S* pSocket)
  710. {return new THttpObjT(bRequest, pContext, pSocket);}
  711. static void Destruct(THttpObjT* pHttpObj)
  712. {if(pHttpObj) delete pHttpObj;}
  713. void Reset()
  714. {
  715. ResetParser();
  716. ResetHeaderState();
  717. ReleaseWSContext();
  718. m_bReleased = FALSE;
  719. m_enUpgrade = HUT_NONE;
  720. m_dwFreeTime = 0;
  721. }
  722. void Renew(T* pContext, S* pSocket)
  723. {
  724. m_pContext = pContext;
  725. m_pSocket = pSocket;
  726. Reset();
  727. }
  728. BOOL CopyData(const THttpObjT& src)
  729. {
  730. if(&src == this)
  731. return FALSE;
  732. if(m_bRequest != src.m_bRequest)
  733. return FALSE;
  734. void* p = m_parser.data;
  735. m_parser = src.m_parser;
  736. m_parser.data = p;
  737. m_headers = src.m_headers;
  738. m_cookies = src.m_cookies;
  739. if(src.m_pstrUrlFileds && m_pstrUrlFileds)
  740. {
  741. m_usUrlFieldSet = src.m_usUrlFieldSet;
  742. for(int i = 0;i < HUF_MAX; i++)
  743. m_pstrUrlFileds[i] = src.m_pstrUrlFileds[i];
  744. }
  745. m_enUpgrade = src.m_enUpgrade;
  746. return TRUE;
  747. }
  748. BOOL CopyWSContext(const THttpObjT& src)
  749. {
  750. if(&src == this)
  751. return FALSE;
  752. if(m_bRequest != src.m_bRequest)
  753. return FALSE;
  754. if(!src.m_pwsContext && !m_pwsContext)
  755. ;
  756. else if(!src.m_pwsContext && m_pwsContext)
  757. {
  758. delete m_pwsContext;
  759. m_pwsContext = nullptr;
  760. }
  761. else
  762. {
  763. if(!m_pwsContext)
  764. m_pwsContext = new TWSContext<THttpObjT<T, S>>(this);
  765. m_pwsContext->CopyData(*src.m_pwsContext);
  766. }
  767. return TRUE;
  768. }
  769. private:
  770. void ResetParser()
  771. {
  772. ::http_parser_init(&m_parser, m_bRequest ? HTTP_REQUEST : HTTP_RESPONSE);
  773. m_parser.data = this;
  774. }
  775. void ResetHeaderState(BOOL bClearCookies = TRUE)
  776. {
  777. if(m_pstrUrlFileds && m_usUrlFieldSet != 0)
  778. {
  779. m_usUrlFieldSet = 0;
  780. for(int i = 0; i < HUF_MAX; i++)
  781. m_pstrUrlFileds[i].Empty();
  782. }
  783. if(m_bRequest || bClearCookies)
  784. DeleteAllCookies();
  785. m_headers.clear();
  786. ResetHeaderBuffer();
  787. }
  788. void ResetHeaderBuffer()
  789. {
  790. ResetBuffer();
  791. m_strCurHeader.Empty();
  792. }
  793. void ReleaseWSContext()
  794. {
  795. if(m_pwsContext)
  796. {
  797. delete m_pwsContext;
  798. m_pwsContext = nullptr;
  799. }
  800. }
  801. void AppendBuffer(const char* at, size_t length) {m_strBuffer.Append(at, (int)length);}
  802. void ResetBuffer() {m_strBuffer.Empty();}
  803. LPCSTR GetBuffer() {return m_strBuffer;}
  804. static THttpObjT* Self(http_parser* p) {return (THttpObjT*)(p->data);}
  805. static T* SelfContext(http_parser* p) {return Self(p)->m_pContext;}
  806. static S* SelfSocketObj(http_parser* p) {return Self(p)->m_pSocket;}
  807. private:
  808. BOOL m_bRequest;
  809. BOOL m_bReleased;
  810. T* m_pContext;
  811. S* m_pSocket;
  812. http_parser m_parser;
  813. THeaderMap m_headers;
  814. TCookieMap m_cookies;
  815. CStringA m_strBuffer;
  816. CStringA m_strCurHeader;
  817. USHORT m_usUrlFieldSet;
  818. CStringA* m_pstrUrlFileds;
  819. EnHttpUpgradeType m_enUpgrade;
  820. DWORD m_dwFreeTime;
  821. TWSContext<THttpObjT<T, S>>* m_pwsContext;
  822. static http_parser_settings sm_settings;
  823. };
  824. template<class T, class S> http_parser_settings THttpObjT<T, S>::sm_settings =
  825. {
  826. on_message_begin,
  827. on_url,
  828. on_status,
  829. on_header_field,
  830. on_header_value,
  831. on_headers_complete,
  832. on_body,
  833. on_message_complete,
  834. on_chunk_header,
  835. on_chunk_complete
  836. };
  837. // ------------------------------------------------------------------------------------------------------------- //
  838. template<BOOL is_request, class T, class S> class CHttpObjPoolT
  839. {
  840. typedef THttpObjT<T, S> THttpObj;
  841. typedef CRingPool<THttpObj> TSSLHttpObjList;
  842. typedef CCASQueue<THttpObj> TSSLHttpObjQueue;
  843. public:
  844. THttpObj* PickFreeHttpObj(T* pContext, S* pSocket)
  845. {
  846. DWORD dwIndex;
  847. THttpObj* pHttpObj = nullptr;
  848. if(m_lsFreeHttpObj.TryLock(&pHttpObj, dwIndex))
  849. {
  850. if(::GetTimeGap32(pHttpObj->GetFreeTime()) >= m_dwHttpObjLockTime)
  851. m_lsFreeHttpObj.ReleaseLock(nullptr, dwIndex);
  852. else
  853. {
  854. m_lsFreeHttpObj.ReleaseLock(pHttpObj, dwIndex);
  855. pHttpObj = nullptr;
  856. }
  857. }
  858. if(pHttpObj)
  859. pHttpObj->Renew(pContext, pSocket);
  860. else
  861. {
  862. pHttpObj = THttpObj::Construct(is_request, pContext, pSocket);
  863. ASSERT(pHttpObj);
  864. }
  865. return pHttpObj;
  866. }
  867. void PutFreeHttpObj(THttpObj* pHttpObj)
  868. {
  869. pHttpObj->SetFree();
  870. if(!m_lsFreeHttpObj.TryPut(pHttpObj))
  871. {
  872. m_lsGCHttpObj.PushBack(pHttpObj);
  873. if(m_lsGCHttpObj.Size() > m_dwHttpObjPoolSize)
  874. ReleaseGCHttpObj();
  875. }
  876. }
  877. void Prepare()
  878. {
  879. m_lsFreeHttpObj.Reset(m_dwHttpObjPoolHold);
  880. }
  881. void Clear()
  882. {
  883. THttpObj* pHttpObj = nullptr;
  884. while(m_lsFreeHttpObj.TryGet(&pHttpObj))
  885. delete pHttpObj;
  886. VERIFY(m_lsFreeHttpObj.IsEmpty());
  887. m_lsFreeHttpObj.Reset();
  888. ReleaseGCHttpObj(TRUE);
  889. VERIFY(m_lsGCHttpObj.IsEmpty());
  890. }
  891. private:
  892. void ReleaseGCHttpObj(BOOL bForce = FALSE)
  893. {
  894. THttpObj* pHttpObj = nullptr;
  895. DWORD now = ::TimeGetTime();
  896. while(m_lsGCHttpObj.PopFront(&pHttpObj))
  897. {
  898. if(bForce || (int)(now - pHttpObj->GetFreeTime()) >= (int)m_dwHttpObjLockTime)
  899. delete pHttpObj;
  900. else
  901. {
  902. m_lsGCHttpObj.PushBack(pHttpObj);
  903. break;
  904. }
  905. }
  906. }
  907. public:
  908. void SetHttpObjLockTime (DWORD dwHttpObjLockTime) {m_dwHttpObjLockTime = dwHttpObjLockTime;}
  909. void SetHttpObjPoolSize (DWORD dwHttpObjPoolSize) {m_dwHttpObjPoolSize = dwHttpObjPoolSize;}
  910. void SetHttpObjPoolHold (DWORD dwHttpObjPoolHold) {m_dwHttpObjPoolHold = dwHttpObjPoolHold;}
  911. DWORD GetHttpObjLockTime() {return m_dwHttpObjLockTime;}
  912. DWORD GetHttpObjPoolSize() {return m_dwHttpObjPoolSize;}
  913. DWORD GetHttpObjPoolHold() {return m_dwHttpObjPoolHold;}
  914. public:
  915. CHttpObjPoolT( DWORD dwPoolSize = DEFAULT_HTTPOBJ_POOL_SIZE,
  916. DWORD dwPoolHold = DEFAULT_HTTPOBJ_POOL_HOLD,
  917. DWORD dwLockTime = DEFAULT_HTTPOBJ_LOCK_TIME)
  918. : m_dwHttpObjPoolSize(dwPoolSize)
  919. , m_dwHttpObjPoolHold(dwPoolHold)
  920. , m_dwHttpObjLockTime(dwLockTime)
  921. {
  922. }
  923. ~CHttpObjPoolT() {Clear();}
  924. DECLARE_NO_COPY_CLASS(CHttpObjPoolT)
  925. public:
  926. static const DWORD DEFAULT_HTTPOBJ_LOCK_TIME;
  927. static const DWORD DEFAULT_HTTPOBJ_POOL_SIZE;
  928. static const DWORD DEFAULT_HTTPOBJ_POOL_HOLD;
  929. private:
  930. DWORD m_dwHttpObjLockTime;
  931. DWORD m_dwHttpObjPoolSize;
  932. DWORD m_dwHttpObjPoolHold;
  933. TSSLHttpObjList m_lsFreeHttpObj;
  934. TSSLHttpObjQueue m_lsGCHttpObj;
  935. };
  936. template<BOOL is_request, class T, class S> const DWORD CHttpObjPoolT<is_request, T, S>::DEFAULT_HTTPOBJ_LOCK_TIME = 10 * 1000;
  937. template<BOOL is_request, class T, class S> const DWORD CHttpObjPoolT<is_request, T, S>::DEFAULT_HTTPOBJ_POOL_SIZE = 150;
  938. template<BOOL is_request, class T, class S> const DWORD CHttpObjPoolT<is_request, T, S>::DEFAULT_HTTPOBJ_POOL_HOLD = 600;
  939. // ------------------------------------------------------------------------------------------------------------- //
  940. extern CStringA& GetHttpVersionStr(EnHttpVersion enVersion, CStringA& strResult);
  941. extern LPCSTR GetHttpDefaultStatusCodeDesc(EnHttpStatusCode enCode);
  942. extern void MakeRequestLine(LPCSTR lpszMethod, LPCSTR lpszPath, EnHttpVersion enVersion, CStringA& strValue);
  943. extern void MakeStatusLine(EnHttpVersion enVersion, USHORT usStatusCode, LPCSTR lpszDesc, CStringA& strValue);
  944. extern void MakeHeaderLines(const THeader lpHeaders[], int iHeaderCount, const TCookieMap* pCookies, int iBodyLength, BOOL bRequest, LPCSTR lpszDefaultHost, USHORT usPort, CStringA& strValue);
  945. extern void MakeHttpPacket(const CStringA& strHeader, const BYTE* pBody, int iLength, WSABUF szBuffer[2]);
  946. extern BOOL MakeWSPacket(BOOL bFinal, BYTE iReserved, BYTE iOperationCode, const BYTE lpszMask[4], BYTE* pData, int iLength, ULONGLONG ullBodyLen, BYTE szHeader[HTTP_MAX_WS_HEADER_LEN], WSABUF szBuffer[2]);
  947. extern BOOL ParseUrl(const CStringA& strUrl, BOOL& bHttps, CStringA& strHost, USHORT& usPort, CStringA& strPath);
  948. // CP_XXX -> UNICODE
  949. BOOL CodePageToUnicode(int iCodePage, const char szSrc[], WCHAR szDest[], int& iDestLength);
  950. // UNICODE -> CP_XXX
  951. BOOL UnicodeToCodePage(int iCodePage, const WCHAR szSrc[], char szDest[], int& iDestLength);
  952. // GBK -> UNICODE
  953. BOOL GbkToUnicode(const char szSrc[], WCHAR szDest[], int& iDestLength);
  954. // UNICODE -> GBK
  955. BOOL UnicodeToGbk(const WCHAR szSrc[], char szDest[], int& iDestLength);
  956. // UTF8 -> UNICODE
  957. BOOL Utf8ToUnicode(const char szSrc[], WCHAR szDest[], int& iDestLength);
  958. // UNICODE -> UTF8
  959. BOOL UnicodeToUtf8(const WCHAR szSrc[], char szDest[], int& iDestLength);
  960. // GBK -> UTF8
  961. BOOL GbkToUtf8(const char szSrc[], char szDest[], int& iDestLength);
  962. // UTF8 -> GBK
  963. BOOL Utf8ToGbk(const char szSrc[], char szDest[], int& iDestLength);
  964. // 普通压缩(返回值:0 -> 成功,-3 -> 输入数据不正确,-5 -> 输出缓冲区不足)
  965. int Compress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen);
  966. // 高级压缩(返回值:0 -> 成功,-3 -> 输入数据不正确,-5 -> 输出缓冲区不足)
  967. int CompressEx(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen, int iLevel = Z_DEFAULT_COMPRESSION, int iMethod = Z_DEFLATED, int iWindowBits = DEF_WBITS, int iMemLevel = DEF_MEM_LEVEL, int iStrategy = Z_DEFAULT_STRATEGY);
  968. // 普通解压(返回值:0 -> 成功,-3 -> 输入数据不正确,-5 -> 输出缓冲区不足)
  969. int Uncompress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen);
  970. // 高级解压(返回值:0 -> 成功,-3 -> 输入数据不正确,-5 -> 输出缓冲区不足)
  971. int UncompressEx(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen, int iWindowBits = DEF_WBITS);
  972. // 推测压缩结果长度
  973. DWORD GuessCompressBound(DWORD dwSrcLen, BOOL bGZip = FALSE);
  974. // Gzip 压缩(返回值:0 -> 成功,-3 -> 输入数据不正确,-5 -> 输出缓冲区不足)
  975. int GZipCompress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen);
  976. // Gzip 解压(返回值:0 -> 成功,-3 -> 输入数据不正确,-5 -> 输出缓冲区不足)
  977. int GZipUncompress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen);
  978. // 推测 Gzip 解压结果长度(如果返回 0 或不合理值则说明输入内容并非有效的 Gzip 格式)
  979. DWORD GZipGuessUncompressBound(const BYTE* lpszSrc, DWORD dwSrcLen);
  980. // 计算 Base64 编码后长度
  981. DWORD GuessBase64EncodeBound(DWORD dwSrcLen);
  982. // 计算 Base64 解码后长度
  983. DWORD GuessBase64DecodeBound(const BYTE* lpszSrc, DWORD dwSrcLen);
  984. // Base64 编码(返回值:0 -> 成功,-3 -> 输入数据不正确,-5 -> 输出缓冲区不足)
  985. int Base64Encode(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen);
  986. // Base64 解码(返回值:0 -> 成功,-3 -> 输入数据不正确,-5 -> 输出缓冲区不足)
  987. int Base64Decode(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen);
  988. // 计算 URL 编码后长度
  989. DWORD GuessUrlEncodeBound(const BYTE* lpszSrc, DWORD dwSrcLen);
  990. // 计算 URL 解码后长度
  991. DWORD GuessUrlDecodeBound(const BYTE* lpszSrc, DWORD dwSrcLen);
  992. // URL 编码(返回值:0 -> 成功,-3 -> 输入数据不正确,-5 -> 输出缓冲区不足)
  993. int UrlEncode(BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen);
  994. // URL 解码(返回值:0 -> 成功,-3 -> 输入数据不正确,-5 -> 输出缓冲区不足)
  995. int UrlDecode(BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen);