Merge origin/master into claude/sweet-keller-2fba4t

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013wxevjmRqzpy8qDAD3vdwr
This commit is contained in:
Claude committed 2026-10-16 18:23:37 +00:00
commit 65dbca0afe
2 files changed
+69 -8

No files matched your search

+14 -8
View File
@@ -3454,11 +3454,13 @@ private:
std::function<SSLVerifierResponse(tls::session_t)> session_verifier_;
// The verifier given to set_server_certificate_verifier(), kept for the
// redirect client: ctx_ cannot report it back, and the backends keep it in
// a per-thread slot that any other client may overwrite.
tls::VerifyCallback server_certificate_verifier_;
#ifdef CPPHTTPLIB_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE
bool enable_windows_cert_verification_ = true;
// Like ca_cert_store_set_, tracks what ctx_ cannot report back: whether
// set_server_certificate_verifier() installed a verifier.
bool server_certificate_verifier_set_ = false;
#endif
friend class ClientImpl;
@@ -15948,6 +15950,11 @@ inline bool ClientImpl::create_redirect_client(
}
redirect_client.session_verifier_ = self.session_verifier_;
if (self.server_certificate_verifier_) {
redirect_client.set_server_certificate_verifier(
self.server_certificate_verifier_);
}
}
// Client certificates are set through constructor for SSLClient
@@ -18755,10 +18762,8 @@ inline void SSLClient::set_ca_cert_store(tls::ca_store_t ca_cert_store) {
inline void
SSLClient::set_server_certificate_verifier(tls::VerifyCallback verifier) {
if (!ctx_) { return; }
#ifdef CPPHTTPLIB_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE
server_certificate_verifier_set_ = static_cast<bool>(verifier);
#endif
tls::set_verify_callback(ctx_, verifier);
server_certificate_verifier_ = verifier;
tls::set_verify_callback(ctx_, std::move(verifier));
}
inline void SSLClient::set_session_verifier(
@@ -18821,7 +18826,8 @@ inline bool SSLClient::initialize_ssl(Socket &socket, Error &error) {
ca_cert_dir_path_.empty() && ca_cert_pem_.empty() && !ca_cert_store_set_;
// Only a verifier set through set_server_certificate_verifier() is seen
// here, not one installed with tls::set_verify_callback() directly.
options.server_certificate_verifier_set = server_certificate_verifier_set_;
options.server_certificate_verifier_set =
static_cast<bool>(server_certificate_verifier_);
#endif
tls::session_t session = nullptr;
+55
View File
@@ -16098,6 +16098,61 @@ TEST(SSLClientRedirectTest, SessionVerifier) {
EXPECT_EQ(Error::SSLServerVerification, res.error());
EXPECT_EQ(2, sessions.load());
}
// So must the verifier given to set_server_certificate_verifier().
TEST(SSLClientRedirectTest, ServerCertificateVerifier) {
auto ssl_port = PORT + 1;
std::atomic<bool> redirected{false};
SSLServer ssl_svr1(SERVER_CERT2_FILE, SERVER_PRIVATE_KEY_FILE);
ASSERT_TRUE(ssl_svr1.is_valid());
ssl_svr1.Get("/index", [&](const Request &, Response &res) {
redirected = true;
res.set_redirect("https://127.0.0.1:" + std::to_string(ssl_port) +
"/index");
});
SSLServer ssl_svr2(SERVER_CERT2_FILE, SERVER_PRIVATE_KEY_FILE);
ASSERT_TRUE(ssl_svr2.is_valid());
ssl_svr2.Get("/index", [&](const Request &, Response &res) {
res.set_content("test", "text/plain");
});
thread t = thread([&]() { ASSERT_TRUE(ssl_svr1.listen("127.0.0.1", PORT)); });
thread t2 =
thread([&]() { ASSERT_TRUE(ssl_svr2.listen("127.0.0.1", ssl_port)); });
auto se = detail::scope_exit([&] {
ssl_svr2.stop();
ssl_svr1.stop();
t2.join();
t.join();
ASSERT_FALSE(ssl_svr1.is_running());
});
ssl_svr1.wait_until_ready();
ssl_svr2.wait_until_ready();
SSLClient cli("127.0.0.1", PORT);
std::string cert;
read_file(SERVER_CERT2_FILE, cert);
cli.load_ca_cert_store(cert.c_str(), cert.size());
cli.enable_server_certificate_verification(true);
cli.set_follow_location(true);
cli.set_connection_timeout(30);
// Accept the host that redirects only; the verifier runs once per
// certificate in the chain, so count the calls made after the redirect.
std::atomic<int> calls_after_redirect{0};
cli.set_server_certificate_verifier([&](const tls::VerifyContext &) {
if (!redirected) { return true; }
calls_after_redirect++;
return false;
});
auto res = cli.Get("/index");
ASSERT_FALSE(res);
EXPECT_LT(0, calls_after_redirect.load());
}
#endif
#ifdef CPPHTTPLIB_SSL_ENABLED