Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions httplib.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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()) {
Expand All @@ -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") {
Expand Down
43 changes: 43 additions & 0 deletions test/test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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<Response>();
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<std::chrono::milliseconds>(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<std::chrono::milliseconds>(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
Expand Down