mirror of
https://github.com/yhirose/cpp-httplib
synced 2024-11-21 06:26:02 -07:00
Report connection timeout as separate event (#1171)
This commit is contained in:
parent
e5cacb465d
commit
87e03dd1ce
2 changed files with 33 additions and 12 deletions
38
httplib.h
38
httplib.h
|
@ -799,6 +799,7 @@ enum class Error {
|
|||
SSLServerVerification,
|
||||
UnsupportedMultipartBoundaryChars,
|
||||
Compression,
|
||||
ConnectionTimeout,
|
||||
};
|
||||
|
||||
std::string to_string(const Error error);
|
||||
|
@ -1594,6 +1595,7 @@ inline std::string to_string(const Error error) {
|
|||
case Error::UnsupportedMultipartBoundaryChars:
|
||||
return "UnsupportedMultipartBoundaryChars";
|
||||
case Error::Compression: return "Compression";
|
||||
case Error::ConnectionTimeout: return "ConnectionTimeout";
|
||||
case Error::Unknown: return "Unknown";
|
||||
default: break;
|
||||
}
|
||||
|
@ -2313,7 +2315,7 @@ inline ssize_t select_write(socket_t sock, time_t sec, time_t usec) {
|
|||
#endif
|
||||
}
|
||||
|
||||
inline bool wait_until_socket_is_ready(socket_t sock, time_t sec, time_t usec) {
|
||||
inline Error wait_until_socket_is_ready(socket_t sock, time_t sec, time_t usec) {
|
||||
#ifdef CPPHTTPLIB_USE_POLL
|
||||
struct pollfd pfd_read;
|
||||
pfd_read.fd = sock;
|
||||
|
@ -2323,17 +2325,23 @@ inline bool wait_until_socket_is_ready(socket_t sock, time_t sec, time_t usec) {
|
|||
|
||||
auto poll_res = handle_EINTR([&]() { return poll(&pfd_read, 1, timeout); });
|
||||
|
||||
if (poll_res == 0) {
|
||||
return Error::ConnectionTimeout;
|
||||
}
|
||||
|
||||
if (poll_res > 0 && pfd_read.revents & (POLLIN | POLLOUT)) {
|
||||
int error = 0;
|
||||
socklen_t len = sizeof(error);
|
||||
auto res = getsockopt(sock, SOL_SOCKET, SO_ERROR,
|
||||
reinterpret_cast<char *>(&error), &len);
|
||||
return res >= 0 && !error;
|
||||
auto successful = res >= 0 && !error;
|
||||
return successful ? Error::Success : Error::Connection;
|
||||
}
|
||||
return false;
|
||||
|
||||
return Error::Connection;
|
||||
#else
|
||||
#ifndef _WIN32
|
||||
if (sock >= FD_SETSIZE) { return false; }
|
||||
if (sock >= FD_SETSIZE) { return Error::Connection; }
|
||||
#endif
|
||||
|
||||
fd_set fdsr;
|
||||
|
@ -2351,14 +2359,19 @@ inline bool wait_until_socket_is_ready(socket_t sock, time_t sec, time_t usec) {
|
|||
return select(static_cast<int>(sock + 1), &fdsr, &fdsw, &fdse, &tv);
|
||||
});
|
||||
|
||||
if (ret == 0) {
|
||||
return Error::ConnectionTimeout;
|
||||
}
|
||||
|
||||
if (ret > 0 && (FD_ISSET(sock, &fdsr) || FD_ISSET(sock, &fdsw))) {
|
||||
int error = 0;
|
||||
socklen_t len = sizeof(error);
|
||||
return getsockopt(sock, SOL_SOCKET, SO_ERROR,
|
||||
reinterpret_cast<char *>(&error), &len) >= 0 &&
|
||||
!error;
|
||||
auto res = getsockopt(sock, SOL_SOCKET, SO_ERROR,
|
||||
reinterpret_cast<char *>(&error), &len);
|
||||
auto successful = res >= 0 && !error;
|
||||
return successful ? Error::Success : Error::Connection;
|
||||
}
|
||||
return false;
|
||||
return Error::Connection;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -2684,12 +2697,15 @@ inline socket_t create_client_socket(
|
|||
::connect(sock2, ai.ai_addr, static_cast<socklen_t>(ai.ai_addrlen));
|
||||
|
||||
if (ret < 0) {
|
||||
if (is_connection_error() ||
|
||||
!wait_until_socket_is_ready(sock2, connection_timeout_sec,
|
||||
connection_timeout_usec)) {
|
||||
if (is_connection_error()) {
|
||||
error = Error::Connection;
|
||||
return false;
|
||||
}
|
||||
error = wait_until_socket_is_ready(sock2, connection_timeout_sec,
|
||||
connection_timeout_usec);
|
||||
if (error != Error::Success) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
set_nonblocking(sock2, false);
|
||||
|
|
|
@ -622,9 +622,14 @@ TEST(ConnectionErrorTest, Timeout) {
|
|||
#endif
|
||||
cli.set_connection_timeout(std::chrono::seconds(2));
|
||||
|
||||
// only probe one address type so that the error reason
|
||||
// correlates to the timed-out IPv4, not the unsupported
|
||||
// IPv6 connection attempt
|
||||
cli.set_address_family(AF_INET);
|
||||
|
||||
auto res = cli.Get("/");
|
||||
ASSERT_TRUE(!res);
|
||||
EXPECT_TRUE(res.error() == Error::Connection);
|
||||
EXPECT_EQ(Error::ConnectionTimeout, res.error());
|
||||
}
|
||||
|
||||
TEST(CancelTest, NoCancel_Online) {
|
||||
|
|
Loading…
Reference in a new issue