diff --git a/include/boost/beast/http/basic_parser.hpp b/include/boost/beast/http/basic_parser.hpp index 7b890e03..ce22520d 100644 --- a/include/boost/beast/http/basic_parser.hpp +++ b/include/boost/beast/http/basic_parser.hpp @@ -110,7 +110,6 @@ class basic_parser static unsigned constexpr flagContentLength = 1<< 10; static unsigned constexpr flagChunked = 1<< 11; static unsigned constexpr flagUpgrade = 1<< 12; - static unsigned constexpr flagFinalChunk = 1<< 13; static constexpr std::uint64_t diff --git a/include/boost/beast/http/detail/basic_parser.hpp b/include/boost/beast/http/detail/basic_parser.hpp index 196d1c0a..5fa25333 100644 --- a/include/boost/beast/http/detail/basic_parser.hpp +++ b/include/boost/beast/http/detail/basic_parser.hpp @@ -44,6 +44,7 @@ struct basic_parser_base chunk_header0, chunk_header, chunk_body, + trailer_fields, complete }; @@ -108,11 +109,6 @@ struct basic_parser_base char const* it, char const* last, error_code& ec); - BOOST_BEAST_DECL - static - char const* - find_eom(char const* p, char const* last); - //-------------------------------------------------------------------------- BOOST_BEAST_DECL diff --git a/include/boost/beast/http/detail/basic_parser.ipp b/include/boost/beast/http/detail/basic_parser.ipp index 31d7cd40..117fd36a 100644 --- a/include/boost/beast/http/detail/basic_parser.ipp +++ b/include/boost/beast/http/detail/basic_parser.ipp @@ -201,40 +201,6 @@ parse_hex(char const*& it, std::uint64_t& v) return true; } -char const* -basic_parser_base:: -find_eom(char const* p, char const* last) -{ - for(;;) - { - if(p + 4 > last) - return nullptr; - if(p[3] != '\n') - { - if(p[3] == '\r') - ++p; - else - p += 4; - } - else if(p[2] != '\r') - { - p += 4; - } - else if(p[1] != '\n') - { - p += 2; - } - else if(p[0] != '\r') - { - p += 2; - } - else - { - return p + 4; - } - } -} - //-------------------------------------------------------------------------- char const* diff --git a/include/boost/beast/http/impl/basic_parser.ipp b/include/boost/beast/http/impl/basic_parser.ipp index 7f23265e..66671d69 100644 --- a/include/boost/beast/http/impl/basic_parser.ipp +++ b/include/boost/beast/http/impl/basic_parser.ipp @@ -164,6 +164,20 @@ loop: parse_chunk_header(p, n, ec); if(ec) goto done; + BOOST_ASSERT(! skip_); + if(state_ != state::trailer_fields) + break; + n = static_cast(p1 - p); + BOOST_FALLTHROUGH; + + case state::trailer_fields: + parse_fields(p, n, ec); + if(ec) + goto done; + this->on_finish_impl(ec); + if(ec) + goto done; + state_ = state::complete; break; case state::chunk_body: @@ -564,7 +578,7 @@ parse_body_to_eof(char const*& p, template void basic_parser:: -parse_chunk_header(char const*& p0, +parse_chunk_header(char const*& in, std::size_t n, error_code& ec) { /* @@ -581,101 +595,52 @@ parse_chunk_header(char const*& p0, chunk-ext-val = token / quoted-string */ - auto p = p0; + auto p = in; auto const pend = p + n; - char const* eol; - if(! (f_ & flagFinalChunk)) + if(n < skip_ + 2) { - if(n < skip_ + 2) - { - BOOST_BEAST_ASSIGN_EC(ec, error::need_more); - return; - } - if(f_ & flagExpectCRLF) - { - // Treat the last CRLF in a chunk as - // part of the next chunk, so p can - // be parsed in one call instead of two. - if(! parse_crlf(p)) - { - BOOST_BEAST_ASSIGN_EC(ec, error::bad_chunk); - return; - } - } - eol = find_eol(p0 + skip_, pend, ec); - if(ec) - return; - if(! eol) - { - BOOST_BEAST_ASSIGN_EC(ec, error::need_more); - skip_ = n - 1; - return; - } - skip_ = static_cast< - std::size_t>(eol - 2 - p0); - - std::uint64_t size; - if(! parse_hex(p, size)) + BOOST_BEAST_ASSIGN_EC(ec, error::need_more); + return; + } + if(f_ & flagExpectCRLF) + { + // Treat the last CRLF in a chunk as + // part of the next chunk, so p can + // be parsed in one call instead of two. + if(! parse_crlf(p)) { BOOST_BEAST_ASSIGN_EC(ec, error::bad_chunk); return; } - if(size != 0) + } + + auto const eol = find_eol(p + skip_, pend, ec); + if(ec) + return; + if(! eol) + { + BOOST_BEAST_ASSIGN_EC(ec, error::need_more); + if(p != pend) + skip_ = pend - p - 1; + return; + } + skip_ = static_cast(eol - p - 2); + + std::uint64_t size; + if(! parse_hex(p, size)) + { + BOOST_BEAST_ASSIGN_EC(ec, error::bad_chunk); + return; + } + if (body_limit_.has_value()) + { + if (size > *body_limit_) { - if (body_limit_.has_value()) - { - if (size > *body_limit_) - { - BOOST_BEAST_ASSIGN_EC(ec, error::body_limit); - return; - } - *body_limit_ -= size; - } - auto const start = p; - parse_chunk_extensions(p, pend, ec); - if(ec) - return; - if(p != eol -2 ) - { - BOOST_BEAST_ASSIGN_EC(ec, error::bad_chunk_extension); - return; - } - auto const ext = make_string(start, p); - this->on_chunk_header_impl(size, ext, ec); - if(ec) - return; - len_ = size; - skip_ = 2; - p0 = eol; - f_ |= flagExpectCRLF; - state_ = state::chunk_body; + BOOST_BEAST_ASSIGN_EC(ec, error::body_limit); return; } - - f_ |= flagFinalChunk; - } - else - { - BOOST_ASSERT(n >= 3); - if(f_ & flagExpectCRLF) - { - BOOST_ASSERT(n >= 5); - BOOST_VERIFY(parse_crlf(p)); - } - std::uint64_t size; - BOOST_VERIFY(parse_hex(p, size)); - eol = find_eol(p, pend, ec); - BOOST_ASSERT(! ec); - } - - auto eom = find_eom(p0 + skip_, pend); - if(! eom) - { - BOOST_ASSERT(n >= 3); - skip_ = n - 3; - BOOST_BEAST_ASSIGN_EC(ec, error::need_more); - return; + *body_limit_ -= size; } auto const start = p; @@ -688,20 +653,21 @@ parse_chunk_header(char const*& p0, return; } auto const ext = make_string(start, p); - this->on_chunk_header_impl(0, ext, ec); + this->on_chunk_header_impl(size, ext, ec); if(ec) return; - p = eol; - parse_fields(p, static_cast(eom - p), ec); - if(ec) - return; - BOOST_ASSERT(p == eom); - p0 = eom; - this->on_finish_impl(ec); - if(ec) + len_ = size; + skip_ = 0; + in = eol; + f_ |= flagExpectCRLF; + if(size != 0) + { + state_ = state::chunk_body; return; - state_ = state::complete; + } + state_ = state::trailer_fields; + header_limit_ += 2; // for the final chunk's CRLF } template diff --git a/test/beast/http/basic_parser.cpp b/test/beast/http/basic_parser.cpp index 95df1bf4..a3184209 100644 --- a/test/beast/http/basic_parser.cpp +++ b/test/beast/http/basic_parser.cpp @@ -859,6 +859,26 @@ public: BEAST_EXPECT(! p.is_done()); BEAST_EXPECTS(ec == error::header_limit, ec.message()); } + { + multi_buffer b; + ostream(b) << + "POST / HTTP/1.1\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n" + "0\r\n"; + error_code ec; + test_parser p; + p.header_limit(47); + p.eager(true); + b.consume(p.put(b.data(), ec)); + BEAST_EXPECTS(ec == error::need_more, ec.message()); + ostream(b) << + "field: value\r\n" + "\r\n"; + b.consume(p.put(b.data(), ec)); + BEAST_EXPECT(! p.is_done()); + BEAST_EXPECTS(ec == error::header_limit, ec.message()); + } { multi_buffer b; ostream(b) << diff --git a/test/beast/http/parser.cpp b/test/beast/http/parser.cpp index 3d26576b..af7c7cd9 100644 --- a/test/beast/http/parser.cpp +++ b/test/beast/http/parser.cpp @@ -470,7 +470,8 @@ public: ostream(b) << "0\r\n"; // needs an extra CRLF used = p.put(b.data(), ec); - BEAST_EXPECT(used == 0); + BEAST_EXPECT(used == 3); + b.consume(used); BEAST_EXPECT(ec == error::need_more); ostream(b) << "\r"; @@ -480,7 +481,7 @@ public: ostream(b) << "\n"; used = p.put(b.data(), ec); - BEAST_EXPECT(used == 5); + BEAST_EXPECT(used == 2); BEAST_EXPECT(!ec); BEAST_EXPECT(p.is_done()); }