#include "stringex.h" #include "hsparser.h" #include #include 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; }