in Release/src/http/client/http_client_winhttp.cpp [350:509]
bool process_buffer(uint8_t* buffer, size_t buffer_size, size_t& offset, size_t& length)
{
bool done = false;
size_t n = 0;
size_t l = 0;
while (n < buffer_size)
{
if (m_ignore)
{
if (m_expect_linefeed)
{
_ASSERTE(m_chunk_delim && m_trailer);
if (buffer[n] != '\n')
{
// The data stream does not conform to "chunked" encoding
throw http_exception(status_codes::BadRequest, "Transfer-Encoding malformed trailer");
}
// Look for further trailer fields or the end of the stream
m_expect_linefeed = false;
m_trailer = false;
}
else if (buffer[n] == '\r')
{
if (!m_trailer)
{
// We're at the end of the data we need to ignore
_ASSERTE(m_chunk_size || m_chunk_delim);
m_ignore = false;
m_chunk_delim = false; // this is only set if we're at the end of the message
} // else we're at the end of a trailer field
m_expect_linefeed = true;
}
else if (m_chunk_delim)
{
// We're processing (and ignoring) a trailer field
m_trailer = true;
}
}
else if (m_expect_linefeed)
{
// We've already seen a carriage return; confirm the linefeed
if (buffer[n] != '\n')
{
// The data stream does not conform to "chunked" encoding
throw http_exception(status_codes::BadRequest, "Transfer-Encoding malformed delimiter");
}
if (m_chunk_size)
{
if (!m_bytes_remaining)
{
// We're processing the terminating "empty" chunk; there's
// no data, we just need to confirm the final chunk delimiter,
// possibly ignoring a trailer part along the way
m_ignore = true;
m_chunk_delim = true;
} // else we move on to the chunk data itself
m_chunk_size = false;
}
else
{
// Now we move on to the next chunk size
_ASSERTE(!m_bytes_remaining);
if (m_chunk_delim)
{
// We expect a chunk size next
m_chunk_size = true;
}
else
{
// We just processed the end-of-input delimiter
done = true;
}
m_chunk_delim = false;
}
m_expect_linefeed = false;
}
else if (m_chunk_delim)
{
// We're processing a post-chunk delimiter
if (buffer[n] != '\r')
{
// The data stream does not conform to "chunked" encoding
throw http_exception(status_codes::BadRequest,
"Transfer-Encoding malformed chunk delimiter");
}
// We found the carriage return; look for the linefeed
m_expect_linefeed = true;
}
else if (m_chunk_size)
{
// We're processing an ASCII hexadecimal chunk size
if (buffer[n] >= 'a' && buffer[n] <= 'f')
{
m_bytes_remaining *= 16;
m_bytes_remaining += 10 + buffer[n] - 'a';
}
else if (buffer[n] >= 'A' && buffer[n] <= 'F')
{
m_bytes_remaining *= 16;
m_bytes_remaining += 10 + buffer[n] - 'A';
}
else if (buffer[n] >= '0' && buffer[n] <= '9')
{
m_bytes_remaining *= 16;
m_bytes_remaining += buffer[n] - '0';
}
else if (buffer[n] == '\r')
{
// We've reached the end of the size, and there's no chunk extension
m_expect_linefeed = true;
}
else if (buffer[n] == ';')
{
// We've reached the end of the size, and there's a chunk extension;
// we don't support extensions, so we ignore them per RFC
m_ignore = true;
}
else
{
// The data stream does not conform to "chunked" encoding
throw http_exception(status_codes::BadRequest,
"Transfer-Encoding malformed chunk size or extension");
}
}
else
{
if (m_bytes_remaining)
{
// We're at the offset of a chunk of consumable data; let the caller process it
l = (std::min)(m_bytes_remaining, buffer_size - n);
m_bytes_remaining -= l;
if (!m_bytes_remaining)
{
// We're moving on to the post-chunk delimiter
m_chunk_delim = true;
}
}
else
{
// We've previously processed the terminating empty chunk and its
// trailing delimiter; skip the entire buffer, and inform the caller
n = buffer_size;
done = true;
}
// Let the caller process the result
break;
}
// Move on to the next byte
n++;
}
offset = n;
length = l;
return buffer_size ? done : (!m_bytes_remaining && !m_chunk_size && !m_chunk_delim);
}