438 lines
8.7 KiB
C++
438 lines
8.7 KiB
C++
#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;
|
||
} |