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

HttpHelper.cpp 22KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832
  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. #include "stdafx.h"
  25. #include "HttpHelper.h"
  26. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  27. const DWORD MIN_HTTP_RELEASE_CHECK_INTERVAL = 1000;
  28. const DWORD MIN_HTTP_RELEASE_DELAY = 100;
  29. const DWORD MAX_HTTP_RELEASE_DELAY = 60 * 1000;
  30. const DWORD DEFAULT_HTTP_RELEASE_DELAY = 3 * 1000;
  31. const EnHttpVersion DEFAULT_HTTP_VERSION = HV_1_1;
  32. const DWORD DEFAULT_HTTP_SYNC_CONNECT_TIMEOUT = 5000;
  33. const DWORD DEFAULT_HTTP_SYNC_REQUEST_TIMEOUT = 10000;
  34. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  35. CStringA& GetHttpVersionStr(EnHttpVersion enVersion, CStringA& strResult)
  36. {
  37. strResult.Format("HTTP/%d.%d", LOBYTE(enVersion), HIBYTE(enVersion));
  38. return strResult;
  39. }
  40. LPCSTR GetHttpDefaultStatusCodeDesc(EnHttpStatusCode enCode)
  41. {
  42. switch(enCode)
  43. {
  44. case HSC_CONTINUE : return "Continue";
  45. case HSC_SWITCHING_PROTOCOLS : return "Switching Protocols";
  46. case HSC_PROCESSING : return "Processing";
  47. case HSC_OK : return "OK";
  48. case HSC_CREATED : return "Created";
  49. case HSC_ACCEPTED : return "Accepted";
  50. case HSC_NON_AUTHORITATIVE_INFORMATION : return "Non-Authoritative Information";
  51. case HSC_NO_CONTENT : return "No Content";
  52. case HSC_RESET_CONTENT : return "Reset Content";
  53. case HSC_PARTIAL_CONTENT : return "Partial Content";
  54. case HSC_MULTI_STATUS : return "Multi-Status";
  55. case HSC_ALREADY_REPORTED : return "Already Reported";
  56. case HSC_IM_USED : return "IM Used";
  57. case HSC_MULTIPLE_CHOICES : return "Multiple Choices";
  58. case HSC_MOVED_PERMANENTLY : return "Moved Permanently";
  59. case HSC_MOVED_TEMPORARILY : return "Move temporarily";
  60. case HSC_SEE_OTHER : return "See Other";
  61. case HSC_NOT_MODIFIED : return "Not Modified";
  62. case HSC_USE_PROXY : return "Use Proxy";
  63. case HSC_SWITCH_PROXY : return "Switch Proxy";
  64. case HSC_TEMPORARY_REDIRECT : return "Temporary Redirect";
  65. case HSC_PERMANENT_REDIRECT : return "Permanent Redirect";
  66. case HSC_BAD_REQUEST : return "Bad Request";
  67. case HSC_UNAUTHORIZED : return "Unauthorized";
  68. case HSC_PAYMENT_REQUIRED : return "Payment Required";
  69. case HSC_FORBIDDEN : return "Forbidden";
  70. case HSC_NOT_FOUND : return "Not Found";
  71. case HSC_METHOD_NOT_ALLOWED : return "Method Not Allowed";
  72. case HSC_NOT_ACCEPTABLE : return "Not Acceptable";
  73. case HSC_PROXY_AUTHENTICATION_REQUIRED : return "Proxy Authentication Required";
  74. case HSC_REQUEST_TIMEOUT : return "Request Timeout";
  75. case HSC_CONFLICT : return "Conflict";
  76. case HSC_GONE : return "Gone";
  77. case HSC_LENGTH_REQUIRED : return "Length Required";
  78. case HSC_PRECONDITION_FAILED : return "Precondition Failed";
  79. case HSC_REQUEST_ENTITY_TOO_LARGE : return "Request Entity Too Large";
  80. case HSC_REQUEST_URI_TOO_LONG : return "Request-URI Too Long";
  81. case HSC_UNSUPPORTED_MEDIA_TYPE : return "Unsupported Media Type";
  82. case HSC_REQUESTED_RANGE_NOT_SATISFIABLE: return "Requested Range Not Satisfiable";
  83. case HSC_EXPECTATION_FAILED : return "Expectation Failed";
  84. case HSC_MISDIRECTED_REQUEST : return "Misdirected Request";
  85. case HSC_UNPROCESSABLE_ENTITY : return "Unprocessable Entity";
  86. case HSC_LOCKED : return "Locked";
  87. case HSC_FAILED_DEPENDENCY : return "Failed Dependency";
  88. case HSC_UNORDERED_COLLECTION : return "Unordered Collection";
  89. case HSC_UPGRADE_REQUIRED : return "Upgrade Required";
  90. case HSC_PRECONDITION_REQUIRED : return "Precondition Required";
  91. case HSC_TOO_MANY_REQUESTS : return "Too Many Requests";
  92. case HSC_REQUEST_HEADER_FIELDS_TOO_LARGE: return "Request Header Fields Too Large";
  93. case HSC_UNAVAILABLE_FOR_LEGAL_REASONS : return "Unavailable For Legal Reasons";
  94. case HSC_RETRY_WITH : return "Retry With";
  95. case HSC_INTERNAL_SERVER_ERROR : return "Internal Server Error";
  96. case HSC_NOT_IMPLEMENTED : return "Not Implemented";
  97. case HSC_BAD_GATEWAY : return "Bad Gateway";
  98. case HSC_SERVICE_UNAVAILABLE : return "Service Unavailable";
  99. case HSC_GATEWAY_TIMEOUT : return "Gateway Timeout";
  100. case HSC_HTTP_VERSION_NOT_SUPPORTED : return "HTTP Version Not Supported";
  101. case HSC_VARIANT_ALSO_NEGOTIATES : return "Variant Also Negotiates";
  102. case HSC_INSUFFICIENT_STORAGE : return "Insufficient Storage";
  103. case HSC_LOOP_DETECTED : return "Loop Detected";
  104. case HSC_BANDWIDTH_LIMIT_EXCEEDED : return "Bandwidth Limit Exceeded";
  105. case HSC_NOT_EXTENDED : return "Not Extended";
  106. case HSC_NETWORK_AUTHENTICATION_REQUIRED: return "Network Authentication Required";
  107. case HSC_UNPARSEABLE_RESPONSE_HEADERS : return "Unparseable Response Headers";
  108. default : return "***";
  109. }
  110. }
  111. static inline CStringA& AppendHeader(LPCSTR lpszName, LPCSTR lpszValue, CStringA& strValue)
  112. {
  113. strValue.Append(lpszName);
  114. strValue.Append(HTTP_HEADER_SEPARATOR);
  115. strValue.Append(lpszValue);
  116. strValue.Append(HTTP_CRLF);
  117. return strValue;
  118. }
  119. void MakeRequestLine(LPCSTR lpszMethod, LPCSTR lpszPath, EnHttpVersion enVersion, CStringA& strValue)
  120. {
  121. ASSERT(lpszMethod);
  122. CStringA strMethod(lpszMethod);
  123. strMethod.MakeUpper();
  124. if(!lpszPath || lpszPath[0] == 0)
  125. lpszPath = HTTP_PATH_SEPARATOR;
  126. strValue.Format("%s %s HTTP/%d.%d%s", strMethod, lpszPath, LOBYTE(enVersion), HIBYTE(enVersion), HTTP_CRLF);
  127. }
  128. void MakeStatusLine(EnHttpVersion enVersion, USHORT usStatusCode, LPCSTR lpszDesc, CStringA& strValue)
  129. {
  130. if(!lpszDesc) lpszDesc = ::GetHttpDefaultStatusCodeDesc((EnHttpStatusCode)usStatusCode);
  131. strValue.Format("HTTP/%d.%d %d %s%s", LOBYTE(enVersion), HIBYTE(enVersion), usStatusCode, lpszDesc, HTTP_CRLF);
  132. }
  133. void MakeHeaderLines(const THeader lpHeaders[], int iHeaderCount, const TCookieMap* pCookies, int iBodyLength, BOOL bRequest, LPCSTR lpszDefaultHost, USHORT usPort, CStringA& strValue)
  134. {
  135. unordered_set<LPCSTR, str_hash_func::hash, str_hash_func::equal_to> szHeaderNames;
  136. if(iHeaderCount > 0)
  137. {
  138. ASSERT(lpHeaders);
  139. for(int i = 0; i < iHeaderCount; i++)
  140. {
  141. const THeader& header = lpHeaders[i];
  142. if(header.name != nullptr)
  143. {
  144. ASSERT(strlen(header.name) > 0);
  145. szHeaderNames.emplace(header.name);
  146. AppendHeader(header.name, header.value, strValue);
  147. }
  148. }
  149. }
  150. if( (!bRequest || iBodyLength > 0) &&
  151. (szHeaderNames.empty() ||
  152. (szHeaderNames.find(HTTP_HEADER_CONTENT_LENGTH) == szHeaderNames.end() &&
  153. szHeaderNames.find(HTTP_HEADER_TRANSFER_ENCODING) == szHeaderNames.end())))
  154. {
  155. char szBodyLength[16];
  156. _itoa(iBodyLength, szBodyLength, 10);
  157. AppendHeader(HTTP_HEADER_CONTENT_LENGTH, szBodyLength, strValue);
  158. }
  159. if( bRequest && lpszDefaultHost && lpszDefaultHost[0] != 0 &&
  160. (szHeaderNames.empty() ||
  161. (szHeaderNames.find(HTTP_HEADER_HOST) == szHeaderNames.end()) ))
  162. {
  163. CStringA strHost(lpszDefaultHost);
  164. if(usPort != 0) strHost.AppendFormat(":%u", usPort);
  165. AppendHeader(HTTP_HEADER_HOST, strHost, strValue);
  166. }
  167. szHeaderNames.clear();
  168. if(pCookies != nullptr)
  169. {
  170. DWORD dwSize = (DWORD)pCookies->size();
  171. if(dwSize > 0)
  172. {
  173. strValue.Append(HTTP_HEADER_COOKIE);
  174. strValue.Append(HTTP_HEADER_SEPARATOR);
  175. DWORD dwIndex = 0;
  176. for(TCookieMapCI it = pCookies->begin(), end = pCookies->end(); it != end; ++it, ++dwIndex)
  177. {
  178. strValue.Append(it->first);
  179. strValue.AppendChar(HTTP_NV_SEPARATOR_CHAR);
  180. strValue.Append(it->second);
  181. if(dwIndex < dwSize - 1)
  182. strValue.Append(HTTP_COOKIE_TOKENIZE);
  183. }
  184. strValue.Append(HTTP_CRLF);
  185. }
  186. }
  187. strValue.Append(HTTP_CRLF);
  188. }
  189. void MakeHttpPacket(const CStringA& strHeader, const BYTE* pBody, int iLength, WSABUF szBuffer[2])
  190. {
  191. ASSERT(pBody != nullptr || iLength == 0);
  192. szBuffer[0].buf = (LPSTR)(LPCSTR)strHeader;
  193. szBuffer[0].len = strHeader.GetLength();
  194. szBuffer[1].buf = (LPSTR)(LPCSTR)pBody;
  195. szBuffer[1].len = iLength;
  196. }
  197. 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])
  198. {
  199. ULONGLONG ullLength = (ULONGLONG)iLength;
  200. ASSERT(pData != nullptr || iLength == 0);
  201. ASSERT(ullBodyLen == 0 || ullBodyLen >= ullLength);
  202. if(ullBodyLen == 0)
  203. ullBodyLen = ullLength;
  204. else if(ullBodyLen < ullLength)
  205. {
  206. ::SetLastError(ERROR_INVALID_PARAMETER);
  207. return FALSE;
  208. }
  209. TBaseWSHeader bh(szHeader, TRUE);
  210. int iHeaderLen = HTTP_MIN_WS_HEADER_LEN;
  211. bh.set_fin(bFinal);
  212. bh.set_rsv(iReserved);
  213. bh.set_code(iOperationCode);
  214. bh.set_mask(lpszMask ? TRUE : FALSE);
  215. if(ullBodyLen < 126)
  216. bh.set_len((BYTE)ullBodyLen);
  217. else if(ullBodyLen <= 0xFFFF)
  218. {
  219. bh.set_len(126);
  220. bh.set_extlen((USHORT)ullBodyLen);
  221. iHeaderLen += 2;
  222. }
  223. else
  224. {
  225. bh.set_len(127);
  226. *(ULONGLONG*)(szHeader + HTTP_MIN_WS_HEADER_LEN) = ::HToN64(ullBodyLen);
  227. iHeaderLen += 8;
  228. }
  229. if(lpszMask)
  230. {
  231. memcpy(szHeader + iHeaderLen, lpszMask, 4);
  232. for(int i = 0; i < iLength; i++)
  233. pData[i] = pData[i] ^ lpszMask[i & 0x03];
  234. iHeaderLen += 4;
  235. }
  236. szBuffer[0].buf = (LPSTR)(LPCSTR)szHeader;
  237. szBuffer[0].len = iHeaderLen;
  238. szBuffer[1].buf = (LPSTR)(LPCSTR)pData;
  239. szBuffer[1].len = iLength;
  240. return TRUE;
  241. }
  242. BOOL ParseUrl(const CStringA& strUrl, BOOL& bHttps, CStringA& strHost, USHORT& usPort, CStringA& strPath)
  243. {
  244. int iSchemaLength = (int)strlen(HTTP_SCHEMA);
  245. CStringA strSchema = strUrl.Left(iSchemaLength);
  246. strSchema.MakeLower();
  247. if(strSchema.Compare(HTTP_SCHEMA) == 0)
  248. bHttps = FALSE;
  249. else
  250. {
  251. iSchemaLength = (int)strlen(HTTPS_SCHEMA);
  252. strSchema = strUrl.Left(iSchemaLength);
  253. strSchema.MakeLower();
  254. if(strSchema.Compare(HTTPS_SCHEMA) == 0)
  255. bHttps = TRUE;
  256. else
  257. return FALSE;
  258. }
  259. int i = strUrl.Find(HTTP_PATH_SEPARATOR_CHAR, iSchemaLength);
  260. if(i > 0)
  261. {
  262. strHost = strUrl.Mid(iSchemaLength, i - iSchemaLength);
  263. strPath = strUrl.Mid(i);
  264. }
  265. else
  266. {
  267. strHost = strUrl.Mid(iSchemaLength);
  268. strPath = HTTP_PATH_SEPARATOR;
  269. }
  270. if(strHost.IsEmpty() || !::isalnum(strHost.GetAt(0)))
  271. return FALSE;
  272. i = strHost.Find(HTTP_PORT_SEPARATOR_CHAR);
  273. if(i > 0)
  274. {
  275. CStringA strPort = strHost.Mid(i + 1);
  276. int iLength = strPort.GetLength();
  277. if(iLength == 0)
  278. return FALSE;
  279. for(int j = 0; j < iLength; j++)
  280. {
  281. if(!::isdigit(strPort.GetAt(j)))
  282. return FALSE;
  283. }
  284. usPort = (USHORT)::atoi(strPort);
  285. strHost = strHost.Mid(0, i);
  286. }
  287. else
  288. {
  289. usPort = bHttps ? HTTPS_DEFAULT_PORT : HTTP_DEFAULT_PORT;
  290. }
  291. return TRUE;
  292. }
  293. BOOL CodePageToUnicode(int iCodePage, const char szSrc[], WCHAR szDest[], int& iDestLength)
  294. {
  295. ASSERT(szSrc);
  296. int iSize = ::MultiByteToWideChar(iCodePage, 0, szSrc, -1, nullptr, 0);
  297. if(iSize == 0 || iSize > iDestLength || !szDest || iDestLength == 0)
  298. {
  299. iDestLength = iSize;
  300. return FALSE;
  301. }
  302. if(::MultiByteToWideChar(iCodePage, 0, szSrc, -1, szDest, iSize) != 0)
  303. iDestLength = iSize;
  304. else
  305. iDestLength = 0;
  306. return iDestLength != 0;
  307. }
  308. BOOL UnicodeToCodePage(int iCodePage, const WCHAR szSrc[], char szDest[], int& iDestLength)
  309. {
  310. ASSERT(szSrc);
  311. int iSize = ::WideCharToMultiByte(iCodePage, 0, szSrc, -1, nullptr, 0, nullptr, nullptr);
  312. if(iSize == 0 || iSize > iDestLength || !szDest || iDestLength == 0)
  313. {
  314. iDestLength = iSize;
  315. return FALSE;
  316. }
  317. if(::WideCharToMultiByte(iCodePage, 0, szSrc, -1, szDest, iSize, nullptr, nullptr) != 0)
  318. iDestLength = iSize;
  319. else
  320. iDestLength = 0;
  321. return iDestLength != 0;
  322. }
  323. BOOL GbkToUnicode(const char szSrc[], WCHAR szDest[], int& iDestLength)
  324. {
  325. return CodePageToUnicode(CP_ACP, szSrc, szDest, iDestLength);
  326. }
  327. BOOL UnicodeToGbk(const WCHAR szSrc[], char szDest[], int& iDestLength)
  328. {
  329. return UnicodeToCodePage(CP_ACP, szSrc, szDest, iDestLength);
  330. }
  331. BOOL Utf8ToUnicode(const char szSrc[], WCHAR szDest[], int& iDestLength)
  332. {
  333. return CodePageToUnicode(CP_UTF8, szSrc, szDest, iDestLength);
  334. }
  335. BOOL UnicodeToUtf8(const WCHAR szSrc[], char szDest[], int& iDestLength)
  336. {
  337. return UnicodeToCodePage(CP_UTF8, szSrc, szDest, iDestLength);
  338. }
  339. BOOL GbkToUtf8(const char szSrc[], char szDest[], int& iDestLength)
  340. {
  341. int iMiddleLength = 0;
  342. GbkToUnicode(szSrc, nullptr, iMiddleLength);
  343. if(iMiddleLength == 0)
  344. {
  345. iDestLength = 0;
  346. return FALSE;
  347. }
  348. unique_ptr<WCHAR[]> p(new WCHAR[iMiddleLength]);
  349. VERIFY(GbkToUnicode(szSrc, p.get(), iMiddleLength));
  350. return UnicodeToUtf8(p.get(), szDest, iDestLength);
  351. }
  352. BOOL Utf8ToGbk(const char szSrc[], char szDest[], int& iDestLength)
  353. {
  354. int iMiddleLength = 0;
  355. Utf8ToUnicode(szSrc, nullptr, iMiddleLength);
  356. if(iMiddleLength == 0)
  357. {
  358. iDestLength = 0;
  359. return FALSE;
  360. }
  361. unique_ptr<WCHAR[]> p(new WCHAR[iMiddleLength]);
  362. VERIFY(Utf8ToUnicode(szSrc, p.get(), iMiddleLength));
  363. return UnicodeToGbk(p.get(), szDest, iDestLength);
  364. }
  365. int Compress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen)
  366. {
  367. return CompressEx(lpszSrc, dwSrcLen, lpszDest, dwDestLen);
  368. }
  369. int CompressEx(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen, int iLevel, int iMethod, int iWindowBits, int iMemLevel, int iStrategy)
  370. {
  371. z_stream stream;
  372. stream.next_in = (z_const Bytef*)lpszSrc;
  373. stream.avail_in = dwSrcLen;
  374. stream.next_out = lpszDest;
  375. stream.avail_out = dwDestLen;
  376. stream.zalloc = nullptr;
  377. stream.zfree = nullptr;
  378. stream.opaque = nullptr;
  379. int err = ::deflateInit2(&stream, iLevel, iMethod, iWindowBits, iMemLevel, iStrategy);
  380. if(err != Z_OK) return err;
  381. err = ::deflate(&stream, Z_FINISH);
  382. if(err != Z_STREAM_END)
  383. {
  384. ::deflateEnd(&stream);
  385. return err == Z_OK ? Z_BUF_ERROR : err;
  386. }
  387. if(dwDestLen > stream.total_out)
  388. {
  389. lpszDest[stream.total_out] = 0;
  390. dwDestLen = stream.total_out;
  391. }
  392. return ::deflateEnd(&stream);
  393. }
  394. int Uncompress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen)
  395. {
  396. return UncompressEx(lpszSrc, dwSrcLen, lpszDest, dwDestLen);
  397. }
  398. int UncompressEx(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen, int iWindowBits)
  399. {
  400. z_stream stream;
  401. stream.next_in = (z_const Bytef*)lpszSrc;
  402. stream.avail_in = (uInt)dwSrcLen;
  403. stream.next_out = lpszDest;
  404. stream.avail_out = dwDestLen;
  405. stream.zalloc = nullptr;
  406. stream.zfree = nullptr;
  407. int err = ::inflateInit2(&stream, iWindowBits);
  408. if(err != Z_OK) return err;
  409. err = ::inflate(&stream, Z_FINISH);
  410. if(err != Z_STREAM_END)
  411. {
  412. ::inflateEnd(&stream);
  413. return (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) ? Z_DATA_ERROR : err;
  414. }
  415. if(dwDestLen > stream.total_out)
  416. {
  417. lpszDest[stream.total_out] = 0;
  418. dwDestLen = stream.total_out;
  419. }
  420. return inflateEnd(&stream);
  421. }
  422. DWORD GuessCompressBound(DWORD dwSrcLen, BOOL bGZip)
  423. {
  424. DWORD dwBound = ::compressBound(dwSrcLen);
  425. if(bGZip) dwBound += 11;
  426. return dwBound;
  427. }
  428. int GZipCompress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen)
  429. {
  430. return CompressEx(lpszSrc, dwSrcLen, lpszDest, dwDestLen, Z_DEFAULT_COMPRESSION, Z_DEFLATED, MAX_WBITS + 16);
  431. }
  432. int GZipUncompress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen)
  433. {
  434. return UncompressEx(lpszSrc, dwSrcLen, lpszDest, dwDestLen, MAX_WBITS + 32);
  435. }
  436. DWORD GZipGuessUncompressBound(const BYTE* lpszSrc, DWORD dwSrcLen)
  437. {
  438. if(dwSrcLen < 20 || *(USHORT*)lpszSrc != 0x8B1F)
  439. return 0;
  440. return *(DWORD*)(lpszSrc + dwSrcLen - 4);
  441. }
  442. DWORD GuessBase64EncodeBound(DWORD dwSrcLen)
  443. {
  444. return 4 * ((dwSrcLen + 2) / 3);
  445. }
  446. DWORD GuessBase64DecodeBound(const BYTE* lpszSrc, DWORD dwSrcLen)
  447. {
  448. if(dwSrcLen < 2)
  449. return 0;
  450. if(lpszSrc[dwSrcLen - 2] == '=')
  451. dwSrcLen -= 2;
  452. else if(lpszSrc[dwSrcLen - 1] == '=')
  453. --dwSrcLen;
  454. DWORD dwMod = dwSrcLen % 4;
  455. DWORD dwAdd = dwMod == 2 ? 1 : (dwMod == 3 ? 2 : 0);
  456. return 3 * (dwSrcLen / 4) + dwAdd;
  457. }
  458. int Base64Encode(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen)
  459. {
  460. static const BYTE CODES[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  461. DWORD dwRealLen = GuessBase64EncodeBound(dwSrcLen);
  462. if(lpszDest == nullptr || dwDestLen < dwRealLen)
  463. {
  464. dwDestLen = dwRealLen;
  465. return -5;
  466. }
  467. BYTE* p = lpszDest;
  468. DWORD leven = 3 * (dwSrcLen / 3);
  469. DWORD i = 0;
  470. for (; i < leven; i += 3)
  471. {
  472. *p++ = CODES[lpszSrc[0] >> 2];
  473. *p++ = CODES[((lpszSrc[0] & 3) << 4) + (lpszSrc[1] >> 4)];
  474. *p++ = CODES[((lpszSrc[1] & 0xf) << 2) + (lpszSrc[2] >> 6)];
  475. *p++ = CODES[lpszSrc[2] & 0x3f];
  476. lpszSrc += 3;
  477. }
  478. if(i < dwSrcLen)
  479. {
  480. BYTE a = lpszSrc[0];
  481. BYTE b = (i + 1 < dwSrcLen) ? lpszSrc[1] : 0;
  482. *p++ = CODES[a >> 2];
  483. *p++ = CODES[((a & 3) << 4) + (b >> 4)];
  484. *p++ = (i + 1 < dwSrcLen) ? CODES[((b & 0xf) << 2)] : '=';
  485. *p++ = '=';
  486. }
  487. ASSERT(dwRealLen == p - lpszDest);
  488. if(dwDestLen > dwRealLen)
  489. {
  490. *p = 0;
  491. dwDestLen = dwRealLen;
  492. }
  493. return 0;
  494. }
  495. int Base64Decode(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen)
  496. {
  497. static const BYTE MAP[256] =
  498. {
  499. 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 253, 255,
  500. 255, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  501. 255, 255, 255, 255, 255, 255, 255, 255, 253, 255, 255, 255,
  502. 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
  503. 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255,
  504. 255, 254, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6,
  505. 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
  506. 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255,
  507. 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
  508. 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
  509. 49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  510. 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  511. 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  512. 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  513. 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  514. 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  515. 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  516. 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  517. 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  518. 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  519. 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  520. 255, 255, 255, 255
  521. };
  522. DWORD dwRealLen = GuessBase64DecodeBound(lpszSrc, dwSrcLen);
  523. if(lpszDest == nullptr || dwDestLen < dwRealLen)
  524. {
  525. dwDestLen = dwRealLen;
  526. return -5;
  527. }
  528. BYTE c;
  529. int g = 3;
  530. DWORD i, x, y, z;
  531. for(i = x = y = z = 0; i < dwSrcLen || x != 0;)
  532. {
  533. c = i < dwSrcLen ? MAP[lpszSrc[i++]] : 254;
  534. if(c == 255) {dwDestLen = 0; return -3;}
  535. else if(c == 254) {c = 0; g--;}
  536. else if(c == 253) continue;
  537. z = (z << 6) | c;
  538. if(++x == 4)
  539. {
  540. lpszDest[y++] = (BYTE)((z >> 16) & 255);
  541. if (g > 1) lpszDest[y++] = (BYTE)((z >> 8) & 255);
  542. if (g > 2) lpszDest[y++] = (BYTE)(z & 255);
  543. x = z = 0;
  544. }
  545. }
  546. BOOL isOK = (y == dwRealLen);
  547. if(!isOK)
  548. dwDestLen = 0;
  549. else
  550. {
  551. if(dwDestLen > dwRealLen)
  552. {
  553. lpszDest[dwRealLen] = 0;
  554. dwDestLen = dwRealLen;
  555. }
  556. }
  557. return isOK ? 0 : -3;
  558. }
  559. DWORD GuessUrlEncodeBound(const BYTE* lpszSrc, DWORD dwSrcLen)
  560. {
  561. DWORD dwAdd = 0;
  562. for(DWORD i = 0; i < dwSrcLen; i++)
  563. {
  564. BYTE c = lpszSrc[i];
  565. if(!(isalnum(c) || c == ' ' || c == '.' || c == '-' || c == '_' || c == '*'))
  566. dwAdd += 2;
  567. }
  568. return dwSrcLen + dwAdd;
  569. }
  570. DWORD GuessUrlDecodeBound(const BYTE* lpszSrc, DWORD dwSrcLen)
  571. {
  572. DWORD dwPercent = 0;
  573. for(DWORD i = 0; i < dwSrcLen; i++)
  574. {
  575. if(lpszSrc[i] == '%')
  576. {
  577. ++dwPercent;
  578. i += 2;
  579. }
  580. }
  581. DWORD dwSub = dwPercent * 2;
  582. if(dwSrcLen < dwSub)
  583. return 0;
  584. return dwSrcLen - dwSub;
  585. }
  586. #define HEX_CHAR_TO_VALUE(c) (c <= '9' ? c - '0' : (c <= 'F' ? c - 'A' + 0x0A : c - 'a' + 0X0A))
  587. #define HEX_DOUBLE_CHAR_TO_VALUE(pc) (((HEX_CHAR_TO_VALUE(*(pc))) << 4) | (HEX_CHAR_TO_VALUE(*(pc + 1))))
  588. #define HEX_VALUE_TO_CHAR(n) (n <= 9 ? n + '0' : (n <= 'F' ? n + 'A' - 0X0A : n + 'a' - 0X0A))
  589. #define HEX_VALUE_TO_DOUBLE_CHAR(pc, n) {*(pc) = HEX_VALUE_TO_CHAR((n >> 4)); *((pc) + 1) = HEX_VALUE_TO_CHAR((n & 0X0F));}
  590. int UrlEncode(BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen)
  591. {
  592. if(lpszDest == nullptr || dwDestLen == 0)
  593. goto ERROR_DEST_LEN;
  594. BYTE c;
  595. DWORD j = 0;
  596. for(DWORD i = 0; i < dwSrcLen; i++)
  597. {
  598. if(j >= dwDestLen)
  599. goto ERROR_DEST_LEN;
  600. c = lpszSrc[i];
  601. if (isalnum(c) || c == '.' || c == '-' || c == '_' || c == '*')
  602. lpszDest[j++] = c;
  603. else if(c == ' ')
  604. lpszDest[j++] = '+';
  605. else
  606. {
  607. if(j + 3 >= dwDestLen)
  608. goto ERROR_DEST_LEN;
  609. lpszDest[j++] = '%';
  610. HEX_VALUE_TO_DOUBLE_CHAR(lpszDest + j, c);
  611. j += 2;
  612. }
  613. }
  614. if(dwDestLen > j)
  615. {
  616. lpszDest[j] = 0;
  617. dwDestLen = j;
  618. }
  619. return 0;
  620. ERROR_DEST_LEN:
  621. dwDestLen = GuessUrlEncodeBound(lpszSrc, dwSrcLen);
  622. return -5;
  623. }
  624. int UrlDecode(BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen)
  625. {
  626. if(lpszDest == nullptr || dwDestLen == 0)
  627. goto ERROR_DEST_LEN;
  628. char c;
  629. DWORD j = 0;
  630. for(DWORD i = 0; i < dwSrcLen; i++)
  631. {
  632. if(j >= dwDestLen)
  633. goto ERROR_DEST_LEN;
  634. c = lpszSrc[i];
  635. if(c == '+')
  636. lpszDest[j++] = ' ';
  637. else if(c != '%')
  638. lpszDest[j++] = c;
  639. else
  640. {
  641. if(i + 2 >= dwSrcLen)
  642. goto ERROR_SRC_DATA;
  643. lpszDest[j++] = HEX_DOUBLE_CHAR_TO_VALUE(lpszSrc + i + 1);
  644. i += 2;
  645. }
  646. }
  647. if(dwDestLen > j)
  648. {
  649. lpszDest[j] = 0;
  650. dwDestLen = j;
  651. }
  652. return 0;
  653. ERROR_SRC_DATA:
  654. dwDestLen = 0;
  655. return -3;
  656. ERROR_DEST_LEN:
  657. dwDestLen = GuessUrlDecodeBound(lpszSrc, dwSrcLen);
  658. return -5;
  659. }