Files
smartservice_native/hdssd/huslib/HttpHandler.cpp
T
2026-05-20 03:08:08 +09:00

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;
}