HttpHelper.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. /*
  2. * Copyright: JessMA Open Source (ldcsaa@gmail.com)
  3. *
  4. * Version : 3.6.1
  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. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  33. CStringA& GetHttpVersionStr(EnHttpVersion enVersion, CStringA& strResult)
  34. {
  35. strResult.Format("HTTP/%d.%d", LOBYTE(enVersion), HIBYTE(enVersion));
  36. return strResult;
  37. }
  38. LPCSTR GetHttpDefaultStatusCodeDesc(EnHttpStatusCode enCode)
  39. {
  40. switch(enCode)
  41. {
  42. case HSC_CONTINUE : return "Continue";
  43. case HSC_SWITCHING_PROTOCOLS : return "Switching Protocols";
  44. case HSC_PROCESSING : return "Processing";
  45. case HSC_OK : return "OK";
  46. case HSC_CREATED : return "Created";
  47. case HSC_ACCEPTED : return "Accepted";
  48. case HSC_NON_AUTHORITATIVE_INFORMATION : return "Non-Authoritative Information";
  49. case HSC_NO_CONTENT : return "No Content";
  50. case HSC_RESET_CONTENT : return "Reset Content";
  51. case HSC_PARTIAL_CONTENT : return "Partial Content";
  52. case HSC_MULTI_STATUS : return "Multi-Status";
  53. case HSC_MULTIPLE_CHOICES : return "Multiple Choices";
  54. case HSC_MOVED_PERMANENTLY : return "Moved Permanently";
  55. case HSC_MOVED_TEMPORARILY : return "Move temporarily";
  56. case HSC_SEE_OTHER : return "See Other";
  57. case HSC_NOT_MODIFIED : return "Not Modified";
  58. case HSC_USE_PROXY : return "Use Proxy";
  59. case HSC_SWITCH_PROXY : return "Switch Proxy";
  60. case HSC_TEMPORARY_REDIRECT : return "Temporary Redirect";
  61. case HSC_BAD_REQUEST : return "Bad Request";
  62. case HSC_UNAUTHORIZED : return "Unauthorized";
  63. case HSC_PAYMENT_REQUIRED : return "Payment Required";
  64. case HSC_FORBIDDEN : return "Forbidden";
  65. case HSC_NOT_FOUND : return "Not Found";
  66. case HSC_METHOD_NOT_ALLOWED : return "Method Not Allowed";
  67. case HSC_NOT_ACCEPTABLE : return "Not Acceptable";
  68. case HSC_PROXY_AUTHENTICATION_REQUIRED : return "Proxy Authentication Required";
  69. case HSC_REQUEST_TIMEOUT : return "Request Timeout";
  70. case HSC_CONFLICT : return "Conflict";
  71. case HSC_GONE : return "Gone";
  72. case HSC_LENGTH_REQUIRED : return "Length Required";
  73. case HSC_PRECONDITION_FAILED : return "Precondition Failed";
  74. case HSC_REQUEST_ENTITY_TOO_LARGE : return "Request Entity Too Large";
  75. case HSC_REQUEST_URI_TOO_LONG : return "Request-URI Too Long";
  76. case HSC_UNSUPPORTED_MEDIA_TYPE : return "Unsupported Media Type";
  77. case HSC_REQUESTED_RANGE_NOT_SATISFIABLE: return "Requested Range Not Satisfiable";
  78. case HSC_EXPECTATION_FAILED : return "Expectation Failed";
  79. case HSC_UNPROCESSABLE_ENTITY : return "Unprocessable Entity";
  80. case HSC_LOCKED : return "Locked";
  81. case HSC_FAILED_DEPENDENCY : return "Failed Dependency";
  82. case HSC_UNORDERED_COLLECTION : return "Unordered Collection";
  83. case HSC_UPGRADE_REQUIRED : return "Upgrade Required";
  84. case HSC_RETRY_WITH : return "Retry With";
  85. case HSC_INTERNAL_SERVER_ERROR : return "Internal Server Error";
  86. case HSC_NOT_IMPLEMENTED : return "Not Implemented";
  87. case HSC_BAD_GATEWAY : return "Bad Gateway";
  88. case HSC_SERVICE_UNAVAILABLE : return "Service Unavailable";
  89. case HSC_GATEWAY_TIMEOUT : return "Gateway Timeout";
  90. case HSC_HTTP_VERSION_NOT_SUPPORTED : return "HTTP Version Not Supported";
  91. case HSC_VARIANT_ALSO_NEGOTIATES : return "Variant Also Negotiates";
  92. case HSC_INSUFFICIENT_STORAGE : return "Insufficient Storage";
  93. case HSC_BANDWIDTH_LIMIT_EXCEEDED : return "Bandwidth Limit Exceeded";
  94. case HSC_NOT_EXTENDED : return "Not Extended";
  95. case HSC_UNPARSEABLE_RESPONSE_HEADERS : return "Unparseable Response Headers";
  96. default : return "***";
  97. }
  98. }
  99. static inline CStringA& AppendHeader(LPCSTR lpszName, LPCSTR lpszValue, CStringA& strValue)
  100. {
  101. strValue.Append(lpszName);
  102. strValue.Append(HEADER_SEPARATOR);
  103. strValue.Append(lpszValue);
  104. strValue.Append(CRLF);
  105. return strValue;
  106. }
  107. void MakeRequestLine(LPCSTR lpszMethod, LPCSTR lpszPath, EnHttpVersion enVersion, CStringA& strValue)
  108. {
  109. ASSERT(lpszMethod && lpszPath);
  110. strValue.Format("%s %s HTTP/%d.%d%s", lpszMethod, lpszPath, LOBYTE(enVersion), HIBYTE(enVersion), CRLF);
  111. }
  112. void MakeStatusLine(EnHttpVersion enVersion, USHORT usStatusCode, LPCSTR lpszDesc, CStringA& strValue)
  113. {
  114. if(!lpszDesc) lpszDesc = ::GetHttpDefaultStatusCodeDesc((EnHttpStatusCode)usStatusCode);
  115. strValue.Format("HTTP/%d.%d %d %s%s", LOBYTE(enVersion), HIBYTE(enVersion), usStatusCode, lpszDesc, CRLF);
  116. }
  117. void MakeHeaderLines(const THeader lpHeaders[], int iHeaderCount, TCookieMap* pCookies, int iBodyLength, BOOL bRequest, CStringA& strValue)
  118. {
  119. unordered_set<LPCSTR, str_hash_func::hash, str_hash_func::equal_to> szHeaderNames;
  120. if(iHeaderCount > 0)
  121. {
  122. ASSERT(lpHeaders);
  123. for(int i = 0; i < iHeaderCount; i++)
  124. {
  125. const THeader& header = lpHeaders[i];
  126. if(header.name != nullptr)
  127. {
  128. ASSERT(strlen(header.name) > 0);
  129. szHeaderNames.emplace(header.name);
  130. AppendHeader(header.name, header.value, strValue);
  131. }
  132. }
  133. }
  134. if( (!bRequest || iBodyLength > 0) &&
  135. (szHeaderNames.empty() ||
  136. (szHeaderNames.find(CONTENT_LENGTH_HEADER) == szHeaderNames.end() &&
  137. szHeaderNames.find(TRANSFER_ENCODING_HEADER) == szHeaderNames.end())))
  138. {
  139. CStringA strLength;
  140. strLength.Format("%i", iBodyLength);
  141. AppendHeader(CONTENT_LENGTH_HEADER, strLength, strValue);
  142. }
  143. szHeaderNames.clear();
  144. if(pCookies != nullptr)
  145. {
  146. DWORD dwSize = (DWORD)pCookies->size();
  147. if(dwSize > 0)
  148. {
  149. strValue.Append(COOKIE_HEADER);
  150. strValue.Append(HEADER_SEPARATOR);
  151. DWORD dwIndex = 0;
  152. for(TCookieMapCI it = pCookies->begin(), end = pCookies->end(); it != end; ++it, ++dwIndex)
  153. {
  154. strValue.Append(it->first);
  155. strValue.AppendChar(NV_SEPARATOR_CHAR);
  156. strValue.Append(it->second);
  157. if(dwIndex < dwSize - 1)
  158. strValue.Append(COOKIE_TOKENIZE);
  159. }
  160. strValue.Append(CRLF);
  161. }
  162. }
  163. strValue.Append(CRLF);
  164. }
  165. void MakeHttpPacket(const CStringA& strHeader, const BYTE* pBody, int iLength, WSABUF szBuffer[2])
  166. {
  167. ASSERT(pBody != nullptr || iLength == 0);
  168. szBuffer[0].buf = (LPSTR)(LPCSTR)strHeader;
  169. szBuffer[0].len = strHeader.GetLength();
  170. szBuffer[1].buf = (LPSTR)(LPCSTR)pBody;
  171. szBuffer[1].len = iLength;
  172. }