From a1aa2ad9cd9f69038a6d954817336e311fde6dc4 Mon Sep 17 00:00:00 2001 From: yhirose Date: Thu, 6 Aug 2026 23:21:10 -0400 Subject: [PATCH] Give WebSocketClient the chrono::duration timeout setters ClientImpl has WebSocketClient only accepted timeouts as (time_t sec, time_t usec), while ClientImpl has taken std::chrono::duration overloads for its read, write and connection timeouts for a long time. Add the same three overloads, forwarding through the existing detail::duration_to_sec_and_usec helper so the split matches ClientImpl exactly. The template bodies go above the first split.py BORDER, next to the class, so that the .h/.cc split keeps them in the header where instantiation needs them. --- httplib.h | 33 +++++++++++++++++++++++++++++++++ test/test.cc | 22 ++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/httplib.h b/httplib.h index e4eefb4c..12a58b98 100644 --- a/httplib.h +++ b/httplib.h @@ -4279,14 +4279,25 @@ public: bool is_open() const; const std::string &subprotocol() const; void set_read_timeout(time_t sec, time_t usec = 0); + template + void set_read_timeout(const std::chrono::duration &duration); + void set_write_timeout(time_t sec, time_t usec = 0); + template + void set_write_timeout(const std::chrono::duration &duration); + void set_websocket_ping_interval(time_t sec); void set_websocket_max_missed_pongs(int count); void set_tcp_nodelay(bool on); void set_address_family(int family); void set_ipv6_v6only(bool on); void set_socket_options(SocketOptions socket_options); + void set_connection_timeout(time_t sec, time_t usec = 0); + template + void + set_connection_timeout(const std::chrono::duration &duration); + void set_interface(const std::string &intf); void set_hostname_addr_map(std::map addr_map); @@ -4342,6 +4353,28 @@ private: #endif }; +template +inline void WebSocketClient::set_read_timeout( + const std::chrono::duration &duration) { + detail::duration_to_sec_and_usec( + duration, [&](time_t sec, time_t usec) { set_read_timeout(sec, usec); }); +} + +template +inline void WebSocketClient::set_write_timeout( + const std::chrono::duration &duration) { + detail::duration_to_sec_and_usec( + duration, [&](time_t sec, time_t usec) { set_write_timeout(sec, usec); }); +} + +template +inline void WebSocketClient::set_connection_timeout( + const std::chrono::duration &duration) { + detail::duration_to_sec_and_usec(duration, [&](time_t sec, time_t usec) { + set_connection_timeout(sec, usec); + }); +} + namespace impl { bool is_valid_utf8(const std::string &s); diff --git a/test/test.cc b/test/test.cc index 5275177e..fa988ff6 100644 --- a/test/test.cc +++ b/test/test.cc @@ -20487,6 +20487,28 @@ TEST_F(WebSocketIntegrationTest, SocketSettings) { client.close(); } +TEST_F(WebSocketIntegrationTest, ChronoTimeoutSetters) { + ws::WebSocketClient client("ws://localhost:" + std::to_string(port_) + + "/ws-echo"); + client.set_connection_timeout(std::chrono::seconds(3)); + client.set_write_timeout(std::chrono::seconds(3)); + // A sub-second remainder exercises the seconds/microseconds split. + client.set_read_timeout(std::chrono::milliseconds(1500)); + + ASSERT_TRUE(client.connect()); + + auto start = std::chrono::steady_clock::now(); + std::string msg; + EXPECT_EQ(client.read(msg), ws::ReadResult::Fail); + auto elapsed = std::chrono::duration_cast( + std::chrono::steady_clock::now() - start) + .count(); + // Above 1s so that dropping the microseconds half of the split fails here, + // and well under the 300s default so that ignoring the setter fails too. + EXPECT_GE(elapsed, 1400); + EXPECT_LT(elapsed, 30000); +} + TEST(WebSocketPreRoutingTest, RejectWithoutAuth) { Server svr;