diff --git a/httplib.h b/httplib.h index 8411c8c93b..898de337ef 100644 --- a/httplib.h +++ b/httplib.h @@ -7133,7 +7133,7 @@ inline ssize_t SocketStream::read(char *ptr, size_t size) { } inline ssize_t SocketStream::write(const char *ptr, size_t size) { - if (!wait_writable()) { return -1; } + if (!detail::is_socket_alive(sock_) || !wait_writable()) { return -1; } #if defined(_WIN32) && !defined(_WIN64) size = @@ -8618,7 +8618,11 @@ inline ClientImpl::ClientImpl(const std::string &host, int port, const std::string &client_key_path) : host_(detail::escape_abstract_namespace_unix_domain(host)), port_(port), host_and_port_(detail::make_host_and_port_string(host_, port, is_ssl())), - client_cert_path_(client_cert_path), client_key_path_(client_key_path) {} + client_cert_path_(client_cert_path), client_key_path_(client_key_path) { +#ifndef _WIN32 + signal(SIGPIPE, SIG_IGN); +#endif +} inline ClientImpl::~ClientImpl() { // Wait until all the requests in flight are handled. @@ -9516,7 +9520,7 @@ inline bool ClientImpl::process_request(Stream &strm, Request &req, Response &res, bool close_connection, Error &error) { // Send request - if (!write_request(strm, req, close_connection, error)) { return false; } + bool wrote = write_request(strm, req, close_connection, error); #ifdef CPPHTTPLIB_OPENSSL_SUPPORT if (is_ssl()) { @@ -9539,6 +9543,8 @@ inline bool ClientImpl::process_request(Stream &strm, Request &req, return false; } + if (!wrote) return false; + // Body if ((res.status != StatusCode::NoContent_204) && req.method != "HEAD" && req.method != "CONNECT") { diff --git a/test/test.cc b/test/test.cc index b54c0f0afb..26b2a89765 100644 --- a/test/test.cc +++ b/test/test.cc @@ -5898,6 +5898,49 @@ TEST_F(ServerTest, BadRequestLineCancelsKeepAlive) { EXPECT_FALSE(cli_.is_socket_open()); } +TEST_F(ServerTest, SendLargeBodyAfterRequestLineError) { + Request post; + post.method = "POST"; + post.path = "/post-large?q=" + LONG_QUERY_VALUE; + post.body = LARGE_DATA; + + auto start = std::chrono::high_resolution_clock::now(); + + auto resPost = std::make_shared(); + auto error = Error::Success; + cli_.set_keep_alive(true); + auto ret = cli_.send(post, *resPost, error); + + auto end = std::chrono::high_resolution_clock::now(); + auto elapsed = + std::chrono::duration_cast(end - start) + .count(); + + EXPECT_FALSE(ret); +#ifndef _WIN32 + EXPECT_EQ(StatusCode::UriTooLong_414, resPost->status); + EXPECT_EQ("close", resPost->get_header_value("Connection")); +#endif + EXPECT_FALSE(cli_.is_socket_open()); + EXPECT_LE(elapsed, 200); + + // Send an extra GET request to ensure error recovery without hanging + Request get; + get.method = "GET"; + get.path = "/hi"; + + start = std::chrono::high_resolution_clock::now(); + auto resGet = cli_.send(get); + end = std::chrono::high_resolution_clock::now(); + elapsed = std::chrono::duration_cast(end - start) + .count(); + + ASSERT_TRUE(resGet); + EXPECT_EQ(StatusCode::OK_200, resGet->status); + EXPECT_EQ("Hello World!", resGet->body); + EXPECT_LE(elapsed, 100); +} + TEST_F(ServerTest, StartTime) { auto res = cli_.Get("/test-start-time"); } #ifdef CPPHTTPLIB_ZLIB_SUPPORT