Skip every interim response, with its header fields

Only 100 Continue was skipped, and only without header fields, so a 103
Early Hints was taken for the final response and a 100 with fields threw
the parsing off. Skip every 1xx but 101, along with its header fields.
This commit is contained in:
yhirose committed 2026-10-16 16:39:00 -04:00
1 parent 5d10305218
commit ce7ecb633b
2 files changed
+67 -3

No files matched your search

+60
View File
@@ -13535,6 +13535,66 @@ TEST(ClientPayloadTest, DoesNotReserveTheClaimedLength) {
EXPECT_FALSE(cli.Get("/"));
}
// Accepts one connection on 127.0.0.1:port, reads the request head and sends
// back the given bytes, which httplib::Server could not be made to send.
static void serve_raw_once(int port, const std::string &response) {
auto srv = ::socket(AF_INET, SOCK_STREAM, 0);
default_socket_options(srv);
sockaddr_in addr{};
addr.sin_family = AF_INET;
addr.sin_port = htons(static_cast<uint16_t>(port));
::inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr);
int opt = 1;
::setsockopt(srv, SOL_SOCKET, SO_REUSEADDR,
#ifdef _WIN32
reinterpret_cast<const char *>(&opt),
#else
&opt,
#endif
sizeof(opt));
::bind(srv, reinterpret_cast<sockaddr *>(&addr), sizeof(addr));
::listen(srv, 1);
auto cli = ::accept(srv, nullptr, nullptr);
if (cli != INVALID_SOCKET) {
detail::set_socket_opt_time(cli, SOL_SOCKET, SO_RCVTIMEO, 3, 0);
std::string head;
char c;
while (head.find("\r\n\r\n") == std::string::npos &&
::recv(cli, &c, 1, 0) == 1) {
head += c;
}
::send(cli, response.data(), static_cast<int>(response.size()), 0);
detail::close_socket(cli);
}
detail::close_socket(srv);
}
TEST(InterimResponseTest, SkippedWithTheirHeaderFields) {
const char *responses[] = {
"HTTP/1.1 103 Early Hints\r\n"
"Link: </style.css>; rel=preload\r\n"
"\r\n"
"HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nok",
"HTTP/1.1 100 Continue\r\n"
"X-Note: interim\r\n"
"\r\n"
"HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nok",
};
for (auto response : responses) {
std::thread t([&]() { serve_raw_once(PORT, response); });
std::this_thread::sleep_for(std::chrono::milliseconds(100));
Client cli("127.0.0.1", PORT);
auto res = cli.Get("/");
t.join();
ASSERT_TRUE(res) << "Error: " << to_string(res.error());
EXPECT_EQ(StatusCode::OK_200, res->status);
EXPECT_EQ("ok", res->body);
}
}
TEST(ExpectContinueTest, EarlyFinalResponseClosesConnection) {
std::atomic<bool> closed_by_client{false};
auto server_thread = std::thread([&] {