diff --git a/CHANGELOG.md b/CHANGELOG.md index 26e9f157..502189c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +Version 274: + +* Fix leftovers in basic_parser corner case + +-------------------------------------------------------------------------------- + Version 273: * Squelch spurious websocket timer assert diff --git a/include/boost/beast/http/basic_parser.hpp b/include/boost/beast/http/basic_parser.hpp index 650e810a..023bdd7a 100644 --- a/include/boost/beast/http/basic_parser.hpp +++ b/include/boost/beast/http/basic_parser.hpp @@ -128,6 +128,8 @@ class basic_parser template friend class basic_parser; + friend class basic_parser_test; + protected: /// Default constructor basic_parser() = default; diff --git a/include/boost/beast/http/impl/basic_parser.hpp b/include/boost/beast/http/impl/basic_parser.hpp index e25be7ce..1303c5bd 100644 --- a/include/boost/beast/http/impl/basic_parser.hpp +++ b/include/boost/beast/http/impl/basic_parser.hpp @@ -51,9 +51,9 @@ put(ConstBufferSequence const& buffers, } // flatten net::buffer_copy(net::buffer( - buf_.get(), buf_len_), buffers); + buf_.get(), size), buffers); return put(net::const_buffer{ - buf_.get(), buf_len_}, ec); + buf_.get(), size}, ec); } template diff --git a/test/beast/http/basic_parser.cpp b/test/beast/http/basic_parser.cpp index 49f3476e..2cfa7b9d 100644 --- a/test/beast/http/basic_parser.cpp +++ b/test/beast/http/basic_parser.cpp @@ -1286,6 +1286,98 @@ public: //-------------------------------------------------------------------------- + // https://github.com/boostorg/beast/issues/1734 + + void + testIssue1734() + { + // Ensure more than one buffer, this is to avoid an optimized path in + // basic_parser::put(ConstBufferSequence const&,...) which avoids + // buffer flattening. + auto multibufs = [](multi_buffer::const_buffers_type buffers) { + std::vector bs; + for (auto b : buffers_range(buffers)) + bs.push_back(b); + while (std::distance(bs.begin(), bs.end()) < 2) { + bs.push_back({}); + } + return bs; + }; + + // Buffers must be bigger than max_stack_buffer to force flattening + // in basic_parser::put(ConstBufferSequence const&,...) + std::string first_chunk_data( + 2 * basic_parser::max_stack_buffer + 1, 'x'); + + std::string second_chunk_data_part1( + basic_parser::max_stack_buffer + 2, 'x'); + std::string second_chunk_data_part2( + basic_parser::max_stack_buffer + 1, 'x'); + + multi_buffer b; + parser p; + p.eager(true); + error_code ec; + std::size_t used; + + ostream(b) << + "HTTP/1.1 200 OK\r\n" + "Server: test\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n"; + + used = p.put(b.data(), ec); + b.consume(used); + + BEAST_EXPECT(net::buffer_size(b.data()) == 0); + BEAST_EXPECTS(!ec, ec.message()); + BEAST_EXPECT(!p.is_done()); + BEAST_EXPECT(p.is_header_done()); + + ostream(b) << + std::hex << + first_chunk_data.size() << "\r\n" << + first_chunk_data << "\r\n"; + + // First chunk + used = p.put(multibufs(b.data()), ec); + b.consume(used); + + BEAST_EXPECTS(ec == error::need_more, ec.message()); + BEAST_EXPECT(!p.is_done()); + + ostream(b) << + std::hex << + (second_chunk_data_part1.size() + + second_chunk_data_part2.size() ) << "\r\n" << + second_chunk_data_part1; + + // Second chunk, part 1 + used = p.put(multibufs(b.data()), ec); + b.consume(used); + + BEAST_EXPECTS(!ec, ec.message()); + BEAST_EXPECT(!p.is_done()); + + ostream(b) << + second_chunk_data_part2 << "\r\n" + << "0\r\n\r\n"; + + // Second chunk, part 2 + used = p.put(multibufs(b.data()), ec); + b.consume(used); + + BEAST_EXPECTS(!ec, ec.message()); // <-- Error: bad chunk + if(p.need_eof()) + { + p.put_eof(ec); + BEAST_EXPECTS(! ec, ec.message()); + } + BEAST_EXPECT(p.is_done()); + } + + //-------------------------------------------------------------------------- + void run() override {