mirror of
https://github.com/yhirose/cpp-httplib.git
synced 2026-10-19 11:19:36 +00:00
Keep the TLS error behind a failed read or write in the client's Result
A request that fails after the TLS handshake reports Error::Read or Error::Write, and SSLSocketStream dropped the TLS error behind it. On TLS 1.3, where a server rejects a client without a certificate only after the handshake, ssl_error() and ssl_backend_error() were 0 instead of showing, for example, OpenSSL's "tlsv13 alert certificate required". SSLSocketStream now keeps the error from its last failed TLS read or write, and SSLClient copies it into the values Result reports. Error itself stays Read or Write. Those values are also reset at the start of each request, so a later successful request no longer reports the TLS error of an earlier one. A client whose TLS context failed to set up keeps reporting that error. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WGAYpQgXt95LdDQcJYgjB8
This commit is contained in:
2 files changed
+73
-5
No files matched your search
@@ -14612,6 +14612,8 @@ void ClientCertMissing(const ClientCertServerSetup &setup = nullptr) {
|
||||
if (res.error() == Error::SSLConnection) {
|
||||
EXPECT_NE(0UL, res.ssl_backend_error());
|
||||
}
|
||||
// A rejection noticed on the write keeps the TLS error the write hit
|
||||
if (res.error() == Error::Write) { EXPECT_NE(0, res.ssl_error()); }
|
||||
}
|
||||
|
||||
TEST(SSLClientServerTest, ClientCertMissing) { ClientCertMissing(); }
|
||||
@@ -14639,6 +14641,39 @@ TEST(SSLClientServerTest, ClientCertStillRequiredAfterVerifyCallbackCleared) {
|
||||
ClientCertStillRequired(true);
|
||||
}
|
||||
|
||||
// A TLS error from one request must not show up in a later request's Result
|
||||
TEST(SSLClientServerTest, SSLErrorNotCarriedToLaterRequest) {
|
||||
SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE);
|
||||
ASSERT_TRUE(svr.is_valid());
|
||||
svr.Get("/test", [](const Request &, Response &res) {
|
||||
res.set_content("test", "text/plain");
|
||||
});
|
||||
|
||||
auto port = svr.bind_to_any_port(HOST);
|
||||
ASSERT_LT(0, port);
|
||||
thread t = thread([&]() { svr.listen_after_bind(); });
|
||||
auto se = detail::scope_exit([&] {
|
||||
svr.stop();
|
||||
t.join();
|
||||
ASSERT_FALSE(svr.is_running());
|
||||
});
|
||||
|
||||
svr.wait_until_ready();
|
||||
|
||||
SSLClient cli(HOST, port);
|
||||
cli.set_connection_timeout(30);
|
||||
cli.enable_server_hostname_verification(false);
|
||||
|
||||
// cert.pem is not trusted, so the handshake fails
|
||||
ASSERT_FALSE(cli.Get("/test"));
|
||||
|
||||
cli.enable_server_certificate_verification(false);
|
||||
auto res = cli.Get("/test");
|
||||
ASSERT_TRUE(res) << "Error: " << to_string(res.error());
|
||||
EXPECT_EQ(0, res.ssl_error());
|
||||
EXPECT_EQ(0UL, res.ssl_backend_error());
|
||||
}
|
||||
|
||||
// PEM memory-based constructor tests (works with all TLS backends)
|
||||
void PemMemoryClientCertPresent(
|
||||
const std::string &client_cert_file,
|
||||
|
||||
Reference in new issue
Block a user