Another simpler implementation of #890 (#891)

This commit is contained in:
yhirose 2021-04-02 18:25:04 -04:00 committed by GitHub
parent b845425cd0
commit 6ff84d34d1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 117 additions and 11 deletions

106
httplib.h
View file

@ -668,9 +668,18 @@ public:
Server &set_keep_alive_max_count(size_t count); Server &set_keep_alive_max_count(size_t count);
Server &set_keep_alive_timeout(time_t sec); Server &set_keep_alive_timeout(time_t sec);
Server &set_read_timeout(time_t sec, time_t usec = 0); Server &set_read_timeout(time_t sec, time_t usec = 0);
template <class Rep, class Period>
Server &set_read_timeout(const std::chrono::duration<Rep, Period> &duration);
Server &set_write_timeout(time_t sec, time_t usec = 0); Server &set_write_timeout(time_t sec, time_t usec = 0);
template <class Rep, class Period>
Server &set_write_timeout(const std::chrono::duration<Rep, Period> &duration);
Server &set_idle_interval(time_t sec, time_t usec = 0); Server &set_idle_interval(time_t sec, time_t usec = 0);
template <class Rep, class Period>
Server &set_idle_interval(const std::chrono::duration<Rep, Period> &duration);
Server &set_payload_max_length(size_t length); Server &set_payload_max_length(size_t length);
@ -966,8 +975,16 @@ public:
void set_socket_options(SocketOptions socket_options); void set_socket_options(SocketOptions socket_options);
void set_connection_timeout(time_t sec, time_t usec = 0); void set_connection_timeout(time_t sec, time_t usec = 0);
template <class Rep, class Period>
void set_connection_timeout(const std::chrono::duration<Rep, Period> &duration);
void set_read_timeout(time_t sec, time_t usec = 0); void set_read_timeout(time_t sec, time_t usec = 0);
template <class Rep, class Period>
void set_read_timeout(const std::chrono::duration<Rep, Period> &duration);
void set_write_timeout(time_t sec, time_t usec = 0); void set_write_timeout(time_t sec, time_t usec = 0);
template <class Rep, class Period>
void set_write_timeout(const std::chrono::duration<Rep, Period> &duration);
void set_basic_auth(const char *username, const char *password); void set_basic_auth(const char *username, const char *password);
void set_bearer_token_auth(const char *token); void set_bearer_token_auth(const char *token);
@ -1268,8 +1285,16 @@ public:
void set_socket_options(SocketOptions socket_options); void set_socket_options(SocketOptions socket_options);
void set_connection_timeout(time_t sec, time_t usec = 0); void set_connection_timeout(time_t sec, time_t usec = 0);
template <class Rep, class Period>
void set_connection_timeout(const std::chrono::duration<Rep, Period> &duration);
void set_read_timeout(time_t sec, time_t usec = 0); void set_read_timeout(time_t sec, time_t usec = 0);
template <class Rep, class Period>
void set_read_timeout(const std::chrono::duration<Rep, Period> &duration);
void set_write_timeout(time_t sec, time_t usec = 0); void set_write_timeout(time_t sec, time_t usec = 0);
template <class Rep, class Period>
void set_write_timeout(const std::chrono::duration<Rep, Period> &duration);
void set_basic_auth(const char *username, const char *password); void set_basic_auth(const char *username, const char *password);
void set_bearer_token_auth(const char *token); void set_bearer_token_auth(const char *token);
@ -3804,6 +3829,15 @@ private:
ContentProviderWithoutLength content_provider_; ContentProviderWithoutLength content_provider_;
}; };
template <typename T, typename U>
inline void duration_to_sec_and_usec(const T &duration, U callback) {
auto sec = std::chrono::duration_cast<std::chrono::seconds>(duration).count();
auto usec = std::chrono::duration_cast<std::chrono::microseconds>(
duration - std::chrono::seconds(sec))
.count();
callback(sec, usec);
}
} // namespace detail } // namespace detail
// Header utilities // Header utilities
@ -4381,6 +4415,15 @@ inline Server &Server::set_read_timeout(time_t sec, time_t usec) {
return *this; return *this;
} }
template <class Rep, class Period>
inline Server &Server::set_read_timeout(
const std::chrono::duration<Rep, Period> &duration) {
detail::duration_to_sec_and_usec(duration, [&](time_t sec, time_t usec) {
set_read_timeout(sec, usec);
});
return *this;
}
inline Server &Server::set_write_timeout(time_t sec, time_t usec) { inline Server &Server::set_write_timeout(time_t sec, time_t usec) {
write_timeout_sec_ = sec; write_timeout_sec_ = sec;
write_timeout_usec_ = usec; write_timeout_usec_ = usec;
@ -4388,6 +4431,15 @@ inline Server &Server::set_write_timeout(time_t sec, time_t usec) {
return *this; return *this;
} }
template <class Rep, class Period>
inline Server &Server::set_write_timeout(
const std::chrono::duration<Rep, Period> &duration) {
detail::duration_to_sec_and_usec(duration, [&](time_t sec, time_t usec) {
set_write_timeout(sec, usec);
});
return *this;
}
inline Server &Server::set_idle_interval(time_t sec, time_t usec) { inline Server &Server::set_idle_interval(time_t sec, time_t usec) {
idle_interval_sec_ = sec; idle_interval_sec_ = sec;
idle_interval_usec_ = usec; idle_interval_usec_ = usec;
@ -4395,6 +4447,15 @@ inline Server &Server::set_idle_interval(time_t sec, time_t usec) {
return *this; return *this;
} }
template <class Rep, class Period>
inline Server &Server::set_idle_interval(
const std::chrono::duration<Rep, Period> &duration) {
detail::duration_to_sec_and_usec(duration, [&](time_t sec, time_t usec) {
set_idle_interval(sec, usec);
});
return *this;
}
inline Server &Server::set_payload_max_length(size_t length) { inline Server &Server::set_payload_max_length(size_t length) {
payload_max_length_ = length; payload_max_length_ = length;
@ -6273,16 +6334,40 @@ inline void ClientImpl::set_connection_timeout(time_t sec, time_t usec) {
connection_timeout_usec_ = usec; connection_timeout_usec_ = usec;
} }
template <class Rep, class Period>
inline void ClientImpl::set_connection_timeout(
const std::chrono::duration<Rep, Period> &duration) {
detail::duration_to_sec_and_usec(duration, [&](time_t sec, time_t usec) {
set_connection_timeout(sec, usec);
});
}
inline void ClientImpl::set_read_timeout(time_t sec, time_t usec) { inline void ClientImpl::set_read_timeout(time_t sec, time_t usec) {
read_timeout_sec_ = sec; read_timeout_sec_ = sec;
read_timeout_usec_ = usec; read_timeout_usec_ = usec;
} }
template <class Rep, class Period>
inline void ClientImpl::set_read_timeout(
const std::chrono::duration<Rep, Period> &duration) {
detail::duration_to_sec_and_usec(duration, [&](time_t sec, time_t usec) {
set_read_timeout(sec, usec);
});
}
inline void ClientImpl::set_write_timeout(time_t sec, time_t usec) { inline void ClientImpl::set_write_timeout(time_t sec, time_t usec) {
write_timeout_sec_ = sec; write_timeout_sec_ = sec;
write_timeout_usec_ = usec; write_timeout_usec_ = usec;
} }
template <class Rep, class Period>
inline void ClientImpl::set_write_timeout(
const std::chrono::duration<Rep, Period> &duration) {
detail::duration_to_sec_and_usec(duration, [&](time_t sec, time_t usec) {
set_write_timeout(sec, usec);
});
}
inline void ClientImpl::set_basic_auth(const char *username, inline void ClientImpl::set_basic_auth(const char *username,
const char *password) { const char *password) {
basic_auth_username_ = username; basic_auth_username_ = username;
@ -7372,6 +7457,7 @@ inline void Client::set_default_headers(Headers headers) {
} }
inline void Client::set_tcp_nodelay(bool on) { cli_->set_tcp_nodelay(on); } inline void Client::set_tcp_nodelay(bool on) { cli_->set_tcp_nodelay(on); }
inline void Client::set_socket_options(SocketOptions socket_options) { inline void Client::set_socket_options(SocketOptions socket_options) {
cli_->set_socket_options(std::move(socket_options)); cli_->set_socket_options(std::move(socket_options));
} }
@ -7379,13 +7465,33 @@ inline void Client::set_socket_options(SocketOptions socket_options) {
inline void Client::set_connection_timeout(time_t sec, time_t usec) { inline void Client::set_connection_timeout(time_t sec, time_t usec) {
cli_->set_connection_timeout(sec, usec); cli_->set_connection_timeout(sec, usec);
} }
template <class Rep, class Period>
inline void Client::set_connection_timeout(
const std::chrono::duration<Rep, Period> &duration) {
cli_->set_connection_timeout(duration);
}
inline void Client::set_read_timeout(time_t sec, time_t usec) { inline void Client::set_read_timeout(time_t sec, time_t usec) {
cli_->set_read_timeout(sec, usec); cli_->set_read_timeout(sec, usec);
} }
template <class Rep, class Period>
inline void Client::set_read_timeout(
const std::chrono::duration<Rep, Period> &duration) {
cli_->set_read_timeout(duration);
}
inline void Client::set_write_timeout(time_t sec, time_t usec) { inline void Client::set_write_timeout(time_t sec, time_t usec) {
cli_->set_write_timeout(sec, usec); cli_->set_write_timeout(sec, usec);
} }
template <class Rep, class Period>
inline void Client::set_write_timeout(
const std::chrono::duration<Rep, Period> &duration) {
cli_->set_write_timeout(duration);
}
inline void Client::set_basic_auth(const char *username, const char *password) { inline void Client::set_basic_auth(const char *username, const char *password) {
cli_->set_basic_auth(username, password); cli_->set_basic_auth(username, password);
} }

View file

@ -525,7 +525,7 @@ TEST(ConnectionErrorTest, InvalidHost) {
auto port = 80; auto port = 80;
Client cli(host, port); Client cli(host, port);
#endif #endif
cli.set_connection_timeout(2); cli.set_connection_timeout(std::chrono::seconds(2));
auto res = cli.Get("/"); auto res = cli.Get("/");
ASSERT_TRUE(!res); ASSERT_TRUE(!res);
@ -540,7 +540,7 @@ TEST(ConnectionErrorTest, InvalidHost2) {
#else #else
Client cli(host); Client cli(host);
#endif #endif
cli.set_connection_timeout(2); cli.set_connection_timeout(std::chrono::seconds(2));
auto res = cli.Get("/"); auto res = cli.Get("/");
ASSERT_TRUE(!res); ASSERT_TRUE(!res);
@ -556,7 +556,7 @@ TEST(ConnectionErrorTest, InvalidPort) {
#else #else
Client cli(host, port); Client cli(host, port);
#endif #endif
cli.set_connection_timeout(2); cli.set_connection_timeout(std::chrono::seconds(2));
auto res = cli.Get("/"); auto res = cli.Get("/");
ASSERT_TRUE(!res); ASSERT_TRUE(!res);
@ -573,7 +573,7 @@ TEST(ConnectionErrorTest, Timeout) {
auto port = 8080; auto port = 8080;
Client cli(host, port); Client cli(host, port);
#endif #endif
cli.set_connection_timeout(2); cli.set_connection_timeout(std::chrono::seconds(2));
auto res = cli.Get("/"); auto res = cli.Get("/");
ASSERT_TRUE(!res); ASSERT_TRUE(!res);
@ -590,7 +590,7 @@ TEST(CancelTest, NoCancel) {
auto port = 80; auto port = 80;
Client cli(host, port); Client cli(host, port);
#endif #endif
cli.set_connection_timeout(5); cli.set_connection_timeout(std::chrono::seconds(5));
auto res = cli.Get("/range/32", [](uint64_t, uint64_t) { return true; }); auto res = cli.Get("/range/32", [](uint64_t, uint64_t) { return true; });
ASSERT_TRUE(res); ASSERT_TRUE(res);
@ -610,7 +610,7 @@ TEST(CancelTest, WithCancelSmallPayload) {
#endif #endif
auto res = cli.Get("/range/32", [](uint64_t, uint64_t) { return false; }); auto res = cli.Get("/range/32", [](uint64_t, uint64_t) { return false; });
cli.set_connection_timeout(5); cli.set_connection_timeout(std::chrono::seconds(5));
ASSERT_TRUE(!res); ASSERT_TRUE(!res);
EXPECT_EQ(Error::Canceled, res.error()); EXPECT_EQ(Error::Canceled, res.error());
} }
@ -625,7 +625,7 @@ TEST(CancelTest, WithCancelLargePayload) {
auto port = 80; auto port = 80;
Client cli(host, port); Client cli(host, port);
#endif #endif
cli.set_connection_timeout(5); cli.set_connection_timeout(std::chrono::seconds(5));
uint32_t count = 0; uint32_t count = 0;
auto res = cli.Get("/range/65536", auto res = cli.Get("/range/65536",
@ -2478,7 +2478,7 @@ TEST_F(ServerTest, SlowPostFail) {
char buffer[64 * 1024]; char buffer[64 * 1024];
memset(buffer, 0x42, sizeof(buffer)); memset(buffer, 0x42, sizeof(buffer));
cli_.set_write_timeout(0, 0); cli_.set_write_timeout(std::chrono::seconds(0));
auto res = auto res =
cli_.Post("/slowpost", 64 * 1024 * 1024, cli_.Post("/slowpost", 64 * 1024 * 1024,
[&](size_t /*offset*/, size_t /*length*/, DataSink &sink) { [&](size_t /*offset*/, size_t /*length*/, DataSink &sink) {
@ -3146,7 +3146,7 @@ static void test_raw_request(const std::string &req,
// bug to reproduce, probably to force the server to process a request // bug to reproduce, probably to force the server to process a request
// without a trailing blank line. // without a trailing blank line.
const time_t client_read_timeout_sec = 1; const time_t client_read_timeout_sec = 1;
svr.set_read_timeout(client_read_timeout_sec + 1, 0); svr.set_read_timeout(std::chrono::seconds(client_read_timeout_sec + 1));
bool listen_thread_ok = false; bool listen_thread_ok = false;
thread t = thread([&] { listen_thread_ok = svr.listen(HOST, PORT); }); thread t = thread([&] { listen_thread_ok = svr.listen(HOST, PORT); });
while (!svr.is_running()) { while (!svr.is_running()) {
@ -3446,7 +3446,7 @@ TEST(KeepAliveTest, ReadTimeout) {
Client cli("localhost", PORT); Client cli("localhost", PORT);
cli.set_keep_alive(true); cli.set_keep_alive(true);
cli.set_read_timeout(1); cli.set_read_timeout(std::chrono::seconds(1));
auto resa = cli.Get("/a"); auto resa = cli.Get("/a");
ASSERT_TRUE(!resa); ASSERT_TRUE(!resa);
@ -3583,7 +3583,7 @@ TEST(KeepAliveTest, ReadTimeoutSSL) {
SSLClient cli("localhost", PORT); SSLClient cli("localhost", PORT);
cli.enable_server_certificate_verification(false); cli.enable_server_certificate_verification(false);
cli.set_keep_alive(true); cli.set_keep_alive(true);
cli.set_read_timeout(1); cli.set_read_timeout(std::chrono::seconds(1));
auto resa = cli.Get("/a"); auto resa = cli.Get("/a");
ASSERT_TRUE(!resa); ASSERT_TRUE(!resa);