From a5bfddf17f636c39a527427139e0798e135f28fd Mon Sep 17 00:00:00 2001 From: yhirose Date: Mon, 13 Mar 2023 22:11:33 -0400 Subject: [PATCH] Fix #1481 (with content provider) --- httplib.h | 15 ++++++++++++++- test/test.cc | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) diff --git a/httplib.h b/httplib.h index 2aefc4b..a3c8a8a 100644 --- a/httplib.h +++ b/httplib.h @@ -8547,7 +8547,20 @@ inline void ssl_delete(std::mutex &ctx_mutex, SSL *ssl, // the remote has closed the network connection // Note that it is not always possible to avoid SIGPIPE, this is merely a // best-efforts. - if (shutdown_gracefully) { SSL_shutdown(ssl); } + if (shutdown_gracefully) { + auto is_peer_could_be_closed = false; + { + char buf[1]; + if (SSL_peek(ssl, buf, 1) == 0 && + SSL_get_error(ssl, 0) == SSL_ERROR_ZERO_RETURN) { + is_peer_could_be_closed = true; + } + } + + if (!is_peer_could_be_closed) { + SSL_shutdown(ssl); + } + } std::lock_guard guard(ctx_mutex); SSL_free(ssl); diff --git a/test/test.cc b/test/test.cc index df69d4a..a0d793b 100644 --- a/test/test.cc +++ b/test/test.cc @@ -4996,6 +4996,60 @@ TEST(KeepAliveTest, SSLClientReconnection) { ASSERT_TRUE(result); EXPECT_EQ(StatusCode::OK_200, result->status); } + +TEST(KeepAliveTest, SSLClientReconnectionPost) { + SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE); + ASSERT_TRUE(svr.is_valid()); + svr.set_keep_alive_timeout(1); + std::string content = "reconnect"; + + svr.Post("/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.Post( + "/hi", content.size(), + [&content](size_t offset, size_t length, DataSink &sink) { + sink.write(content.c_str(), content.size()); + return true; + }, + "text/plain"); + ASSERT_TRUE(result); + EXPECT_EQ(200, result->status); + + std::this_thread::sleep_for(std::chrono::seconds(2)); + + // Recoonect + result = cli.Post( + "/hi", content.size(), + [&content](size_t offset, size_t length, DataSink &sink) { + sink.write(content.c_str(), content.size()); + return true; + }, + "text/plain"); + ASSERT_TRUE(result); + EXPECT_EQ(200, result->status); + + result = cli.Post( + "/hi", content.size(), + [&content](size_t offset, size_t length, DataSink &sink) { + sink.write(content.c_str(), content.size()); + return true; + }, + "text/plain"); + ASSERT_TRUE(result); + EXPECT_EQ(200, result->status); + + svr.stop(); + f.wait(); +} #endif TEST(ClientProblemDetectionTest, ContentProvider) {