mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-07-17 18:43:07 +02:00
HTTPServer: compose and send replies to connected clients
Sockets-touching bits copied and adapted from `CConnman::SocketSendData()` Testing this requires adding a new feature to the SocketTestingSetup, returning the DynSock I/O pipes from the mock socket so the received data can be checked. Co-authored-by: Vasil Dimov <vd@FreeBSD.org>
This commit is contained in:
@@ -489,6 +489,10 @@ BOOST_AUTO_TEST_CASE(http_request_tests)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(http_server_socket_tests)
|
||||
{
|
||||
// Hard code the timestamp for the Date header in the HTTP response
|
||||
// Wed Dec 11 00:47:09 2024 UTC
|
||||
SetMockTime(1733878029);
|
||||
|
||||
// Prepare a request handler that just stores received requests so we can examine them.
|
||||
// Mutex is required to prevent a race between this test's main thread and the server's I/O loop.
|
||||
Mutex requests_mutex;
|
||||
@@ -524,8 +528,10 @@ BOOST_AUTO_TEST_CASE(http_server_socket_tests)
|
||||
// No connections yet
|
||||
BOOST_CHECK_EQUAL(server.GetConnectionsCount(), 0);
|
||||
|
||||
// Create a mock client with pre-loaded request data and add it to the local CreateSock queue
|
||||
ConnectClient(std::as_bytes(std::span(full_request)));
|
||||
// Create a mock client with pre-loaded request data and add it to the local CreateSock queue.
|
||||
// Keep a handle for the mock client's send and receive pipes so we can examine
|
||||
// the data it "receives".
|
||||
std::shared_ptr<DynSock::Pipes> mock_client_socket_pipes{ConnectClient(std::as_bytes(std::span(full_request)))};
|
||||
|
||||
// Wait up to a minute to find and connect the client in the I/O loop
|
||||
int attempts{6000};
|
||||
@@ -553,6 +559,9 @@ BOOST_AUTO_TEST_CASE(http_server_socket_tests)
|
||||
client = requests.front()->m_client;
|
||||
BOOST_CHECK_EQUAL(client->m_origin, "5.5.5.5:6789");
|
||||
|
||||
// Respond to request
|
||||
requests.front()->WriteReply(HTTP_OK, "874140\n");
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -560,6 +569,31 @@ BOOST_AUTO_TEST_CASE(http_server_socket_tests)
|
||||
BOOST_REQUIRE(--attempts > 0);
|
||||
}
|
||||
|
||||
// Check the sent response from the mock client at the other end of the mock socket
|
||||
std::string actual;
|
||||
// Wait up to one minute for all the bytes to appear in the "send" pipe.
|
||||
char buf[0x10000] = {};
|
||||
attempts = 6000;
|
||||
while (attempts > 0)
|
||||
{
|
||||
ssize_t bytes_read = mock_client_socket_pipes->send.GetBytes(buf, sizeof(buf), 0);
|
||||
if (bytes_read > 0) {
|
||||
actual.append(buf, bytes_read);
|
||||
if (actual.length() == 146) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
std::this_thread::sleep_for(10ms);
|
||||
--attempts;
|
||||
}
|
||||
BOOST_CHECK(actual.starts_with("HTTP/1.1 200 OK\r\n"));
|
||||
BOOST_CHECK(actual.ends_with("\r\n874140\n"));
|
||||
// Headers can be sorted in any order, and will be, since we use unordered_map
|
||||
BOOST_CHECK(actual.find("Connection: close\r\n") != std::string::npos);
|
||||
BOOST_CHECK(actual.find("Content-Length: 7\r\n") != std::string::npos);
|
||||
BOOST_CHECK(actual.find("Content-Type: text/html; charset=ISO-8859-1\r\n") != std::string::npos);
|
||||
BOOST_CHECK(actual.find("Date: Wed, 11 Dec 2024 00:47:09 GMT\r\n") != std::string::npos);
|
||||
|
||||
// Stop the I/O thread before modifying m_connected. CloseConnection() is a
|
||||
// temporary test-only API that is not thread-safe against GenerateWaitSockets(),
|
||||
// which iterates m_connected on the I/O thread.
|
||||
|
||||
Reference in New Issue
Block a user