#include "HttpHead.h" const unsigned int asciiTableData[256] = { 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x104, 0x104, 0x004, 0x104, 0x104, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x140, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x459, 0x459, 0x459, 0x459, 0x459, 0x459, 0x459, 0x459, 0x459, 0x459, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x653, 0x653, 0x653, 0x653, 0x653, 0x653, 0x253, 0x253, 0x253, 0x253, 0x253, 0x253, 0x253, 0x253, 0x253, 0x253, 0x253, 0x253, 0x253, 0x253, 0x253, 0x253, 0x253, 0x253, 0x253, 0x253, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x473, 0x473, 0x473, 0x473, 0x473, 0x473, 0x073, 0x073, 0x073, 0x073, 0x073, 0x073, 0x073, 0x073, 0x073, 0x073, 0x073, 0x073, 0x073, 0x073, 0x073, 0x073, 0x073, 0x073, 0x073, 0x073, 0x0d0, 0x0d0, 0x0d0, 0x0d0, 0x004 /* the upper 128 are all zeroes */ }; static void TrimString(std::string& str) { std::string str1; bool add1 = false; std::string::const_iterator iter1; for (iter1 = str.begin(); iter1 != str.end(); ++iter1) { int c = (HGByte)(*iter1); if (!add1) { if (!isspace(c)) { str1.push_back(c); add1 = true; } } else { str1.push_back(c); } } if (str1.empty()) { str.clear(); return; } std::string str2; bool add2 = false; std::string::const_reverse_iterator iter2; for (iter2 = str1.rbegin(); iter2 != str1.rend(); ++iter2) { int c = (HGByte)(*iter2); if (!add2) { if (!isspace(c)) { str2.push_back(c); add2 = true; } } else { str2.push_back(c); } } if (str2.empty()) { str.clear(); return; } str = std::string(str2.rbegin(), str2.rend()); } HttpHead::HttpHead() { } HttpHead::~HttpHead() { } bool HttpHead::Parse(const std::string& head) { AnalysisHead(head, m_requestMethod, m_requestURIPath, m_requestURIQueryInfos, m_requestURIFragment, m_requestHttpVersion, m_headInfos); return true; } void HttpHead::Clear() { m_requestMethod.clear(); m_requestURIPath.clear(); m_requestURIQueryInfos.clear(); m_requestURIFragment.clear(); m_requestHttpVersion.clear(); m_headInfos.clear(); } std::string HttpHead::GetRequestMethod() const { return m_requestMethod; } std::string HttpHead::GetRequestURIPath() const { return m_requestURIPath; } HttpPairs HttpHead::GetRequestURIQueryInfos() const { return m_requestURIQueryInfos; } std::string HttpHead::GetRequestURIFragment() const { return m_requestURIFragment; } std::string HttpHead::GetRequestHttpVersion() const { return m_requestHttpVersion; } HttpPairs HttpHead::GetHeadInfos() const { return m_headInfos; } int HttpHead::GetContentLength() const { int len = 0; for (int i = 0; i < (int)m_headInfos.size(); ++i) { #if defined(HG_CMP_MSC) if (0 == _stricmp("Content-Length", m_headInfos[i].first.c_str())) #else if (0 == strcasecmp("Content-Length", m_headInfos[i].first.c_str())) #endif { len = atoi(m_headInfos[i].second.c_str()); break; } } return len; } std::string HttpHead::GetContentType() const { std::string type; for (int i = 0; i < (int)m_headInfos.size(); ++i) { #if defined(HG_CMP_MSC) if (0 == _stricmp("Content-Type", m_headInfos[i].first.c_str())) #else if (0 == strcasecmp("Content-Type", m_headInfos[i].first.c_str())) #endif { type = m_headInfos[i].second.c_str(); break; } } return type; } std::string HttpHead::GetValue(const HttpPairs& infos, const std::string& key) { std::string value; for (int i = 0; i < (int)infos.size(); ++i) { if (key == infos[i].first) { value = infos[i].second; break; } } return value; } void HttpHead::AnalysisURIQuery(const std::string& query, HttpPairs& queryInfos) { std::vector queryList; char* p = new char[query.size() + 1]; strcpy(p, query.c_str()); char* pStr = strtok(p, "&"); if (NULL != pStr) queryList.push_back(pStr); while (1) { pStr = strtok(NULL, "&"); if (NULL == pStr) break; queryList.push_back(pStr); } delete[] p; queryInfos.clear(); for (int i = 0; i < (int)queryList.size(); ++i) { p = new char[queryList[i].size() + 1]; strcpy(p, queryList[i].c_str()); std::pair pr; pStr = strtok(p, "="); if (NULL != pStr) pr.first = AnalyURIString(pStr); pStr = strtok(NULL, "="); if (NULL != pStr) pr.second = AnalyURIString(pStr); queryInfos.push_back(pr); delete[] p; } } void HttpHead::AnalysisURI(const std::string& uri, std::string& path, HttpPairs& queryInfos, std::string& fragment) { size_t pathPos = uri.find('/'); size_t queryPos = uri.find('?'); size_t fragmentPos = uri.find('#'); path.clear(); if (std::string::npos != pathPos) { size_t count = std::string::npos; if (queryPos != std::string::npos) { assert(queryPos > pathPos); count = queryPos - pathPos; } else if (fragmentPos != std::string::npos) { assert(fragmentPos > pathPos); count = fragmentPos - pathPos; } path = AnalyURIString(uri.substr(pathPos, count)); } queryInfos.clear(); if (std::string::npos != queryPos) { size_t count = std::string::npos; if (fragmentPos != std::string::npos) { assert(fragmentPos > queryPos); count = fragmentPos - queryPos; } std::string query = uri.substr(queryPos + 1, count - 1); AnalysisURIQuery(query, queryInfos); } fragment.clear(); if (std::string::npos != fragmentPos) { fragment = AnalyURIString(uri.substr(fragmentPos + 1)); } } void HttpHead::AnalysisHead(const std::string& head, std::string& requestMethod, std::string& requestURIPath, HttpPairs& requestURIQueryInfos, std::string& requestURIFragment, std::string& httpVersion, HttpPairs& headInfos) { requestMethod.clear(); requestURIPath.clear(); requestURIQueryInfos.clear(); requestURIFragment.clear(); httpVersion.clear(); headInfos.clear(); std::vector headList; char* p = new char[head.size() + 1]; strcpy(p, head.c_str()); char* pStr = strtok(p, "\r\n"); if (NULL != pStr) headList.push_back(pStr); while (1) { pStr = strtok(NULL, "\r\n"); if (NULL == pStr) break; headList.push_back(pStr); } delete[] p; if (headList.size() < 1) { return; } std::string requestURI; // 解析请求行 p = new char[headList[0].size() + 1]; strcpy(p, headList[0].c_str()); pStr = strtok(p, " "); if (NULL != pStr) requestMethod = pStr; pStr = strtok(NULL, " "); if (NULL != pStr) requestURI = pStr; pStr = strtok(NULL, " "); if (NULL != pStr) httpVersion = pStr; delete[] p; // 解析URI AnalysisURI(requestURI, requestURIPath, requestURIQueryInfos, requestURIFragment); // 解析请求头 for (int i = 1; i < (int)headList.size(); ++i) { p = new char[headList[i].size() + 1]; strcpy(p, headList[i].c_str()); std::pair pr; pStr = strtok(p, ":"); if (NULL != pStr) pr.first = pStr; pStr = strtok(NULL, ":"); if (NULL != pStr) pr.second = pStr; TrimString(pr.first); TrimString(pr.second); headInfos.push_back(pr); delete[] p; } } /*判断ascii码是否是数字0-9*/ static bool asciiIsDigit(char c) { /*字符的ascii码&8 结果为0-127,则是数字*/ return asciiTableData[(unsigned char)c & (1 << 3)]; } static int asciiDigitValue(char c) { if (asciiIsDigit(c)) return c - '0'; return -1; } static int asciiXdigitValue(char c) { //printf("-->%c\n",c); if (c >= 'A' && c <= 'F') return c - 'A' + 10;//(A B C D E F)->(10 11 12 13 14 15) if (c >= 'a' && c <= 'f') return c - 'a' + 10; return asciiDigitValue(c);//('0'...'9')->(0...9) } static int unescapeCharacter(const char* scanner) { int first = asciiXdigitValue(scanner[0]); if (first < 0) return -1; int second = asciiXdigitValue(scanner[1]); if (second < 0) return -1; return (first << 4) | second; //== (first*16 | second) == (first*16 + second) } static char* unescapeUriString(const char* uriString, bool asciiEscape) { if (NULL == uriString) return NULL; int strLen = (int)strlen(uriString); char* result = (char*)malloc(strLen + 1);//可推测解码后的长度<=原长度 char* out = result; const char* in, * end; for (in = uriString, end = in + strLen; in < end; ++in) { int c = *in; //遇到了'%'才去解析 if ('%' == c) { if (in + 3 > end) break; //获取%后2个字符的解码值 c = unescapeCharacter(in + 1); if (c <= 0) break; if (asciiEscape && c <= 0x7F) break; in += 2;//一般的格式为%后加两个ascii码字符 } *out++ = c;//存储转义结果 } *out = '\0'; if (in != end) { free(result); return NULL; } return result; } std::string HttpHead::AnalyURIString(const std::string& str) { std::string ret; char* decodeStr = unescapeUriString(str.c_str(), false); if (NULL != decodeStr) { ret = decodeStr; free(decodeStr); } return ret; }