mirror of
https://github.com/yhirose/cpp-httplib.git
synced 2026-10-19 11:19:36 +00:00
Close the connection after a response body with no length
A content provider without a length or chunked coding sends a body that only the end of the connection delimits (RFC 9112 6.3), yet the response offered keep-alive, so a keep-alive client waited for the server's idle timeout. Send Connection: close and close after it, as Go's net/http does. A Content-Length set by the handler is still dropped; the overload that takes a length frames such a body.
This commit is contained in:
1 parent
645bdab90e
commit
7bf66db6ca
2 files changed
+46
-2
No files matched your search
@@ -12091,8 +12091,9 @@ inline bool is_partial_content(const Request &req, const Response &res) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Sets the Content-Length or Transfer-Encoding framing the body that
|
// Sets the Content-Length or Transfer-Encoding framing the body that
|
||||||
// Server::write_response_core() writes. Only the library sets them: one from a
|
// Server::write_response_core() writes, or closes the connection after a body
|
||||||
// handler would go out next to it, or describe some other body.
|
// that has neither. Only the library sets them: one from a handler would go
|
||||||
|
// out next to it, or describe some other body.
|
||||||
inline void set_framing_headers(const Request &req, Response &res,
|
inline void set_framing_headers(const Request &req, Response &res,
|
||||||
const std::string &boundary,
|
const std::string &boundary,
|
||||||
const std::string &content_type) {
|
const std::string &content_type) {
|
||||||
@@ -12109,6 +12110,12 @@ inline void set_framing_headers(const Request &req, Response &res,
|
|||||||
if (res.content_length_ == 0) {
|
if (res.content_length_ == 0) {
|
||||||
if (res.is_chunked_content_provider_) {
|
if (res.is_chunked_content_provider_) {
|
||||||
res.set_header("Transfer-Encoding", "chunked");
|
res.set_header("Transfer-Encoding", "chunked");
|
||||||
|
} else if (req.method != "HEAD") {
|
||||||
|
// RFC 9112 6.3: a body with neither ends where the connection does.
|
||||||
|
res.headers.erase("Keep-Alive");
|
||||||
|
if (!has_header_token(res.headers, "Connection", "close")) {
|
||||||
|
res.set_header("Connection", "close");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5756,6 +5756,43 @@ TEST(ResponseFramingTest, PostRoutingHandlerChangesAreFramed) {
|
|||||||
EXPECT_FALSE(res->has_header("Transfer-Encoding"));
|
EXPECT_FALSE(res->has_header("Transfer-Encoding"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(ResponseFramingTest, BodyWithoutLengthEndsWithTheConnection) {
|
||||||
|
Server svr;
|
||||||
|
|
||||||
|
svr.Get("/", [](const Request & /*req*/, Response &res) {
|
||||||
|
res.set_header("Content-Length", "3");
|
||||||
|
res.set_content_provider("text/plain", [](size_t, DataSink &sink) {
|
||||||
|
sink.write("abc", 3);
|
||||||
|
sink.done();
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
Client cli(HOST, PORT);
|
||||||
|
cli.set_keep_alive(true);
|
||||||
|
|
||||||
|
auto res = cli.Get("/");
|
||||||
|
ASSERT_TRUE(res) << "Error: " << to_string(res.error());
|
||||||
|
EXPECT_EQ("abc", res->body);
|
||||||
|
EXPECT_FALSE(res->has_header("Content-Length"));
|
||||||
|
EXPECT_EQ("close", res->get_header_value("Connection"));
|
||||||
|
EXPECT_FALSE(res->has_header("Keep-Alive"));
|
||||||
|
|
||||||
|
// No body to delimit
|
||||||
|
auto head = cli.Head("/");
|
||||||
|
ASSERT_TRUE(head) << "Error: " << to_string(head.error());
|
||||||
|
EXPECT_FALSE(head->has_header("Connection"));
|
||||||
|
}
|
||||||
|
|
||||||
TEST(RoutingHandlerTest, PreAndPostRoutingHandlers) {
|
TEST(RoutingHandlerTest, PreAndPostRoutingHandlers) {
|
||||||
#ifdef CPPHTTPLIB_SSL_ENABLED
|
#ifdef CPPHTTPLIB_SSL_ENABLED
|
||||||
SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE);
|
SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE);
|
||||||
|
|||||||
Reference in new issue
Block a user