diff options
| author | j-berman <justinberman@protonmail.com> | 2026-01-08 16:10:36 -0800 |
|---|---|---|
| committer | j-berman <justinberman@protonmail.com> | 2026-02-02 10:22:41 -0800 |
| commit | ee9e4a49baae0319f6cab543979e221f251339a3 (patch) | |
| tree | d6ddeb5dd24015a62d242f26b799d6ea646ebee4 /tests | |
| parent | 4ce39e0c144a092415e31876bcb3cdaa43481272 (diff) | |
| download | monzero-core-ee9e4a49baae0319f6cab543979e221f251339a3.tar.gz monzero-core-ee9e4a49baae0319f6cab543979e221f251339a3.tar.xz monzero-core-ee9e4a49baae0319f6cab543979e221f251339a3.zip | |
p2p: connection patches
- Make sure the server sends a complete response when the client
includes the "Connection: close" header.
- Make sure the server terminates in `m_strand` to avoid
concurrent socket closure and ops processing.
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/unit_tests/epee_http_server.cpp | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/tests/unit_tests/epee_http_server.cpp b/tests/unit_tests/epee_http_server.cpp index 1d3b60d54..f2eb9e41e 100644 --- a/tests/unit_tests/epee_http_server.cpp +++ b/tests/unit_tests/epee_http_server.cpp @@ -198,3 +198,71 @@ TEST(http_server, private_ip_limit) failed |= bool(error); EXPECT_TRUE(failed); } + +TEST(http_server, read_then_close) +{ + namespace http = boost::beast::http; + + http_server server{}; + server.dummy_size = 200000; + server.init(nullptr, "8080"); + server.run(2, false); // need at least 2 threads to trigger issues + + bool failed_read = false; + bool closed_all_connections = true; + for (std::size_t j = 0; j < 1000; ++j) + { + boost::system::error_code error{}; + boost::asio::io_context context{}; + boost::asio::ip::tcp::socket stream{context}; + stream.connect( + boost::asio::ip::tcp::endpoint{ + boost::asio::ip::make_address("127.0.0.1"), 8080 + }, + error + ); + EXPECT_FALSE(bool(error)); + + http::request<http::string_body> req{http::verb::get, "/dummy", 11}; + req.set(http::field::host, "127.0.0.1"); + req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING); + req.set(http::field::connection, "close"); // tell server to close connection after sending all data to the client + req.body() = make_payload(); + req.prepare_payload(); + + dummy::response payload{}; + boost::beast::flat_buffer buffer; + http::response_parser<http::basic_string_body<char>> parser; + parser.body_limit(server.dummy_size + 1024); + + http::write(stream, req, error); + EXPECT_FALSE(bool(error)); + + http::read(stream, buffer, parser, error); + + // If the read fails, continue the loop still just to make sure the server can handle it + failed_read |= bool(error); + if (failed_read) + continue; + failed_read |= !(parser.is_done()); + if (failed_read) + continue; + const auto res = parser.release(); + failed_read |= res.result_int() != 200u + || !(epee::serialization::load_t_from_binary(payload, res.body())) + || (server.dummy_size != std::count(payload.payload.begin(), payload.payload.end(), 'f')); + + // See if the server closes the connection after handling the resp + char buf[1]; + stream.read_some(boost::asio::buffer(buf), error); + closed_all_connections &= error == boost::asio::error::eof; + } + + // The client should have been able to read all data sent by the server across all requests + EXPECT_FALSE(failed_read); + + // The server should have closed all connections + EXPECT_TRUE(closed_all_connections); + + server.send_stop_signal(); +} |
