1
0
mirror of synced 2025-12-01 23:17:49 +03:00
Enhance request handling: add support for requests without Content-Length or Transfer-Encoding headers
This commit is contained in:
yhirose
2025-11-25 20:30:43 -05:00
parent 9e7861b0b4
commit 337fbb0793
2 changed files with 78 additions and 4 deletions

View File

@@ -7932,7 +7932,11 @@ inline bool Server::read_content_core(
size_t /*len*/) { return receiver(buf, n); };
}
if (req.method == "DELETE" && !req.has_header("Content-Length")) {
// RFC 7230 Section 3.3.3: If this is a request message and none of the above
// are true (no Transfer-Encoding and no Content-Length), then the message
// body length is zero (no message body is present).
if (!req.has_header("Content-Length") &&
!detail::is_chunked_transfer_encoding(req.headers)) {
return true;
}

View File

@@ -3424,7 +3424,7 @@ protected:
res.set_content(req.body, "text/plain");
})
.Post("/post-loopback",
[&](const Request &req, Response &res,
[&](const Request &, Response &res,
ContentReader const &content_reader) {
std::string body;
content_reader([&](const char *data, size_t data_length) {
@@ -3435,7 +3435,7 @@ protected:
res.set_content(body, "text/plain");
})
.Put("/put-loopback",
[&](const Request &req, Response &res,
[&](const Request &, Response &res,
ContentReader const &content_reader) {
std::string body;
content_reader([&](const char *data, size_t data_length) {
@@ -3446,7 +3446,7 @@ protected:
res.set_content(body, "text/plain");
})
.Patch("/patch-loopback",
[&](const Request &req, Response &res,
[&](const Request &, Response &res,
ContentReader const &content_reader) {
std::string body;
content_reader([&](const char *data, size_t data_length) {
@@ -11609,3 +11609,73 @@ TEST(ForwardedHeadersTest, HandlesWhitespaceAroundIPs) {
EXPECT_EQ(observed_xff, "198.51.100.23 , 203.0.113.66 , 192.0.2.45");
EXPECT_EQ(observed_remote_addr, "203.0.113.66");
}
TEST(ServerRequestParsingTest, RequestWithoutContentLengthOrTransferEncoding) {
Server svr;
svr.Post("/post", [&](const Request &req, Response &res) {
res.set_content(req.body, "text/plain");
});
svr.Put("/put", [&](const Request &req, Response &res) {
res.set_content(req.body, "text/plain");
});
svr.Patch("/patch", [&](const Request &req, Response &res) {
res.set_content(req.body, "text/plain");
});
svr.Delete("/delete", [&](const Request &req, Response &res) {
res.set_content(req.body, "text/plain");
});
thread t = thread([&]() { svr.listen(HOST, PORT); });
auto se = detail::scope_exit([&] {
svr.stop();
t.join();
ASSERT_FALSE(svr.is_running());
});
svr.wait_until_ready();
std::string resp;
// POST without Content-Length
ASSERT_TRUE(send_request(5,
"POST /post HTTP/1.1\r\n"
"Host: localhost\r\n"
"Connection: close\r\n"
"\r\n",
&resp));
EXPECT_TRUE(resp.find("HTTP/1.1 200 OK") == 0);
// PUT without Content-Length
resp.clear();
ASSERT_TRUE(send_request(5,
"PUT /put HTTP/1.1\r\n"
"Host: localhost\r\n"
"Connection: close\r\n"
"\r\n",
&resp));
EXPECT_TRUE(resp.find("HTTP/1.1 200 OK") == 0);
// PATCH without Content-Length
resp.clear();
ASSERT_TRUE(send_request(5,
"PATCH /patch HTTP/1.1\r\n"
"Host: localhost\r\n"
"Connection: close\r\n"
"\r\n",
&resp));
EXPECT_TRUE(resp.find("HTTP/1.1 200 OK") == 0);
// DELETE without Content-Length
resp.clear();
ASSERT_TRUE(send_request(5,
"DELETE /delete HTTP/1.1\r\n"
"Host: localhost\r\n"
"Connection: close\r\n"
"\r\n",
&resp));
EXPECT_TRUE(resp.find("HTTP/1.1 200 OK") == 0);
}