Add test for url accumulation bug
This commit is contained in:
@@ -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();
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user