工具项目

HttpHelper.cpp 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  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 "HttpHelper.h"
  25. #ifdef _HTTP_SUPPORT
  26. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  27. CStringA& GetHttpVersionStr(EnHttpVersion enVersion, CStringA& strResult)
  28. {
  29. strResult.Format("HTTP/%d.%d", LOBYTE(enVersion), HIBYTE(enVersion));
  30. return strResult;
  31. }
  32. CStringA& AdjustRequestPath(BOOL bConnect, LPCSTR lpszPath, CStringA& strPath)
  33. {
  34. strPath = lpszPath;
  35. if(strPath.IsEmpty() || (!bConnect && strPath.GetAt(0) != HTTP_PATH_SEPARATOR_CHAR))
  36. strPath.Insert(0, HTTP_PATH_SEPARATOR_CHAR);
  37. return strPath;
  38. }
  39. LPCSTR GetHttpDefaultStatusCodeDesc(EnHttpStatusCode enCode)
  40. {
  41. switch(enCode)
  42. {
  43. case HSC_CONTINUE : return "Continue";
  44. case HSC_SWITCHING_PROTOCOLS : return "Switching Protocols";
  45. case HSC_PROCESSING : return "Processing";
  46. case HSC_OK : return "OK";
  47. case HSC_CREATED : return "Created";
  48. case HSC_ACCEPTED : return "Accepted";
  49. case HSC_NON_AUTHORITATIVE_INFORMATION : return "Non-Authoritative Information";
  50. case HSC_NO_CONTENT : return "No Content";
  51. case HSC_RESET_CONTENT : return "Reset Content";
  52. case HSC_PARTIAL_CONTENT : return "Partial Content";
  53. case HSC_MULTI_STATUS : return "Multi-Status";
  54. case HSC_ALREADY_REPORTED : return "Already Reported";
  55. case HSC_IM_USED : return "IM Used";
  56. case HSC_MULTIPLE_CHOICES : return "Multiple Choices";
  57. case HSC_MOVED_PERMANENTLY : return "Moved Permanently";
  58. case HSC_MOVED_TEMPORARILY : return "Move temporarily";
  59. case HSC_SEE_OTHER : return "See Other";
  60. case HSC_NOT_MODIFIED : return "Not Modified";
  61. case HSC_USE_PROXY : return "Use Proxy";
  62. case HSC_SWITCH_PROXY : return "Switch Proxy";
  63. case HSC_TEMPORARY_REDIRECT : return "Temporary Redirect";
  64. case HSC_PERMANENT_REDIRECT : return "Permanent Redirect";
  65. case HSC_BAD_REQUEST : return "Bad Request";
  66. case HSC_UNAUTHORIZED : return "Unauthorized";
  67. case HSC_PAYMENT_REQUIRED : return "Payment Required";
  68. case HSC_FORBIDDEN : return "Forbidden";
  69. case HSC_NOT_FOUND : return "Not Found";
  70. case HSC_METHOD_NOT_ALLOWED : return "Method Not Allowed";
  71. case HSC_NOT_ACCEPTABLE : return "Not Acceptable";
  72. case HSC_PROXY_AUTHENTICATION_REQUIRED : return "Proxy Authentication Required";
  73. case HSC_REQUEST_TIMEOUT : return "Request Timeout";
  74. case HSC_CONFLICT : return "Conflict";
  75. case HSC_GONE : return "Gone";
  76. case HSC_LENGTH_REQUIRED : return "Length Required";
  77. case HSC_PRECONDITION_FAILED : return "Precondition Failed";
  78. case HSC_REQUEST_ENTITY_TOO_LARGE : return "Request Entity Too Large";
  79. case HSC_REQUEST_URI_TOO_LONG : return "Request-URI Too Long";
  80. case HSC_UNSUPPORTED_MEDIA_TYPE : return "Unsupported Media Type";
  81. case HSC_REQUESTED_RANGE_NOT_SATISFIABLE: return "Requested Range Not Satisfiable";
  82. case HSC_EXPECTATION_FAILED : return "Expectation Failed";
  83. case HSC_MISDIRECTED_REQUEST : return "Misdirected Request";
  84. case HSC_UNPROCESSABLE_ENTITY : return "Unprocessable Entity";
  85. case HSC_LOCKED : return "Locked";
  86. case HSC_FAILED_DEPENDENCY : return "Failed Dependency";
  87. case HSC_UNORDERED_COLLECTION : return "Unordered Collection";
  88. case HSC_UPGRADE_REQUIRED : return "Upgrade Required";
  89. case HSC_PRECONDITION_REQUIRED : return "Precondition Required";
  90. case HSC_TOO_MANY_REQUESTS : return "Too Many Requests";
  91. case HSC_REQUEST_HEADER_FIELDS_TOO_LARGE: return "Request Header Fields Too Large";
  92. case HSC_UNAVAILABLE_FOR_LEGAL_REASONS : return "Unavailable For Legal Reasons";
  93. case HSC_RETRY_WITH : return "Retry With";
  94. case HSC_INTERNAL_SERVER_ERROR : return "Internal Server Error";
  95. case HSC_NOT_IMPLEMENTED : return "Not Implemented";
  96. case HSC_BAD_GATEWAY : return "Bad Gateway";
  97. case HSC_SERVICE_UNAVAILABLE : return "Service Unavailable";
  98. case HSC_GATEWAY_TIMEOUT : return "Gateway Timeout";
  99. case HSC_HTTP_VERSION_NOT_SUPPORTED : return "HTTP Version Not Supported";
  100. case HSC_VARIANT_ALSO_NEGOTIATES : return "Variant Also Negotiates";
  101. case HSC_INSUFFICIENT_STORAGE : return "Insufficient Storage";
  102. case HSC_LOOP_DETECTED : return "Loop Detected";
  103. case HSC_BANDWIDTH_LIMIT_EXCEEDED : return "Bandwidth Limit Exceeded";
  104. case HSC_NOT_EXTENDED : return "Not Extended";
  105. case HSC_NETWORK_AUTHENTICATION_REQUIRED: return "Network Authentication Required";
  106. case HSC_UNPARSEABLE_RESPONSE_HEADERS : return "Unparseable Response Headers";
  107. default : return "***";
  108. }
  109. }
  110. static inline CStringA& AppendHeader(LPCSTR lpszName, LPCSTR lpszValue, CStringA& strValue)
  111. {
  112. strValue.Append(lpszName);
  113. strValue.Append(HTTP_HEADER_SEPARATOR);
  114. strValue.Append(lpszValue);
  115. strValue.Append(HTTP_CRLF);
  116. return strValue;
  117. }
  118. void MakeRequestLine(LPCSTR lpszMethod, LPCSTR lpszPath, EnHttpVersion enVersion, CStringA& strValue)
  119. {
  120. ASSERT(lpszMethod);
  121. strValue.Format("%s %s HTTP/%d.%d%s", CStringA(lpszMethod).MakeUpper(), lpszPath, LOBYTE(enVersion), HIBYTE(enVersion), HTTP_CRLF);
  122. }
  123. void MakeStatusLine(EnHttpVersion enVersion, USHORT usStatusCode, LPCSTR lpszDesc, CStringA& strValue)
  124. {
  125. if(!lpszDesc) lpszDesc = ::GetHttpDefaultStatusCodeDesc((EnHttpStatusCode)usStatusCode);
  126. strValue.Format("HTTP/%d.%d %d %s%s", LOBYTE(enVersion), HIBYTE(enVersion), usStatusCode, lpszDesc, HTTP_CRLF);
  127. }
  128. void MakeHeaderLines(const THeader lpHeaders[], int iHeaderCount, const TCookieMap* pCookies, int iBodyLength, BOOL bRequest, int iConnFlag, LPCSTR lpszDefaultHost, USHORT usPort, CStringA& strValue)
  129. {
  130. unordered_set<LPCSTR, str_hash_func::hash, str_hash_func::equal_to> szHeaderNames;
  131. if(iHeaderCount > 0)
  132. {
  133. ASSERT(lpHeaders);
  134. for(int i = 0; i < iHeaderCount; i++)
  135. {
  136. const THeader& header = lpHeaders[i];
  137. ASSERT(!::IsStrEmptyA(header.name));
  138. if(!::IsStrEmptyA(header.name))
  139. {
  140. szHeaderNames.emplace(header.name);
  141. AppendHeader(header.name, header.value, strValue);
  142. }
  143. }
  144. }
  145. if( (!bRequest || iBodyLength > 0) &&
  146. (szHeaderNames.empty() ||
  147. (szHeaderNames.find(HTTP_HEADER_CONTENT_LENGTH) == szHeaderNames.end() &&
  148. szHeaderNames.find(HTTP_HEADER_TRANSFER_ENCODING) == szHeaderNames.end())))
  149. {
  150. char szBodyLength[16];
  151. _itoa(iBodyLength, szBodyLength, 10);
  152. AppendHeader(HTTP_HEADER_CONTENT_LENGTH, szBodyLength, strValue);
  153. }
  154. if( (iConnFlag == 0 || iConnFlag == 1) &&
  155. (szHeaderNames.empty() ||
  156. szHeaderNames.find(HTTP_HEADER_CONNECTION) == szHeaderNames.end() ))
  157. {
  158. LPCSTR lpszValue = iConnFlag == 0 ? HTTP_CONNECTION_CLOSE_VALUE : HTTP_CONNECTION_KEEPALIVE_VALUE;
  159. AppendHeader(HTTP_HEADER_CONNECTION, lpszValue, strValue);
  160. }
  161. if( bRequest && !::IsStrEmptyA(lpszDefaultHost) &&
  162. (szHeaderNames.empty() ||
  163. (szHeaderNames.find(HTTP_HEADER_HOST) == szHeaderNames.end()) ))
  164. {
  165. CStringA strHost(lpszDefaultHost);
  166. if(usPort != 0) strHost.AppendFormat(":%u", usPort);
  167. AppendHeader(HTTP_HEADER_HOST, strHost, strValue);
  168. }
  169. szHeaderNames.clear();
  170. if(pCookies != nullptr)
  171. {
  172. DWORD dwSize = (DWORD)pCookies->size();
  173. if(dwSize > 0)
  174. {
  175. strValue.Append(HTTP_HEADER_COOKIE);
  176. strValue.Append(HTTP_HEADER_SEPARATOR);
  177. DWORD dwIndex = 0;
  178. for(TCookieMapCI it = pCookies->begin(), end = pCookies->end(); it != end; ++it, ++dwIndex)
  179. {
  180. strValue.Append(it->first);
  181. strValue.AppendChar(COOKIE_KV_SEP_CHAR);
  182. strValue.Append(it->second);
  183. if(dwIndex < dwSize - 1)
  184. strValue.Append(HTTP_COOKIE_SEPARATOR);
  185. }
  186. strValue.Append(HTTP_CRLF);
  187. }
  188. }
  189. strValue.Append(HTTP_CRLF);
  190. }
  191. void MakeHttpPacket(const CStringA& strHeader, const BYTE* pBody, int iLength, WSABUF szBuffer[2])
  192. {
  193. ASSERT(pBody != nullptr || iLength == 0);
  194. szBuffer[0].buf = (LPSTR)(LPCSTR)strHeader;
  195. szBuffer[0].len = strHeader.GetLength();
  196. szBuffer[1].buf = (LPSTR)(LPCSTR)pBody;
  197. szBuffer[1].len = iLength;
  198. }
  199. 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])
  200. {
  201. ULONGLONG ullLength = (ULONGLONG)iLength;
  202. ASSERT(pData != nullptr || iLength == 0);
  203. ASSERT(ullBodyLen == 0 || ullBodyLen >= ullLength);
  204. if(ullBodyLen == 0)
  205. ullBodyLen = ullLength;
  206. else if(ullBodyLen < ullLength)
  207. {
  208. ::SetLastError(ERROR_INVALID_PARAMETER);
  209. return FALSE;
  210. }
  211. TBaseWSHeader bh(szHeader, TRUE);
  212. int iHeaderLen = HTTP_MIN_WS_HEADER_LEN;
  213. bh.set_fin(bFinal);
  214. bh.set_rsv(iReserved);
  215. bh.set_code(iOperationCode);
  216. bh.set_mask(lpszMask ? TRUE : FALSE);
  217. if(ullBodyLen < 126)
  218. bh.set_len((BYTE)ullBodyLen);
  219. else if(ullBodyLen <= 0xFFFF)
  220. {
  221. bh.set_len(126);
  222. bh.set_extlen((USHORT)ullBodyLen);
  223. iHeaderLen += 2;
  224. }
  225. else
  226. {
  227. bh.set_len(127);
  228. *(ULONGLONG*)(szHeader + HTTP_MIN_WS_HEADER_LEN) = ::HToN64(ullBodyLen);
  229. iHeaderLen += 8;
  230. }
  231. if(lpszMask)
  232. {
  233. memcpy(szHeader + iHeaderLen, lpszMask, 4);
  234. for(int i = 0; i < iLength; i++)
  235. pData[i] = pData[i] ^ lpszMask[i & 0x03];
  236. iHeaderLen += 4;
  237. }
  238. szBuffer[0].buf = (LPSTR)(LPCSTR)szHeader;
  239. szBuffer[0].len = iHeaderLen;
  240. szBuffer[1].buf = (LPSTR)(LPCSTR)pData;
  241. szBuffer[1].len = iLength;
  242. return TRUE;
  243. }
  244. BOOL ParseUrl(const CStringA& strUrl, BOOL& bHttps, CStringA& strHost, USHORT& usPort, CStringA& strPath)
  245. {
  246. int iSchemaLength = (int)strlen(HTTP_SCHEMA);
  247. if(_strnicmp(strUrl, HTTP_SCHEMA, iSchemaLength) == 0)
  248. bHttps = FALSE;
  249. else
  250. {
  251. iSchemaLength = (int)strlen(HTTPS_SCHEMA);
  252. if(_strnicmp(strUrl, HTTPS_SCHEMA, iSchemaLength) == 0)
  253. bHttps = TRUE;
  254. else
  255. return FALSE;
  256. }
  257. CStringA strFullHost;
  258. int i = strUrl.Find(HTTP_PATH_SEPARATOR_CHAR, iSchemaLength);
  259. if(i > 0)
  260. {
  261. strFullHost = strUrl.Mid(iSchemaLength, i - iSchemaLength);
  262. strPath = strUrl.Mid(i);
  263. }
  264. else
  265. {
  266. strFullHost = strUrl.Mid(iSchemaLength);
  267. strPath = HTTP_PATH_SEPARATOR;
  268. }
  269. if(strFullHost.IsEmpty())
  270. return FALSE;
  271. CStringA strPort;
  272. char c = strFullHost.GetAt(0);
  273. if(!::isalnum(c))
  274. {
  275. if(c != IPV6_ADDR_BEGIN_CHAR)
  276. return FALSE;
  277. else
  278. {
  279. i = strFullHost.ReverseFind(IPV6_ADDR_END_CHAR);
  280. if(i < 0)
  281. return FALSE;
  282. else
  283. {
  284. if(strFullHost.GetLength() > i + 1)
  285. {
  286. if(strFullHost.GetAt(i + 1) != PORT_SEPARATOR_CHAR)
  287. return FALSE;
  288. strPort = strFullHost.Mid(i + 2);
  289. if(strPort.IsEmpty())
  290. return FALSE;
  291. }
  292. strHost = strFullHost.Mid(1, i - 1);
  293. }
  294. }
  295. }
  296. else
  297. {
  298. i = strFullHost.Find(PORT_SEPARATOR_CHAR);
  299. if(i < 0)
  300. strHost = strFullHost;
  301. else
  302. {
  303. strPort = strFullHost.Mid(i + 1);
  304. if(strPort.IsEmpty())
  305. return FALSE;
  306. strHost = strFullHost.Mid(0, i);
  307. }
  308. }
  309. if(strPort.IsEmpty())
  310. usPort = bHttps ? HTTPS_DEFAULT_PORT : HTTP_DEFAULT_PORT;
  311. else
  312. usPort = (USHORT)::atoi(strPort);
  313. return TRUE;
  314. }
  315. int Compress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen)
  316. {
  317. return CompressEx(lpszSrc, dwSrcLen, lpszDest, dwDestLen);
  318. }
  319. int CompressEx(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen, int iLevel, int iMethod, int iWindowBits, int iMemLevel, int iStrategy)
  320. {
  321. z_stream stream;
  322. stream.next_in = (z_const Bytef*)lpszSrc;
  323. stream.avail_in = dwSrcLen;
  324. stream.next_out = lpszDest;
  325. stream.avail_out = dwDestLen;
  326. stream.zalloc = nullptr;
  327. stream.zfree = nullptr;
  328. stream.opaque = nullptr;
  329. int err = ::deflateInit2(&stream, iLevel, iMethod, iWindowBits, iMemLevel, iStrategy);
  330. if(err != Z_OK) return err;
  331. err = ::deflate(&stream, Z_FINISH);
  332. if(err != Z_STREAM_END)
  333. {
  334. ::deflateEnd(&stream);
  335. return err == Z_OK ? Z_BUF_ERROR : err;
  336. }
  337. if(dwDestLen > stream.total_out)
  338. {
  339. lpszDest[stream.total_out] = 0;
  340. dwDestLen = stream.total_out;
  341. }
  342. return ::deflateEnd(&stream);
  343. }
  344. int Uncompress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen)
  345. {
  346. return UncompressEx(lpszSrc, dwSrcLen, lpszDest, dwDestLen);
  347. }
  348. int UncompressEx(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen, int iWindowBits)
  349. {
  350. z_stream stream;
  351. stream.next_in = (z_const Bytef*)lpszSrc;
  352. stream.avail_in = (uInt)dwSrcLen;
  353. stream.next_out = lpszDest;
  354. stream.avail_out = dwDestLen;
  355. stream.zalloc = nullptr;
  356. stream.zfree = nullptr;
  357. int err = ::inflateInit2(&stream, iWindowBits);
  358. if(err != Z_OK) return err;
  359. err = ::inflate(&stream, Z_FINISH);
  360. if(err != Z_STREAM_END)
  361. {
  362. ::inflateEnd(&stream);
  363. return (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) ? Z_DATA_ERROR : err;
  364. }
  365. if(dwDestLen > stream.total_out)
  366. {
  367. lpszDest[stream.total_out] = 0;
  368. dwDestLen = stream.total_out;
  369. }
  370. return inflateEnd(&stream);
  371. }
  372. DWORD GuessCompressBound(DWORD dwSrcLen, BOOL bGZip)
  373. {
  374. DWORD dwBound = ::compressBound(dwSrcLen);
  375. if(bGZip) dwBound += 11;
  376. return dwBound;
  377. }
  378. int GZipCompress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen)
  379. {
  380. return CompressEx(lpszSrc, dwSrcLen, lpszDest, dwDestLen, Z_DEFAULT_COMPRESSION, Z_DEFLATED, MAX_WBITS + 16);
  381. }
  382. int GZipUncompress(const BYTE* lpszSrc, DWORD dwSrcLen, BYTE* lpszDest, DWORD& dwDestLen)
  383. {
  384. return UncompressEx(lpszSrc, dwSrcLen, lpszDest, dwDestLen, MAX_WBITS + 32);
  385. }
  386. DWORD GZipGuessUncompressBound(const BYTE* lpszSrc, DWORD dwSrcLen)
  387. {
  388. if(dwSrcLen < 20 || *(USHORT*)lpszSrc != 0x8B1F)
  389. return 0;
  390. return *(DWORD*)(lpszSrc + dwSrcLen - 4);
  391. }
  392. #endif