#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 = ""; } ////////////////////////////////////////////////////////////////////////////// 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; }