551 lines
13 KiB
C++
551 lines
13 KiB
C++
|
|
#include "huslib.h"
|
|
#include "huslibex.h"
|
|
|
|
|
|
bool HHttpHandler::UriCmp(const char * pszRequestUri, const char * pszPrefix)
|
|
{
|
|
const char * p1 = pszRequestUri;
|
|
const char * p2 = pszPrefix;
|
|
for (;;)
|
|
{
|
|
if (*p1 == '?' && *p2 == '\0')
|
|
break;
|
|
else if (strcmp(p1, "/") == 0 && *p2 == '\0')
|
|
break;
|
|
else if (*p1 != '\0' && *p2 == '*')
|
|
break;
|
|
else if (*p1 != *p2)
|
|
return false;
|
|
else if (*p1 == '\0' && *p2 == '\0')
|
|
break;
|
|
else if (*p1 == '\0' || *p2 == '\0')
|
|
return false;
|
|
|
|
p1++;
|
|
p2++;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool HHttpHandler::GetParamValue(const char * pszString, const char * pszKey, char * pszValue)
|
|
{
|
|
pszValue[0] = '\0';
|
|
|
|
char * pszKeyString = (char *)malloc(strlen(pszKey) + 2);
|
|
strcpy(pszKeyString, pszKey);
|
|
strcat(pszKeyString, "=");
|
|
|
|
const char * pszSearch = strstr(pszString, pszKeyString);
|
|
free(pszKeyString);
|
|
|
|
if (pszSearch == NULL)
|
|
return false;
|
|
|
|
int nIndex = (int)(pszSearch - pszString);
|
|
if (nIndex > 0 &&
|
|
pszString[nIndex - 1] != '?' &&
|
|
pszString[nIndex - 1] != '&' &&
|
|
#if 0
|
|
pszString[nIndex - 1] != ' ' && pszString[nIndex - 1] != '\\' &&
|
|
pszString[nIndex - 1] != '/' && pszString[nIndex - 1] != ':' &&
|
|
pszString[nIndex - 1] != '\"' && pszString[nIndex - 1] != '\'' &&
|
|
#endif
|
|
pszString[nIndex - 1] != ';')
|
|
{
|
|
return false;
|
|
}
|
|
|
|
int nStart = strlen(pszKey) + 1;
|
|
int nCount = strlen(pszSearch);
|
|
int i;
|
|
for (i = nStart; i < nCount; i++)
|
|
{
|
|
if (pszSearch[i] == '?' ||
|
|
pszSearch[i] == '&' ||
|
|
#if 0
|
|
pszSearch[i] == ' ' || pszSearch[i] == '\\' ||
|
|
pszSearch[i] == '/' || pszSearch[i] == ':' ||
|
|
pszSearch[i] == '\"' || pszSearch[i] == '\'' ||
|
|
#endif
|
|
pszSearch[i] == ';')
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (nStart == i)
|
|
{
|
|
pszValue[0] = '\0';
|
|
return true;
|
|
}
|
|
|
|
strncpy(pszValue, pszSearch + nStart, i - nStart);
|
|
pszValue[i - nStart] = '\0';
|
|
|
|
return true;
|
|
}
|
|
|
|
bool HHttpHandler::GetCookieValue(const char * pszCookie, const char * pszKeyName, char * pszValue)
|
|
{
|
|
*pszValue = '\0';
|
|
|
|
const char * pszOffset = stristr(pszCookie, pszKeyName);
|
|
if (pszOffset == NULL)
|
|
return false;
|
|
|
|
pszOffset += strlen(pszKeyName);
|
|
|
|
while (*pszOffset)
|
|
{
|
|
if (*pszOffset == '=')
|
|
{
|
|
pszOffset++;
|
|
break;
|
|
}
|
|
else if (*pszOffset == ' ' || *pszOffset == '\t')
|
|
;
|
|
else if (*pszOffset == '\0')
|
|
return true;
|
|
else
|
|
return false;
|
|
|
|
pszOffset++;
|
|
}
|
|
|
|
int i = 0;
|
|
while (*pszOffset)
|
|
{
|
|
if (*pszOffset == ';' || *pszOffset == '\r' || *pszOffset == '\n' || *pszOffset == '\0')
|
|
{
|
|
pszValue[i] = '\0';
|
|
return true;
|
|
}
|
|
else if (*pszOffset == '\t' || *pszOffset == ' ')
|
|
;
|
|
else
|
|
pszValue[i++] = *pszOffset;
|
|
|
|
pszOffset++;
|
|
}
|
|
|
|
pszValue[i] = '\0';
|
|
return true;
|
|
}
|
|
|
|
bool HHttpHandler::SetCookieValue(char * pszNewCookie, const char * pszCookie, const char * pszKeyName, const char * pszValue)
|
|
{
|
|
*pszNewCookie = '\0';
|
|
bool bIsSearch = false;
|
|
const char * pFirst = NULL;
|
|
const char * pSecond = NULL;
|
|
|
|
const char * pszOffset = pszCookie;
|
|
for (;;)
|
|
{
|
|
pszOffset = stristr(pszOffset, pszKeyName);
|
|
if (pszOffset == NULL)
|
|
break;
|
|
|
|
if (pszOffset != pszCookie)
|
|
{
|
|
const char * pTemp = pszOffset - 1;
|
|
if (*pTemp != ' ' && *pTemp != ';' && *pTemp != '\t')
|
|
{
|
|
pszOffset += strlen(pszKeyName);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
pszOffset += strlen(pszKeyName);
|
|
|
|
for (; *pszOffset; pszOffset++)
|
|
{
|
|
if (bIsSearch == false)
|
|
{
|
|
if (*pszOffset == '=')
|
|
{
|
|
bIsSearch = true;
|
|
pFirst = pszOffset + 1;
|
|
}
|
|
else if (*pszOffset != ' ' && *pszOffset != '\t' && *pszOffset != '\r' && *pszOffset != '\n')
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
if (*pszOffset == ';')
|
|
{
|
|
pSecond = pszOffset;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bIsSearch == true)
|
|
break;
|
|
}
|
|
|
|
if (bIsSearch == true)
|
|
{
|
|
int nCopySize = pFirst - pszCookie;
|
|
strncpy(pszNewCookie, pszCookie, nCopySize);
|
|
pszNewCookie[nCopySize] = '\0';
|
|
strcat(pszNewCookie, pszValue);
|
|
|
|
if (pSecond)
|
|
strcat(pszNewCookie, pSecond);
|
|
}
|
|
else
|
|
{
|
|
bool bAddSemiColon = true;
|
|
|
|
int nTotalLength = strlen(pszCookie);
|
|
for (int i = nTotalLength; i > 0; i--)
|
|
{
|
|
if (pszCookie[i - 1] == ';')
|
|
{
|
|
bAddSemiColon = false;
|
|
break;
|
|
}
|
|
else if (pszCookie[i - 1] == ' ' || pszCookie[i - 1] == '\t' ||
|
|
pszCookie[i - 1] == '\r' || pszCookie[i - 1] == '\n')
|
|
{
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
|
|
strcpy(pszNewCookie, pszCookie);
|
|
|
|
if (bAddSemiColon == true)
|
|
strcat(pszNewCookie, "; ");
|
|
|
|
strcat(pszNewCookie, pszKeyName);
|
|
strcat(pszNewCookie, "=");
|
|
strcat(pszNewCookie, pszValue);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
int HHttpHandler::RemoveCookieValue(char * pszCookie, const char * pszKeyName, int nIndex)
|
|
{
|
|
const char * pszOffset = pszCookie;
|
|
|
|
for (;;)
|
|
{
|
|
pszOffset = stristr(pszOffset, pszKeyName);
|
|
if (pszOffset == NULL || pszOffset[strlen(pszKeyName)] != '=')
|
|
return 0;
|
|
|
|
if (nIndex-- > 0)
|
|
{
|
|
pszOffset += 2;
|
|
continue;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
char * pszFront = (char *)pszOffset;
|
|
while (*pszOffset)
|
|
{
|
|
if (*pszOffset == ';' || *pszOffset == '\r' || *pszOffset == '\n' || *pszOffset == '\0')
|
|
break;
|
|
|
|
pszOffset++;
|
|
}
|
|
|
|
if (*pszOffset == ';')
|
|
pszOffset++;
|
|
|
|
if (*pszOffset == '\r' || *pszOffset == '\n' || *pszOffset == '\0')
|
|
{
|
|
if (pszCookie == pszFront) // empty cookie
|
|
{
|
|
*pszFront = '\0';
|
|
return 2;
|
|
}
|
|
|
|
*pszFront = '\0';
|
|
return 1;
|
|
}
|
|
|
|
if (*pszOffset == ' ')
|
|
pszOffset++;
|
|
|
|
char * pszTemp = (char *)malloc(strlen(pszOffset) + 1);
|
|
strcpy(pszTemp, pszOffset);
|
|
strcpy(pszFront, pszTemp);
|
|
free(pszTemp);
|
|
|
|
return 1;
|
|
}
|
|
|
|
int HHttpHandler::MakeCookie(char * pszSetCookie, const char * pszKeyName,
|
|
const char * pszKeyValue, const char * pszDomain, const char * pszPath, long nExpireMinute)
|
|
{
|
|
if (nExpireMinute < 0)
|
|
{
|
|
return sprintf(pszSetCookie, "%s=%s; expires=Thu, 01 Jan 1970 23:59:59 GMT%s%s%s%s",
|
|
pszKeyName, pszKeyValue,
|
|
pszDomain ? "; domain=" : "", pszDomain ? pszDomain : "",
|
|
pszPath ? "; path=" : "", pszPath ? pszPath : "");
|
|
}
|
|
else if (nExpireMinute == 0)
|
|
{
|
|
return sprintf(pszSetCookie, "%s=%s%s%s%s%s",
|
|
pszKeyName, pszKeyValue,
|
|
pszDomain ? "; domain=" : "", pszDomain ? pszDomain : "",
|
|
pszPath ? "; path=" : "", pszPath ? pszPath : "");
|
|
}
|
|
|
|
char szDateTime[32];
|
|
struct tm * tmTmp;
|
|
timeb tTimeb;
|
|
|
|
ftime(&tTimeb);
|
|
tTimeb.time += nExpireMinute;
|
|
tmTmp = localtime(&tTimeb.time);
|
|
strftime(szDateTime, 32, "%a, %d-%b-%Y %H:%M:%S", tmTmp);
|
|
|
|
return sprintf(pszSetCookie, "%s=%s; expires=%s GMT%s%s%s%s",
|
|
pszKeyName, pszKeyValue, szDateTime,
|
|
pszDomain ? "; domain=" : "", pszDomain ? pszDomain : "",
|
|
pszPath ? "; path=" : "", pszPath ? pszPath : "");
|
|
}
|
|
|
|
const char * HHttpHandler::EnumExtractCookie(const char * pszCookie, char ** ppName, char ** ppValue)
|
|
{
|
|
*ppName = NULL;
|
|
*ppValue = NULL;
|
|
|
|
if (pszCookie == NULL || pszCookie[0] == '\0')
|
|
return NULL;
|
|
|
|
const char * pOffset1 = strchr(pszCookie, ';');
|
|
const char * pOffset2 = strchr(pszCookie, '=');
|
|
if (pOffset1 == NULL && pOffset2 == NULL)
|
|
return NULL;
|
|
else if (pOffset2 == NULL || (pOffset1 && pOffset1 <= pOffset2 + 1))
|
|
return pOffset1 + 1;
|
|
|
|
int nNameSize = pOffset2 - pszCookie;
|
|
*ppName = (char *)malloc(nNameSize + 1);
|
|
StrNTrimCpy(*ppName, pszCookie, nNameSize);
|
|
|
|
int nValueSize;
|
|
if (pOffset1)
|
|
nValueSize = pOffset1 - (pOffset2 + 1);
|
|
else
|
|
nValueSize = strlen(pOffset2 + 1);
|
|
|
|
*ppValue = (char *)malloc(nValueSize + 1);
|
|
StrNTrimCpy(*ppValue, pOffset2 + 1, nValueSize);
|
|
|
|
if (pOffset1)
|
|
return pOffset1 + 1;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
int HHttpHandler::MakeResponse(char * pszResponse, const char * pszResponseType, const char * pszHtml)
|
|
{
|
|
HString strRear;
|
|
if (pszHtml)
|
|
{
|
|
strRear = "Content-Length: ";
|
|
strRear += strlen(pszHtml);
|
|
strRear += "\r\n\r\n";
|
|
strRear += pszHtml;
|
|
}
|
|
|
|
size_t nSize = sprintf(pszResponse, "HTTP/1.1 %s\n"
|
|
"Server: HUSS/2.0\r\n"
|
|
"X-UA-Compatible: IE=Edge\r\n"
|
|
"Content-Security-Policy: script-src 'self' 'unsafe-inline'; object-src 'self';\r\n"
|
|
"X-Content-Type-Options: nosniff\r\n"
|
|
"X-XSS-Protection: 1; mode=block\r\n"
|
|
"Connection: close\r\n"
|
|
"%s", pszResponseType, pszHtml ? strRear.psz() : "\r\n");
|
|
|
|
return nSize;
|
|
}
|
|
|
|
int HHttpHandler::Make200Header(char * pszResponse, const char * pszContentType, unsigned long nBodySize, const char * pszAddtionalHeaders)
|
|
{
|
|
size_t nSize = sprintf(pszResponse, "HTTP/1.1 200 OK\r\n"
|
|
"Server: HUSS/2.0\r\n"
|
|
"X-UA-Compatible: IE=Edge\r\n"
|
|
"Content-Security-Policy: script-src 'self' 'unsafe-inline'; object-src 'self';\r\n"
|
|
"X-Content-Type-Options: nosniff\r\n"
|
|
"X-XSS-Protection: 1; mode=block\r\n"
|
|
"%s%s"
|
|
"Content-Type: %s\r\n"
|
|
"Connection: close\r\n"
|
|
"Content-Length: %ld\r\n"
|
|
"\r\n", pszAddtionalHeaders && pszAddtionalHeaders[0] != '\0' ? pszAddtionalHeaders : "",
|
|
pszAddtionalHeaders && pszAddtionalHeaders[0] != '\0' ? "\r\n" : "",
|
|
pszContentType, nBodySize);
|
|
|
|
return nSize;
|
|
}
|
|
|
|
int HHttpHandler::Make302Response(char * pszResponse, const char * pszLocation, const char * pszSetCookie)
|
|
{
|
|
size_t nSize = sprintf(pszResponse, "HTTP/1.1 302 Moved Temporarily\r\n"
|
|
"Server: HUSS/2.0\r\n"
|
|
"Location: %s\r\n"
|
|
"Connection: close\r\n"
|
|
"%s%s%s"
|
|
"\r\n", pszLocation, pszSetCookie ? "Set-Cookie: " : "",
|
|
pszSetCookie ? pszSetCookie : "", pszSetCookie ? "\r\n" : "");
|
|
|
|
return nSize;
|
|
}
|
|
|
|
int HHttpHandler::Make307Response(char * pszResponse, const char * pszLocation, const char * pszSetCookie)
|
|
{
|
|
size_t nSize = sprintf(pszResponse, "HTTP/1.1 307 Temporary Redirect\r\n"
|
|
"Server: HUSS/2.0\r\n"
|
|
"Location: %s\r\n"
|
|
"Connection: close\r\n"
|
|
"%s%s%s"
|
|
"\r\n", pszLocation, pszSetCookie ? "Set-Cookie: " : "",
|
|
pszSetCookie ? pszSetCookie : "", pszSetCookie ? "\r\n" : "");
|
|
|
|
return nSize;
|
|
}
|
|
|
|
void HHttpHandler::MakeRedirectBody(HString * pstrBody, const char * pszUrl)
|
|
{
|
|
*pstrBody = "<html><head><META HTTP-EQUIV=Refresh CONTENT=\"0; URL='";
|
|
*pstrBody += pszUrl;
|
|
*pstrBody += "'\"></head></html>";
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
HHttpHandler::HHttpHandler()
|
|
{
|
|
m_pRecvStreamBuffer = new HStreamBuffer(g_nMaxHsHeaderSize + g_nSocketReceiveBlockSize);
|
|
m_pHttpParser = NULL;
|
|
m_nProtocolStatus = HHsParser::HP_NOT_HTTP_PACKET;
|
|
|
|
m_nRemainBodySize = 0;
|
|
}
|
|
|
|
HHttpHandler::~HHttpHandler()
|
|
{
|
|
if (m_pHttpParser)
|
|
delete m_pHttpParser;
|
|
|
|
delete m_pRecvStreamBuffer;
|
|
}
|
|
|
|
void HHttpHandler::InitParser()
|
|
{
|
|
if (m_pHttpParser)
|
|
{
|
|
m_pRecvStreamBuffer->Reset();
|
|
m_nProtocolStatus = HHsParser::HP_NOT_HTTP_PACKET;
|
|
delete m_pHttpParser;
|
|
m_pHttpParser = NULL;
|
|
}
|
|
}
|
|
|
|
void HHttpHandler::WriteStreamPacket(const char * pszDir, const char * pszPrefix)
|
|
{
|
|
HString strFileName = pszDir;
|
|
strFileName += pszPrefix;
|
|
char szDateTime[32];
|
|
GetDateTimeNum(szDateTime);
|
|
strFileName += szDateTime;
|
|
|
|
HFile file;
|
|
if (file.Open(strFileName, HFile::FMODE_CREATE | HFile::FMODE_WRONLY) == false)
|
|
return;
|
|
file.Write(m_pRecvStreamBuffer->Head(), m_pRecvStreamBuffer->StoredSize());
|
|
}
|
|
|
|
int HHttpHandler::OnReceivedFromTransport(const char * pData, int nSize)
|
|
{
|
|
//HLOGF(HLOG_WARNING, "TestLog, HttpHdler, inst = 0x%x, recv size = %d\n", this, nSize);
|
|
//HLOGD(HLOG_WARNING, pData, 40, true);
|
|
|
|
if (m_nProtocolStatus == HHsParser::HP_BODY_REMAIN_PACKET)
|
|
{
|
|
m_nRemainBodySize -= nSize;
|
|
|
|
int nResult = OnReceivedBodyStream(pData, nSize);
|
|
|
|
if (m_nRemainBodySize <= 0)
|
|
{
|
|
m_pRecvStreamBuffer->Reset();
|
|
m_nProtocolStatus = HHsParser::HP_NOT_HTTP_PACKET;
|
|
delete m_pHttpParser;
|
|
m_pHttpParser = NULL;
|
|
}
|
|
|
|
return nResult;
|
|
}
|
|
else if (m_nProtocolStatus == HHsParser::HP_BODYSIZE_UNKNOWN_PACKET)
|
|
{
|
|
return OnReceivedBodyStream(pData, nSize);
|
|
}
|
|
|
|
if (m_pRecvStreamBuffer->Store(pData, nSize) == false)
|
|
{
|
|
HLOGF(HLOG_ERROR, "[ERROR], HttpHdler, Failed to insert data, inst = 0x%x, buffer = %d, stored = %d, recv size = %d\n", this, m_pRecvStreamBuffer->Size(), m_pRecvStreamBuffer->StoredSize(), nSize);
|
|
return -1; // disconnect
|
|
}
|
|
|
|
// simply verify header
|
|
if (isalnum(m_pRecvStreamBuffer->Head()[0]) == 0)
|
|
{
|
|
HLOGF(HLOG_WARNING, "[WARN], HttpHdler, Invalid http protocol 1, inst = 0x%x, buffer = %d, stored = %d, recv size = %d\n", this, m_pRecvStreamBuffer->Size(), m_pRecvStreamBuffer->StoredSize(), nSize);
|
|
HLOGD(HLOG_WARNING, m_pRecvStreamBuffer->Head(), 20, false);
|
|
return -1; // disconnect
|
|
}
|
|
|
|
m_pRecvStreamBuffer->Head()[m_pRecvStreamBuffer->StoredSize()] = '\0'; // for using string operation
|
|
|
|
char * pszBodyPtr = HHsParser::SearchBodyPtr((char *)pData, nSize); //... search "\r\n\r\n" or "\n\n"
|
|
if (pszBodyPtr == NULL)
|
|
return 0; // continue received (remain header)
|
|
|
|
m_pHttpParser = new HHsParser("HTTP");
|
|
m_nProtocolStatus = m_pHttpParser->Parse(m_pRecvStreamBuffer->Head(), m_pRecvStreamBuffer->StoredSize());
|
|
|
|
if (m_nProtocolStatus == HHsParser::HP_NOT_HTTP_PACKET ||
|
|
m_nProtocolStatus == HHsParser::HP_PARAMETER_ERROR)
|
|
{
|
|
HLOGF(HLOG_WARNING, "[WARN], HttpHdler, Invalid http protocol 2, inst = 0x%x, buffer = %d, stored = %d, recv size = %d\n", this, m_pRecvStreamBuffer->Size(), m_pRecvStreamBuffer->StoredSize(), nSize);
|
|
HLOGD(HLOG_WARNING, m_pRecvStreamBuffer->Head(), 20, false);
|
|
return -1; // disconnect
|
|
}
|
|
else if (m_nProtocolStatus == HHsParser::HP_BODY_REMAIN_PACKET)
|
|
{
|
|
m_nRemainBodySize = m_pHttpParser->GetContentLength() - m_pHttpParser->GetBodySize();
|
|
return OnPacketProcessing(m_pHttpParser->GetBodyPtr(), m_pHttpParser->GetBodySize());
|
|
}
|
|
else if (m_nProtocolStatus == HHsParser::HP_BODYSIZE_UNKNOWN_PACKET)
|
|
{
|
|
return OnPacketProcessing(m_pHttpParser->GetBodyPtr(), m_pHttpParser->GetBodySize());
|
|
}
|
|
else if (m_nProtocolStatus == HHsParser::HP_COMPLETE_PACKET)
|
|
{
|
|
int nResult = OnPacketProcessing(m_pHttpParser->GetBodyPtr(), m_pHttpParser->GetBodySize());
|
|
|
|
m_pRecvStreamBuffer->Reset();
|
|
m_nProtocolStatus = HHsParser::HP_NOT_HTTP_PACKET;
|
|
delete m_pHttpParser;
|
|
m_pHttpParser = NULL;
|
|
|
|
return nResult;
|
|
}
|
|
|
|
return 0;
|
|
}
|