// EnvelopeParser.cpp
// Implements the cEnvelopeParser class representing a parser for RFC-822 envelope headers, used both in HTTP and in MIME
#include "Globals.h"
#include "EnvelopeParser.h"
cEnvelopeParser::cEnvelopeParser(cCallbacks & a_Callbacks) :
m_Callbacks(a_Callbacks),
m_IsInHeaders(true)
{
}
size_t cEnvelopeParser::Parse(const char * a_Data, size_t a_Size)
{
if (!m_IsInHeaders)
{
return 0;
}
// Start searching 1 char from the end of the already received data, if available:
auto searchStart = m_IncomingData.size();
searchStart = (searchStart > 1) ? searchStart - 1 : 0;
m_IncomingData.append(a_Data, a_Size);
size_t idxCRLF = m_IncomingData.find("\r\n", searchStart);
if (idxCRLF == AString::npos)
{
// Not a complete line yet, all input consumed:
return a_Size;
}
// Parse as many lines as found:
size_t Last = 0;
do
{
if (idxCRLF == Last)
{
// This was the last line of the data. Finish whatever value has been cached and return:
NotifyLast();
m_IsInHeaders = false;
return a_Size - (m_IncomingData.size() - idxCRLF) + 2;
}
if (!ParseLine(m_IncomingData.c_str() + Last, idxCRLF - Last))
{
// An error has occurred
m_IsInHeaders = false;
return AString::npos;
}
Last = idxCRLF + 2;
idxCRLF = m_IncomingData.find("\r\n", idxCRLF + 2);
} while (idxCRLF != AString::npos);
m_IncomingData.erase(0, Last);
// Parsed all lines and still expecting more
return a_Size;
}
void cEnvelopeParser::Reset(void)
{
m_IsInHeaders = true;
m_IncomingData.clear();
m_LastKey.clear();
m_LastValue.clear();
}
void cEnvelopeParser::NotifyLast(void)
{
if (!m_LastKey.empty())
{
m_Callbacks.OnHeaderLine(m_LastKey, m_LastValue);
m_LastKey.clear();
}
m_LastValue.clear();
}
bool cEnvelopeParser::ParseLine(const char * a_Data, size_t a_Size)
{
ASSERT(a_Size > 0);
if (a_Data[0] <= ' ')
{
// This line is a continuation for the previous line
if (m_LastKey.empty())
{
return false;
}
// Append, including the whitespace in a_Data[0]
m_LastValue.append(a_Data, a_Size);
return true;
}
// This is a line with a new key:
NotifyLast();
for (size_t i = 0; i < a_Size; i++)
{
if (a_Data[i] == ':')
{
m_LastKey.assign(a_Data, i);
if (a_Size > i + 1)
{
m_LastValue.assign(a_Data + i + 2, a_Size - i - 2);
}
else
{
m_LastValue.clear();
}
return true;
}
} // for i - a_Data[]
// No colon was found, key-less header??
return false;
}