diff --git a/httplib.h b/httplib.h index cf688c88..85b3a261 100644 --- a/httplib.h +++ b/httplib.h @@ -1480,6 +1480,8 @@ using SocketOptions = std::function; void default_socket_options(socket_t sock); +bool set_socket_opt(socket_t sock, int level, int optname, int optval); + const char *status_message(int status); std::string to_string(Error error); @@ -4338,10 +4340,6 @@ inline bool set_socket_opt_impl(socket_t sock, int level, int optname, optlen) == 0; } -inline bool set_socket_opt(socket_t sock, int level, int optname, int optval) { - return set_socket_opt_impl(sock, level, optname, &optval, sizeof(optval)); -} - inline bool set_socket_opt_time(socket_t sock, int level, int optname, time_t sec, time_t usec) { #ifdef _WIN32 @@ -6089,7 +6087,7 @@ socket_t create_socket(const std::string &host, const std::string &ip, int port, #ifdef _WIN32 // Setting SO_REUSEADDR seems not to work well with AF_UNIX on windows, so // remove the option. - detail::set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 0); + set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 0); #endif bool dummy; @@ -9135,13 +9133,18 @@ inline bool setup_client_tls_session(const std::string &host, tls::ctx_t &ctx, */ inline void default_socket_options(socket_t sock) { - detail::set_socket_opt(sock, SOL_SOCKET, + set_socket_opt(sock, SOL_SOCKET, #ifdef SO_REUSEPORT - SO_REUSEPORT, + SO_REUSEPORT, #else - SO_REUSEADDR, + SO_REUSEADDR, #endif - 1); + 1); +} + +inline bool set_socket_opt(socket_t sock, int level, int optname, int optval) { + return detail::set_socket_opt_impl(sock, level, optname, &optval, + sizeof(optval)); } inline std::string get_bearer_token_auth(const Request &req) { @@ -11561,9 +11564,7 @@ inline bool Server::listen_internal() { detail::set_socket_opt_time(sock, SOL_SOCKET, SO_SNDTIMEO, write_timeout_sec_, write_timeout_usec_); - if (tcp_nodelay_) { - detail::set_socket_opt(sock, IPPROTO_TCP, TCP_NODELAY, 1); - } + if (tcp_nodelay_) { set_socket_opt(sock, IPPROTO_TCP, TCP_NODELAY, 1); } if (!task_queue->enqueue( [this, sock]() { process_and_close_socket(sock); })) { diff --git a/test/test.cc b/test/test.cc index f5a10397..f9ff93c7 100644 --- a/test/test.cc +++ b/test/test.cc @@ -316,6 +316,19 @@ TEST(SocketStream, wait_writable_INET) { } #endif // #ifndef _WIN32 +TEST(SetSocketOptTest, TcpNoDelay) { + auto sock = ::socket(AF_INET, SOCK_STREAM, 0); + ASSERT_NE(sock, INVALID_SOCKET); + EXPECT_TRUE(set_socket_opt(sock, IPPROTO_TCP, TCP_NODELAY, 1)); + + int val = 0; + socklen_t len = sizeof(val); + ASSERT_EQ(0, ::getsockopt(sock, IPPROTO_TCP, TCP_NODELAY, + reinterpret_cast(&val), &len)); + EXPECT_NE(val, 0); + detail::close_socket(sock); +} + TEST(ClientTest, MoveConstructible) { EXPECT_FALSE(std::is_copy_constructible::value); EXPECT_TRUE(std::is_nothrow_move_constructible::value); @@ -17315,8 +17328,7 @@ TEST(RequestSmugglingTest, UnconsumedGETBodyOnFileHandler) { "\r\n" "\r\n"; - auto sent = - send(sock, outer_headers.data(), outer_headers.size(), MSG_NOSIGNAL); + auto sent = send(sock, outer_headers.data(), outer_headers.size(), 0); ASSERT_EQ(static_cast(outer_headers.size()), sent); // Step 2: Read the first response (server serves file without reading body) @@ -17346,7 +17358,7 @@ TEST(RequestSmugglingTest, UnconsumedGETBodyOnFileHandler) { // Step 3: Now send the body, which looks like a new HTTP request. // On a vulnerable server the keep-alive loop reads this as a second request. - sent = send(sock, smuggled.data(), smuggled.size(), MSG_NOSIGNAL); + sent = send(sock, smuggled.data(), smuggled.size(), 0); ASSERT_EQ(static_cast(smuggled.size()), sent); // Step 4: Try to read a second response (should NOT exist after fix)