From fc47880e5fd1b5821f30cc6a83c1f3afc88ebd90 Mon Sep 17 00:00:00 2001 From: Mohammad Nejati Date: Fri, 23 Feb 2024 12:12:21 +0000 Subject: [PATCH] fix: buffer preparation in serializer --- src/serializer.cpp | 89 ++++++++++++++++++++-------------------- test/unit/serializer.cpp | 48 +++++++++++++--------- 2 files changed, 72 insertions(+), 65 deletions(-) diff --git a/src/serializer.cpp b/src/serializer.cpp index c6571aa9..89c19ab4 100644 --- a/src/serializer.cpp +++ b/src/serializer.cpp @@ -138,59 +138,57 @@ prepare() -> if(st_ == style::source) { - if(! is_chunked_) + if(more_) { - auto rv = src_->read( - tmp0_.prepare( - tmp0_.capacity() - - tmp0_.size())); - tmp0_.commit(rv.bytes); - if(rv.ec.failed()) - return rv.ec; - more_ = ! rv.finished; - } - else - { - if((tmp0_.capacity() - - tmp0_.size()) > - chunked_overhead_) + if(! is_chunked_) { - auto dest = tmp0_.prepare(18); - write_chunk_header(dest, 0); - tmp0_.commit(18); auto rv = src_->read( - tmp0_.prepare( - tmp0_.capacity() - - 2 - // CRLF - 5 - // final chunk - tmp0_.size())); + tmp0_.prepare(tmp0_.capacity())); tmp0_.commit(rv.bytes); - // VFALCO FIXME! - //if(rv.bytes == 0) - //tmp0_.uncommit(18); // undo if(rv.ec.failed()) return rv.ec; - if(rv.bytes > 0) - { - // rewrite with correct size - write_chunk_header( - dest, rv.bytes); - // terminate chunk - tmp0_.commit( - buffers::buffer_copy( - tmp0_.prepare(2), - buffers::const_buffer( - "\r\n", 2))); - } - if(rv.finished) + more_ = ! rv.finished; + } + else + { + if(tmp0_.capacity() > chunked_overhead_) { - tmp0_.commit( - buffers::buffer_copy( - tmp0_.prepare(5), - buffers::const_buffer( - "0\r\n\r\n", 5))); + auto dest = tmp0_.prepare(18); + write_chunk_header(dest, 0); + tmp0_.commit(18); + auto rv = src_->read( + tmp0_.prepare( + tmp0_.capacity() - + 2 - // CRLF + 5));// final chunk + tmp0_.commit(rv.bytes); + // VFALCO FIXME! + //if(rv.bytes == 0) + //tmp0_.uncommit(18); // undo + if(rv.ec.failed()) + return rv.ec; + if(rv.bytes > 0) + { + // rewrite with correct size + write_chunk_header( + dest, rv.bytes); + // terminate chunk + tmp0_.commit( + buffers::buffer_copy( + tmp0_.prepare(2), + buffers::const_buffer( + "\r\n", 2))); + } + if(rv.finished) + { + tmp0_.commit( + buffers::buffer_copy( + tmp0_.prepare(5), + buffers::const_buffer( + "0\r\n\r\n", 5))); + } + more_ = ! rv.finished; } - more_ = ! rv.finished; } } @@ -474,6 +472,7 @@ start_source( hp_ = &out_[0]; *hp_ = { m.ph_->cbuf, m.ph_->size }; + more_ = true; } auto diff --git a/test/unit/serializer.cpp b/test/unit/serializer.cpp index 9b3e05e7..c29afdf1 100644 --- a/test/unit/serializer.cpp +++ b/test/unit/serializer.cpp @@ -33,8 +33,8 @@ struct serializer_test { struct test_source : source { - test_source() - : s_("12345") + test_source(core::string_view s) + : s_(s) { } @@ -81,11 +81,16 @@ struct serializer_test { std::string s; auto cbs = sr.prepare().value(); - s.resize(buffers::buffer_size(cbs)); + // we limit buffer consumption to complicate + // the serializer's internal buffer management + auto consumed = std::min( + std::size_t{256}, + buffers::buffer_size(cbs)); + s.resize(consumed); buffers::buffer_copy( buffers::mutable_buffer( - &s[0], s.size()), cbs); - sr.consume(s.size()); + &s[0], consumed), cbs); + sr.consume(consumed); return s; } @@ -118,10 +123,10 @@ struct serializer_test sr.start(res); sr.start(res, buffers::const_buffer{}); sr.start(res, buffers::mutable_buffer{}); - sr.start(res, test_source{}); + sr.start(res, test_source{"12345"}); sr.start(res, make_const(buffers::const_buffer{})); sr.start(res, make_const(buffers::mutable_buffer{})); - sr.start(res, make_const(test_source{})); + sr.start(res, make_const(test_source{"12345"})); serializer(65536); #ifdef BOOST_HTTP_PROTO_HAS_ZLIB @@ -197,7 +202,9 @@ struct serializer_test core::string_view expected) { response res(headers); - serializer sr; + // we limit the buffer size of the serializer, requiring + // it to make multiple calls to source::read + serializer sr(1024); sr.start(res, std::forward< Source>(src)); std::string s = read(sr); @@ -256,15 +263,14 @@ struct serializer_test check_src( "HTTP/1.1 200 OK\r\n" "Server: test\r\n" - "Content-Length: 5\r\n" + "Content-Length: 2048\r\n" "\r\n", - test_source{}, - //-------------------------- + test_source{std::string(2048, 'A')}, "HTTP/1.1 200 OK\r\n" "Server: test\r\n" - "Content-Length: 5\r\n" - "\r\n" - "12345"); + "Content-Length: 2048\r\n" + "\r\n" + + std::string(2048, 'A')); // source chunked check_src( @@ -272,14 +278,16 @@ struct serializer_test "Server: test\r\n" "Transfer-Encoding: chunked\r\n" "\r\n", - test_source{}, - //-------------------------- + test_source{std::string(1024, 'A')}, "HTTP/1.1 200 OK\r\n" "Server: test\r\n" "Transfer-Encoding: chunked\r\n" "\r\n" - "0000000000000005\r\n" - "12345" + "0000000000000367\r\n" + + std::string(0x367, 'A') + + "\r\n" + "0000000000000099\r\n" + + std::string(0x099, 'A') + "\r\n" "0\r\n\r\n"); } @@ -295,7 +303,7 @@ struct serializer_test "Expect: 100-continue\r\n" "Content-Length: 5\r\n" "\r\n"); - sr.start(req, test_source{}); + sr.start(req, test_source{"12345"}); std::string s; system::result< serializer::const_buffers_type> rv; @@ -375,7 +383,7 @@ struct serializer_test "\r\n"; serializer sr; response res(sv); - sr.start(res, test_source{}); + sr.start(res, test_source{"12345"}); auto s = read(sr); BOOST_TEST(s == "HTTP/1.1 200 OK\r\n"