From 74d28c030d9a37e37e68985db53d68ab2ce56fd0 Mon Sep 17 00:00:00 2001 From: Mohammad Nejati Date: Thu, 6 Jun 2024 09:57:07 +0000 Subject: [PATCH] Partial writes don't cause bytes_transferred underflow Fixes #2880 --- include/boost/beast/websocket/impl/write.hpp | 9 ++++-- test/beast/websocket/write.cpp | 29 ++++++++++++++++++++ 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/include/boost/beast/websocket/impl/write.hpp b/include/boost/beast/websocket/impl/write.hpp index 6e75be79..493572e4 100644 --- a/include/boost/beast/websocket/impl/write.hpp +++ b/include/boost/beast/websocket/impl/write.hpp @@ -346,8 +346,8 @@ operator()( beast::detail::bind_continuation(std::move(*this))); } // VFALCO What about consuming the buffer on error? - bytes_transferred_ += - bytes_transferred - impl.wr_fb.size(); + if(bytes_transferred > impl.wr_fb.size()) + bytes_transferred_ += bytes_transferred - impl.wr_fb.size(); if(impl.check_stop_now(ec)) goto upcall; while(remain_ > 0) @@ -431,7 +431,10 @@ operator()( ), beast::detail::bind_continuation(std::move(*this))); } - n = bytes_transferred - impl.wr_fb.size(); + if(bytes_transferred > impl.wr_fb.size()) + n = bytes_transferred - impl.wr_fb.size(); + else + n = 0; bytes_transferred_ += n; if(impl.check_stop_now(ec)) goto upcall; diff --git a/test/beast/websocket/write.cpp b/test/beast/websocket/write.cpp index ebbc9191..84978969 100644 --- a/test/beast/websocket/write.cpp +++ b/test/beast/websocket/write.cpp @@ -806,6 +806,34 @@ public: BEAST_EXPECT(n1 < n0 + s.size()); } + void + testIssue2880() + { + for(auto fragment : {false, true}) + { + net::io_context ioc; + stream wsc{ioc}; + stream wss{ioc}; + wsc.next_layer().connect(wss.next_layer()); + wsc.async_handshake( + "localhost", "/", [](error_code){}); + wss.async_accept([](error_code){}); + ioc.run(); + ioc.restart(); + // limit the write size to be less than the header buffer + wsc.next_layer().write_size(3); + if(fragment) + wsc.write_buffer_bytes(8); + wsc.async_write(sbuf("*********"), + [&](error_code ec, std::size_t n) + { + BEAST_EXPECTS(ec, ec.message()); + BEAST_EXPECT(n == 0); + }); + wsc.next_layer().close(); + ioc.run(); + } + } #if BOOST_ASIO_HAS_CO_AWAIT void testAwaitableCompiles( @@ -835,6 +863,7 @@ public: testIssue227(); testIssue300(); testIssue1666(); + testIssue2880(); #if BOOST_ASIO_HAS_CO_AWAIT boost::ignore_unused(&write_test::testAwaitableCompiles); #endif