code_app/sdk/webservice/HttpHead.cpp

438 lines
8.7 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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<std::string> 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 <std::string, std::string> 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<std::string> 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 <std::string, std::string> 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;
}