bool process_buffer()

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);
            }