Add test for url accumulation bug

This commit is contained in:
2025-09-15 21:29:33 -04:00
parent 345d8e21b2
commit 5dda7353fa

View File

@@ -3,6 +3,7 @@
#include "http_handler.hpp" #include "http_handler.hpp"
#include "server.hpp" #include "server.hpp"
#include <chrono>
#include <doctest/doctest.h> #include <doctest/doctest.h>
#include <fcntl.h> #include <fcntl.h>
#include <poll.h> #include <poll.h>
@@ -198,3 +199,70 @@ TEST_CASE("HTTP pipelined POST requests race condition") {
server->shutdown(); server->shutdown();
runThread.join(); runThread.join();
} }
TEST_CASE("HTTP URL split across multiple writes") {
weaseldb::Config config;
HttpHandler handler(config);
auto server = Server::create(config, handler, {});
int fd = server->create_local_connection();
auto runThread = std::thread{[&]() { server->run(); }};
// Test URL accumulation by splitting the URL across multiple writes
// This would have caught the original bug where URL string_view pointed
// to llhttp's internal buffer that gets reused between writes
// Split "GET /metrics HTTP/1.1\r\n" across multiple writes
std::string part1 = "GET /met";
std::string part2 = "rics HTTP/1.1\r\n";
std::string headers = "Host: localhost\r\n"
"Connection: close\r\n"
"\r\n";
// Write URL in two parts - this tests URL accumulation
int w1 = write(fd, part1.c_str(), part1.size());
REQUIRE(w1 == static_cast<int>(part1.size()));
// Attempt to trigger separate llhttp parsing calls
std::this_thread::sleep_for(std::chrono::milliseconds(1));
int w2 = write(fd, part2.c_str(), part2.size());
REQUIRE(w2 == static_cast<int>(part2.size()));
int w3 = write(fd, headers.c_str(), headers.size());
REQUIRE(w3 == static_cast<int>(headers.size()));
// Read response
char buf[4096];
int total_read = 0;
bool found_metrics_response = false;
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);
// Check for successful metrics response (not 404)
if (response.find("HTTP/1.1 200 OK") != std::string::npos &&
response.find("text/plain; version=0.0.4") != std::string::npos) {
found_metrics_response = true;
break;
}
// Check for 404 which would indicate URL accumulation failed
if (response.find("HTTP/1.1 404") != std::string::npos) {
FAIL("Got 404 - URL accumulation failed, split URL was not properly "
"reconstructed");
}
}
REQUIRE(found_metrics_response);
close(fd);
server->shutdown();
runThread.join();
}