#include "config.hpp" #include "connection.hpp" #include "http_handler.hpp" #include "server.hpp" #include #include #include TEST_CASE("HTTP pipelined POST requests race condition") { weaseldb::Config config; HttpHandler handler(config); auto server = Server::create(config, handler, {}); int fd = server->create_local_connection(); auto runThread = std::thread{[&]() { server->run(); }}; // Create a POST request with JSON body that requires parsing std::string json_body = R"({ "request_id": "test-123", "leader_id": "leader-1", "read_version": 1, "preconditions": [], "operations": [{"write": {"key": "dGVzdA==", "value": "dmFsdWU="}}] })"; std::string first_post = "POST /v1/commit HTTP/1.1\r\n" "Host: localhost\r\n" "Content-Type: application/json\r\n" "Content-Length: " + std::to_string(json_body.size()) + "\r\n" "Connection: keep-alive\r\n" "\r\n" + json_body; std::string second_get = "GET /v1/version HTTP/1.1\r\n" "Host: localhost\r\n" "Connection: close\r\n" "\r\n"; // Send POST request followed immediately by GET request // This creates a scenario where the GET request starts parsing // while the POST response is being written (triggering the reset) int w1 = write(fd, first_post.c_str(), first_post.size()); REQUIRE(w1 == static_cast(first_post.size())); int w2 = write(fd, second_get.c_str(), second_get.size()); REQUIRE(w2 == static_cast(second_get.size())); // Read responses using blocking I/O (deterministic synchronization) char buf[4096]; int total_read = 0; int responses_found = 0; while (total_read < 4000) { int r = read(fd, buf + total_read, sizeof(buf) - total_read - 1); if (r <= 0) break; total_read += r; buf[total_read] = '\0'; std::string response(buf, total_read); std::size_t pos = 0; while ((pos = response.find("HTTP/1.1", pos)) != std::string::npos) { responses_found++; pos += 8; } if (responses_found >= 2) break; } // Should get responses to both requests // Race condition might cause parsing errors or connection issues CHECK(responses_found >= 1); // At minimum should handle first request close(fd); server->shutdown(); runThread.join(); }