From ba5884e779c77db7bda3ad26e4d7820ea724464c Mon Sep 17 00:00:00 2001 From: yhirose Date: Fri, 3 Mar 2023 23:45:19 -0500 Subject: [PATCH] Fix #1481 (#1513) --- httplib.h | 9 +++++++- test/test.cc | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/httplib.h b/httplib.h index ca29cc2..1b7f5f8 100644 --- a/httplib.h +++ b/httplib.h @@ -6289,6 +6289,13 @@ inline bool ClientImpl::send(Request &req, Response &res, Error &error) { auto is_alive = false; if (socket_.is_open()) { is_alive = detail::is_socket_alive(socket_.sock); +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT + if (is_ssl() && is_alive) { + char buf[1]; + auto n = SSL_peek(socket_.ssl, buf, 1); + if (n <= 0) { is_alive = false; } + } +#endif if (!is_alive) { // Attempt to avoid sigpipe by shutting down nongracefully if it seems // like the other side has already closed the connection Also, there @@ -6339,7 +6346,7 @@ inline bool ClientImpl::send(Request &req, Response &res, Error &error) { auto ret = false; auto close_connection = !keep_alive_; - auto se = detail::scope_exit>([&]() { + auto se = detail::scope_exit>([&]() { // Briefly lock mutex in order to mark that a request is no longer ongoing std::lock_guard guard(socket_mutex_); socket_requests_in_flight_ -= 1; diff --git a/test/test.cc b/test/test.cc index 298aa8e..9446a70 100644 --- a/test/test.cc +++ b/test/test.cc @@ -3871,6 +3871,32 @@ TEST(ServerStopTest, StopServerWithChunkedTransmission) { ASSERT_FALSE(svr.is_running()); } +TEST(ServerStopTest, ClientAccessAfterServerDown) { + httplib::Server svr; + svr.Post("/hi", [&](const httplib::Request & /*req*/, httplib::Response &res) { + res.status = 200; + }); + + auto thread = std::thread([&]() { svr.listen(HOST, PORT); }); + + while (!svr.is_running()) { + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + } + + Client cli(HOST, PORT); + + auto res = cli.Post("/hi", "data", "text/plain"); + ASSERT_TRUE(res); + EXPECT_EQ(200, res->status); + + svr.stop(); + thread.join(); + ASSERT_FALSE(svr.is_running()); + + res = cli.Post("/hi", "data", "text/plain"); + ASSERT_FALSE(res); +} + TEST(StreamingTest, NoContentLengthStreaming) { Server svr; @@ -4067,6 +4093,39 @@ TEST(KeepAliveTest, Issue1041) { f.wait(); } +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT +TEST(KeepAliveTest, SSLClientReconnection) { + SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE); + ASSERT_TRUE(svr.is_valid()); + svr.set_keep_alive_timeout(1); + + svr.Get("/hi", [](const httplib::Request &, httplib::Response &res) { + res.set_content("Hello World!", "text/plain"); + }); + + auto f = std::async(std::launch::async, [&svr] { svr.listen(HOST, PORT); }); + std::this_thread::sleep_for(std::chrono::milliseconds(200)); + + SSLClient cli(HOST, PORT); + cli.enable_server_certificate_verification(false); + cli.set_keep_alive(true); + + auto result = cli.Get("/hi"); + ASSERT_TRUE(result); + EXPECT_EQ(200, result->status); + + std::this_thread::sleep_for(std::chrono::seconds(2)); + + result = cli.Get("/hi"); + + svr.stop(); + f.wait(); + + ASSERT_TRUE(result); + EXPECT_EQ(200, result->status); +} +#endif + TEST(ClientProblemDetectionTest, ContentProvider) { Server svr;