mirror of
https://github.com/yhirose/cpp-httplib.git
synced 2026-10-19 11:19:36 +00:00
Reset the client's TLS error per attempt and read it under the request lock
Reset last_ssl_error_ and last_backend_error_ at the start of each attempt in send_() rather than once in send(), so a request that succeeds on the SSLPeerCouldBeClosed_ retry does not report the TLS error of the attempt before it. Now that every request writes those members, hold request_mutex_ until the Result has read them, so another thread's request on the same client cannot reset or replace them in between. Also pick the TLS error up in a lambda in SSLClient::process_socket() instead of through an out-parameter on process_client_socket_ssl(), which has no other caller. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WGAYpQgXt95LdDQcJYgjB8
This commit is contained in:
1 file changed
+32
-25
@@ -10725,14 +10725,11 @@ inline bool process_client_socket_ssl(
|
||||
tls::session_t session, socket_t sock, time_t read_timeout_sec,
|
||||
time_t read_timeout_usec, time_t write_timeout_sec,
|
||||
time_t write_timeout_usec, time_t max_timeout_msec,
|
||||
std::chrono::time_point<std::chrono::steady_clock> start_time, T callback,
|
||||
tls::TlsError *tls_error = nullptr) {
|
||||
std::chrono::time_point<std::chrono::steady_clock> start_time, T callback) {
|
||||
SSLSocketStream strm(sock, session, read_timeout_sec, read_timeout_usec,
|
||||
write_timeout_sec, write_timeout_usec, max_timeout_msec,
|
||||
start_time);
|
||||
auto ret = callback(strm);
|
||||
if (tls_error) { *tls_error = strm.tls_error(); }
|
||||
return ret;
|
||||
return callback(strm);
|
||||
}
|
||||
|
||||
inline std::pair<std::string, std::string> make_digest_authentication_header(
|
||||
@@ -15224,14 +15221,6 @@ inline bool ClientImpl::read_response_line(Stream &strm, const Request &req,
|
||||
|
||||
inline bool ClientImpl::send(Request &req, Response &res, Error &error) {
|
||||
std::lock_guard<std::recursive_mutex> request_mutex_guard(request_mutex_);
|
||||
#ifdef CPPHTTPLIB_SSL_ENABLED
|
||||
// Don't let an earlier request's TLS error show up in this one's Result. A
|
||||
// client that failed to set up its TLS context keeps reporting why.
|
||||
if (is_valid()) {
|
||||
last_ssl_error_ = 0;
|
||||
last_backend_error_ = 0;
|
||||
}
|
||||
#endif
|
||||
auto ret = send_(req, res, error);
|
||||
if (error == Error::SSLPeerCouldBeClosed_) {
|
||||
assert(!ret);
|
||||
@@ -15243,6 +15232,15 @@ inline bool ClientImpl::send(Request &req, Response &res, Error &error) {
|
||||
}
|
||||
|
||||
inline bool ClientImpl::send_(Request &req, Response &res, Error &error) {
|
||||
#ifdef CPPHTTPLIB_SSL_ENABLED
|
||||
// Don't let an earlier attempt's TLS error show up in this one's Result. A
|
||||
// client that failed to set up its TLS context keeps reporting why.
|
||||
if (is_valid()) {
|
||||
last_ssl_error_ = 0;
|
||||
last_backend_error_ = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(socket_mutex_);
|
||||
|
||||
@@ -15341,6 +15339,10 @@ inline Result ClientImpl::send(const Request &req) {
|
||||
inline Result ClientImpl::send_(Request &&req) {
|
||||
auto res = detail::make_unique<Response>();
|
||||
auto error = Error::Success;
|
||||
#ifdef CPPHTTPLIB_SSL_ENABLED
|
||||
// Hold the request lock until the Result has read this request's TLS error
|
||||
std::lock_guard<std::recursive_mutex> request_mutex_guard(request_mutex_);
|
||||
#endif
|
||||
auto ret = send(req, *res, error);
|
||||
#ifdef CPPHTTPLIB_SSL_ENABLED
|
||||
return Result{ret ? std::move(res) : nullptr, error, std::move(req.headers),
|
||||
@@ -16413,6 +16415,10 @@ inline Result ClientImpl::send_with_content_provider_and_receiver(
|
||||
|
||||
auto error = Error::Success;
|
||||
|
||||
#ifdef CPPHTTPLIB_SSL_ENABLED
|
||||
// Hold the request lock until the Result has read this request's TLS error
|
||||
std::lock_guard<std::recursive_mutex> request_mutex_guard(request_mutex_);
|
||||
#endif
|
||||
auto res = send_with_content_provider_and_receiver(
|
||||
req, body, content_length, std::move(content_provider),
|
||||
std::move(content_provider_without_length), content_type,
|
||||
@@ -18578,20 +18584,21 @@ inline bool SSLClient::process_socket(
|
||||
std::chrono::time_point<std::chrono::steady_clock> start_time,
|
||||
std::function<bool(Stream &strm)> callback) {
|
||||
assert(socket.ssl);
|
||||
tls::TlsError tls_error;
|
||||
auto ret = detail::process_client_socket_ssl(
|
||||
return detail::process_client_socket_ssl(
|
||||
socket.ssl, socket.sock, read_timeout_sec_, read_timeout_usec_,
|
||||
write_timeout_sec_, write_timeout_usec_, max_timeout_msec_, start_time,
|
||||
std::move(callback), &tls_error);
|
||||
|
||||
// A request that failed after the handshake reports Error::Read or
|
||||
// Error::Write; keep the TLS error behind it, such as a fatal alert from
|
||||
// the server, for Result::ssl_error() and ssl_backend_error()
|
||||
if (!ret && tls_error.code != tls::ErrorCode::Success) {
|
||||
last_ssl_error_ = static_cast<int>(tls_error.code);
|
||||
last_backend_error_ = tls_error.backend_code;
|
||||
}
|
||||
return ret;
|
||||
[&](detail::SSLSocketStream &strm) {
|
||||
auto ret = callback(strm);
|
||||
// A request that failed after the handshake reports Error::Read or
|
||||
// Error::Write; keep the TLS error behind it, such as a fatal alert
|
||||
// from the server, for Result::ssl_error() and ssl_backend_error()
|
||||
const auto &tls_error = strm.tls_error();
|
||||
if (!ret && tls_error.code != tls::ErrorCode::Success) {
|
||||
last_ssl_error_ = static_cast<int>(tls_error.code);
|
||||
last_backend_error_ = tls_error.backend_code;
|
||||
}
|
||||
return ret;
|
||||
});
|
||||
}
|
||||
|
||||
inline bool SSLClient::is_ssl() const { return true; }
|
||||
|
||||
Reference in new issue
Block a user