552 lines
12 KiB
C++
552 lines
12 KiB
C++
|
|
#include "stringex.h"
|
|
#include "hsparser.h"
|
|
#include <time.h>
|
|
#include <sys/timeb.h>
|
|
|
|
|
|
static char * SliceHeader(char * pszBuffer)
|
|
{
|
|
for (unsigned int i = 0; pszBuffer[i]; i++)
|
|
{
|
|
if (pszBuffer[i] == '\r' && pszBuffer[i + 1] == '\n')
|
|
{
|
|
pszBuffer[i] = '\0';
|
|
return (pszBuffer + i + 2);
|
|
}
|
|
else if (pszBuffer[i] == '\n')
|
|
{
|
|
pszBuffer[i] = '\0';
|
|
return (pszBuffer + i + 1);
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static char * SliceToken(char * pszLine, char cDelimiter)
|
|
{
|
|
for (unsigned int i = 0; pszLine[i]; i++)
|
|
{
|
|
if (pszLine[i] == cDelimiter)
|
|
{
|
|
pszLine[i] = '\0';
|
|
return (pszLine + i + 1);
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
char * HHsParser::SearchBodyPtr(char * pData, unsigned int nSize)
|
|
{
|
|
for (unsigned int i = 0; i < nSize; i++)
|
|
{
|
|
if (pData[i] == '\r' && pData[i + 1] == '\n' && pData[i + 2] == '\r' && pData[i + 3] == '\n')
|
|
return (pData + i + 4);
|
|
else if (pData[i] == '\n' && pData[i + 1] == '\n')
|
|
return (pData + i + 2);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
HHsHeaderElement::HHsHeaderElement(const char * pszName, bool bNameMewMemory, const char * pszValue, bool bValueNewMemory)
|
|
{
|
|
m_bNameNewMemory = bNameMewMemory;
|
|
m_bValueNewMemory = bValueNewMemory;
|
|
m_nNameLength = strlen(pszName);
|
|
m_nValueLength = strlen(pszValue);
|
|
|
|
if (bNameMewMemory)
|
|
{
|
|
m_pszName = (char *)malloc(m_nNameLength + 1);
|
|
strcpy(m_pszName, pszName);
|
|
}
|
|
else
|
|
{
|
|
m_pszName = (char *)pszName;
|
|
}
|
|
|
|
if (bValueNewMemory)
|
|
{
|
|
m_pszValue = (char *)malloc(m_nValueLength + 1);
|
|
strcpy(m_pszValue, pszValue);
|
|
}
|
|
else
|
|
{
|
|
m_pszValue = (char *)pszValue;
|
|
}
|
|
|
|
m_pNext = NULL;
|
|
}
|
|
|
|
HHsHeaderElement::~HHsHeaderElement()
|
|
{
|
|
if (m_bNameNewMemory)
|
|
free(m_pszName);
|
|
|
|
if (m_bValueNewMemory)
|
|
free(m_pszValue);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
HHsParser::HHsParser(const char * pszProtocolName)
|
|
{
|
|
strcpy(m_szProtocolName, pszProtocolName);
|
|
m_nProtocolNameLength = strlen(pszProtocolName);
|
|
|
|
m_pszMethod = NULL;
|
|
|
|
m_pszRequestUri = NULL;
|
|
m_bRequestUriNewMemory = false;
|
|
|
|
m_pszVersion = NULL;
|
|
m_nStatusCode = -1;
|
|
|
|
m_pszReasonPhrase = NULL;
|
|
m_bReasonPhraseNewMemory = false;
|
|
|
|
m_pElementHead = NULL;
|
|
m_pElementRear = NULL;
|
|
|
|
m_nHeaderSize = 0;
|
|
m_nContentLength = 0;
|
|
|
|
m_pBody = NULL;
|
|
m_bBodyNewMemory = false;
|
|
m_nBodySize = 0;
|
|
}
|
|
|
|
HHsParser::~HHsParser()
|
|
{
|
|
if (m_bRequestUriNewMemory)
|
|
free(m_pszRequestUri);
|
|
|
|
if (m_bReasonPhraseNewMemory)
|
|
free(m_pszReasonPhrase);
|
|
|
|
if (m_pElementHead)
|
|
{
|
|
HHsHeaderElement * pTemp;
|
|
HHsHeaderElement * pNext = m_pElementHead;
|
|
|
|
do
|
|
{
|
|
pTemp = pNext;
|
|
pNext = pNext->m_pNext;
|
|
|
|
delete pTemp;
|
|
} while (pNext != NULL);
|
|
}
|
|
|
|
if (m_bBodyNewMemory)
|
|
free(m_pBody);
|
|
}
|
|
|
|
void HHsParser::SetRequestUri(const char * pszRequestUri)
|
|
{
|
|
size_t oldLen = strlen(m_pszRequestUri);
|
|
size_t newLen = strlen(pszRequestUri);
|
|
|
|
if (newLen > oldLen)
|
|
{
|
|
if (m_bRequestUriNewMemory)
|
|
free(m_pszRequestUri);
|
|
else
|
|
m_bRequestUriNewMemory = true;
|
|
|
|
m_pszRequestUri = (char *)malloc(newLen + 1);
|
|
}
|
|
|
|
strcpy(m_pszRequestUri, pszRequestUri);
|
|
|
|
m_nHeaderSize += (newLen - oldLen);
|
|
}
|
|
|
|
void HHsParser::SetVersion(const char * pszVersion)
|
|
{
|
|
strcpy(m_pszVersion, pszVersion); //...
|
|
}
|
|
|
|
void HHsParser::SetReasonPhrase(const char * pszReasonPhrase)
|
|
{
|
|
size_t oldLen = strlen(m_pszReasonPhrase);
|
|
size_t newLen = strlen(pszReasonPhrase);
|
|
|
|
if (newLen > oldLen)
|
|
{
|
|
if (m_bReasonPhraseNewMemory)
|
|
free(m_pszReasonPhrase);
|
|
else
|
|
m_bReasonPhraseNewMemory = true;
|
|
|
|
m_pszReasonPhrase = (char *)malloc(newLen + 1);
|
|
}
|
|
|
|
strcpy(m_pszReasonPhrase, pszReasonPhrase);
|
|
|
|
m_nHeaderSize += (newLen - oldLen);
|
|
}
|
|
|
|
void HHsParser::SetBody(char * pData, unsigned int nSize)
|
|
{
|
|
if (nSize > m_nBodySize)
|
|
{
|
|
if (m_bBodyNewMemory)
|
|
free(m_pBody);
|
|
else
|
|
m_bBodyNewMemory = true;
|
|
|
|
m_pBody = (char *)malloc(nSize + 1);
|
|
}
|
|
|
|
memcpy(m_pBody, pData, nSize);
|
|
m_pBody[nSize] = '\0';
|
|
m_nBodySize = nSize;
|
|
}
|
|
|
|
HHsHeaderElement * HHsParser::GetHeaderElement(const char * pszHeaderName, int nIndex)
|
|
{
|
|
int i = 0;
|
|
for (HHsHeaderElement * pNext = m_pElementHead; pNext != NULL; pNext = pNext->m_pNext)
|
|
{
|
|
if (stricmp(pszHeaderName, pNext->m_pszName) == 0)
|
|
{
|
|
if (nIndex != i++)
|
|
continue;
|
|
|
|
return pNext;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
const char * HHsParser::GetHeaderValue(const char * pszHeaderName, int nIndex)
|
|
{
|
|
int i = 0;
|
|
for (HHsHeaderElement * pNext = m_pElementHead; pNext != NULL; pNext = pNext->m_pNext)
|
|
{
|
|
if (stricmp(pszHeaderName, pNext->m_pszName) == 0)
|
|
{
|
|
if (nIndex != i++)
|
|
continue;
|
|
|
|
return pNext->m_pszValue;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
bool HHsParser::AddHeader(const char * pszHeaderName, const char * pszHeaderValue)
|
|
{
|
|
HHsHeaderElement * pElement = new HHsHeaderElement(pszHeaderName, true, pszHeaderValue, true);
|
|
|
|
if (m_pElementHead == NULL)
|
|
m_pElementHead = pElement;
|
|
|
|
if (m_pElementRear)
|
|
m_pElementRear->m_pNext = pElement;
|
|
|
|
m_pElementRear = pElement;
|
|
|
|
m_nHeaderSize += (pElement->m_nNameLength + pElement->m_nValueLength + 4); // 4 = ": " + "\r\n"
|
|
|
|
return true;
|
|
}
|
|
|
|
bool HHsParser::SetHeader(const char * pszHeaderName, const char * pszHeaderValue, int nIndex)
|
|
{
|
|
HHsHeaderElement * pFindElement = GetHeaderElement(pszHeaderName, nIndex);
|
|
if (pFindElement)
|
|
{
|
|
size_t newLen = strlen(pszHeaderValue);
|
|
|
|
if (newLen > pFindElement->m_nValueLength)
|
|
{
|
|
if (pFindElement->m_bValueNewMemory)
|
|
free(pFindElement->m_pszValue);
|
|
else
|
|
pFindElement->m_bValueNewMemory = true;
|
|
|
|
pFindElement->m_pszValue = (char *)malloc(newLen + 1);
|
|
}
|
|
|
|
strcpy(pFindElement->m_pszValue, pszHeaderValue);
|
|
|
|
m_nHeaderSize += (newLen - pFindElement->m_nValueLength);
|
|
pFindElement->m_nValueLength = newLen;
|
|
|
|
return true;
|
|
}
|
|
|
|
return AddHeader(pszHeaderName, pszHeaderValue);
|
|
}
|
|
|
|
bool HHsParser::OrganizeHeader(char * pszHeaderName, char * pszHeaderValue)
|
|
{
|
|
HHsHeaderElement * pElement = new HHsHeaderElement(pszHeaderName, false, pszHeaderValue, false);
|
|
|
|
if (m_pElementHead == NULL)
|
|
m_pElementHead = pElement;
|
|
|
|
if (m_pElementRear)
|
|
m_pElementRear->m_pNext = pElement;
|
|
|
|
m_pElementRear = pElement;
|
|
|
|
return true;
|
|
}
|
|
|
|
void HHsParser::RemoveHeader(const char * pszHeaderName, const char * pszHeaderValue, int nIndex)
|
|
{
|
|
int i = 0;
|
|
HHsHeaderElement * pPrevNext = m_pElementHead;
|
|
for (HHsHeaderElement * pNext = m_pElementHead; pNext != NULL; pNext = pNext->m_pNext)
|
|
{
|
|
if (stricmp(pszHeaderName, pNext->m_pszName) == 0)
|
|
{
|
|
if (nIndex != i++)
|
|
continue;
|
|
|
|
if (pszHeaderValue && stricmp(pszHeaderValue, pNext->m_pszValue) != 0)
|
|
{
|
|
pPrevNext = pNext;
|
|
continue;
|
|
}
|
|
|
|
if (pNext == m_pElementHead)
|
|
{
|
|
m_pElementHead = pNext->m_pNext;
|
|
|
|
if (pNext == m_pElementRear)
|
|
m_pElementRear = m_pElementHead;
|
|
}
|
|
else if (pNext == m_pElementRear)
|
|
{
|
|
m_pElementRear = pPrevNext;
|
|
m_pElementRear->m_pNext = NULL;
|
|
}
|
|
else
|
|
{
|
|
pPrevNext->m_pNext = pNext->m_pNext;
|
|
}
|
|
|
|
m_nHeaderSize -= (pNext->m_nNameLength + pNext->m_nValueLength + 4); // 4 = ": " + "\rn"
|
|
delete pNext;
|
|
break;
|
|
}
|
|
|
|
pPrevNext = pNext;
|
|
}
|
|
}
|
|
|
|
size_t HHsParser::RefleshHeaderSize()
|
|
{
|
|
size_t nHeaderSize = 0;
|
|
|
|
if (m_pszMethod && m_pszRequestUri && m_pszVersion)
|
|
{
|
|
nHeaderSize += strlen(m_pszMethod) + 1;
|
|
nHeaderSize += strlen(m_pszRequestUri) + 1;
|
|
nHeaderSize += m_nProtocolNameLength + strlen(m_pszVersion) + 3; // GET / HTTP/1.1\r\n
|
|
}
|
|
else if (m_pszVersion && m_nStatusCode > 0 && m_pszReasonPhrase)
|
|
{
|
|
nHeaderSize += m_nProtocolNameLength + strlen(m_pszVersion) + 2; // HTTP/1.1 200 OK
|
|
|
|
int nNum = m_nStatusCode;
|
|
int nFigure = 0;
|
|
for (; nNum != 0; nFigure++)
|
|
nNum = nNum / 10;
|
|
|
|
nHeaderSize += nFigure + 1;
|
|
nHeaderSize += strlen(m_pszReasonPhrase) + 2;
|
|
}
|
|
else
|
|
return 0;
|
|
|
|
if (m_pElementHead == 0)
|
|
return 0;
|
|
|
|
for (HHsHeaderElement * pNext = m_pElementHead; pNext != NULL; pNext = pNext->m_pNext)
|
|
{
|
|
nHeaderSize += pNext->m_nNameLength + 2;
|
|
nHeaderSize += pNext->m_nValueLength + 2;
|
|
}
|
|
|
|
nHeaderSize += 2; // + \r\n
|
|
m_nHeaderSize = nHeaderSize;
|
|
|
|
return nHeaderSize;
|
|
}
|
|
|
|
int HHsParser::Parse(char * pData, unsigned int nSize, char * pBodyPtr)
|
|
{
|
|
if (pData == NULL || pData[0] == '\0')
|
|
return HP_PARAMETER_ERROR;
|
|
|
|
if (pBodyPtr == NULL)
|
|
{
|
|
pBodyPtr = SearchBodyPtr(pData, nSize);
|
|
if (pBodyPtr == NULL)
|
|
return HP_HEADER_REMAIN_PACKET;
|
|
}
|
|
m_nHeaderSize = pBodyPtr - pData;
|
|
|
|
char * pNextToken;
|
|
char * pNextLine = SliceHeader(pData);
|
|
if (strncmp(pData, m_szProtocolName, m_nProtocolNameLength) == 0)
|
|
{
|
|
// Response Start-Line (ex: HTTP/1.1 200 OK)
|
|
m_pszVersion = pData + m_nProtocolNameLength + 1;
|
|
if ((pNextToken = SliceToken(m_pszVersion, ' ')) == NULL)
|
|
return HP_NOT_HTTP_PACKET;
|
|
|
|
char * pszStatusCode = pNextToken;
|
|
if ((pNextToken = SliceToken(pszStatusCode, ' ')) == NULL)
|
|
return HP_NOT_HTTP_PACKET;
|
|
m_nStatusCode = atoi(pszStatusCode);
|
|
|
|
m_pszReasonPhrase = pNextToken;
|
|
}
|
|
else
|
|
{
|
|
// Request Start-Line
|
|
m_pszMethod = pData;
|
|
if ((pNextToken = SliceToken(m_pszMethod, ' ')) == NULL)
|
|
return HP_NOT_HTTP_PACKET;
|
|
|
|
//... check method name
|
|
|
|
m_pszRequestUri = pNextToken;
|
|
if ((pNextToken = SliceToken(m_pszRequestUri, ' ')) == NULL)
|
|
return HP_NOT_HTTP_PACKET;
|
|
|
|
m_pszVersion = pNextToken + m_nProtocolNameLength + 1;
|
|
}
|
|
|
|
bool bHasContentLength = false;
|
|
bool bIsChunkded = false;
|
|
bool bIsConnectionClose = false;
|
|
bool bHasContentType = false;
|
|
|
|
char * pOneLine;
|
|
char * pszHeaderName;
|
|
do
|
|
{
|
|
pOneLine = pNextLine;
|
|
if ((pNextLine = SliceHeader(pOneLine)) == NULL)
|
|
break;
|
|
|
|
pszHeaderName = pOneLine;
|
|
if ((pNextToken = SliceToken(pszHeaderName, ':')) == NULL)
|
|
return HP_NOT_HTTP_PACKET;
|
|
|
|
for (int i = 0; ; i++) // front trim
|
|
{
|
|
if (*pNextToken == ' ') pNextToken++;
|
|
else break;
|
|
}
|
|
|
|
if (stricmp(pszHeaderName, "Content-Length") == 0)
|
|
{
|
|
m_nContentLength = atol(pNextToken);
|
|
bHasContentLength = true;
|
|
}
|
|
else if (stricmp(pszHeaderName, "Transfer-Encoding") == 0)
|
|
{
|
|
if (stricmp(pNextToken, "chunked") == 0)
|
|
bIsChunkded = true;
|
|
}
|
|
else if (stricmp(pszHeaderName, "Connection") == 0)
|
|
{
|
|
if (stricmp(pNextToken, "close") == 0)
|
|
bIsConnectionClose = true;
|
|
}
|
|
else if (stricmp(pszHeaderName, "Content-Type") == 0)
|
|
bHasContentType = true;
|
|
|
|
OrganizeHeader(pszHeaderName, pNextToken);
|
|
} while (*pNextLine != '\r' && *pNextLine != '\n'); // header end
|
|
|
|
if (m_nHeaderSize == nSize && m_nContentLength == 0)
|
|
{
|
|
if (bIsChunkded || (bHasContentType && m_pszMethod == NULL && bHasContentLength == false && bIsConnectionClose))
|
|
return HP_BODYSIZE_UNKNOWN_PACKET;
|
|
else
|
|
return HP_COMPLETE_PACKET;
|
|
}
|
|
|
|
unsigned int nRemainSize = nSize - m_nHeaderSize;
|
|
if (m_nContentLength == 0 || m_nContentLength >= nRemainSize)
|
|
m_nBodySize = nRemainSize;
|
|
else
|
|
m_nBodySize = m_nContentLength;
|
|
|
|
if (m_nBodySize > 0)
|
|
{
|
|
m_pBody = pBodyPtr;
|
|
m_pBody[m_nBodySize] = '\0';
|
|
}
|
|
|
|
if (m_nContentLength == 0)
|
|
return HP_BODYSIZE_UNKNOWN_PACKET;
|
|
else if (m_nContentLength == m_nBodySize)
|
|
return HP_COMPLETE_PACKET;
|
|
else if (m_nContentLength > m_nBodySize)
|
|
return HP_BODY_REMAIN_PACKET;
|
|
|
|
return HP_BODYSIZE_UNKNOWN_PACKET;
|
|
}
|
|
|
|
bool HHsParser::ToString(char * pBuffer, bool bOnlyHeader)
|
|
{
|
|
if (m_pszVersion == NULL || m_pElementHead == NULL)
|
|
{
|
|
pBuffer[0] = '\0';
|
|
return false;
|
|
}
|
|
|
|
if (m_pszMethod)
|
|
sprintf(pBuffer, "%s %s %s/%s\r\n", m_pszMethod, m_pszRequestUri, m_szProtocolName, m_pszVersion);
|
|
else
|
|
sprintf(pBuffer, "%s/%s %d %s\r\n", m_szProtocolName, m_pszVersion, m_nStatusCode, m_pszReasonPhrase);
|
|
|
|
size_t nTempSize = strlen(pBuffer);
|
|
|
|
char * pBufferOffset = pBuffer + nTempSize;
|
|
for (HHsHeaderElement * pNext = m_pElementHead; pNext != NULL; pNext = pNext->m_pNext)
|
|
{
|
|
strcpy(pBufferOffset, pNext->m_pszName);
|
|
pBufferOffset += pNext->m_nNameLength;
|
|
|
|
strcpy(pBufferOffset, ": ");
|
|
pBufferOffset += 2;
|
|
|
|
strcpy(pBufferOffset, pNext->m_pszValue);
|
|
pBufferOffset += pNext->m_nValueLength;
|
|
|
|
strcpy(pBufferOffset, "\r\n");
|
|
pBufferOffset += 2;
|
|
}
|
|
|
|
strcpy(pBufferOffset, "\r\n");
|
|
|
|
if (bOnlyHeader == false && m_pBody)
|
|
{
|
|
pBufferOffset += 2;
|
|
memcpy(pBufferOffset, m_pBody, m_nBodySize);
|
|
pBufferOffset[m_nBodySize] = '\0';
|
|
}
|
|
|
|
return true;
|
|
}
|