Let WebSocketClient take a CA directory the way ClientImpl does

WebSocketClient::set_ca_cert_path took a single path and create_stream()
hardcoded an empty directory when calling detail::load_client_ca_config, while
ClientImpl has always accepted (ca_cert_file_path, ca_cert_dir_path = ""). Give
WebSocketClient the same signature and store the directory, so both clients
configure CA loading identically. The one-argument form is unchanged for
callers.

Also note at both call sites why the "load the CA config once" guard differs:
SSLClient needs call_once because one client serves concurrent requests, and
WebSocketClient does not because connect() is not safe to call concurrently
anyway.
This commit is contained in:
yhirose
2026-08-07 13:41:38 -04:00
parent a1aa2ad9cd
commit d2ef193b9c
3 changed files with 44 additions and 7 deletions
+22
View File
@@ -20958,6 +20958,28 @@ TEST_F(WebSocketSSLCATest, WrongCustomCaFailsVerification) {
ASSERT_FALSE(client.connect());
}
// The same CA as a file path rather than PEM in memory
TEST_F(WebSocketSSLCATest, SetCaCertPathVerifiesServer) {
ws::WebSocketClient client(url());
client.set_ca_cert_path(SERVER_CERT2_FILE);
ASSERT_TRUE(client.connect());
ASSERT_TRUE(client.send("hello"));
std::string msg;
EXPECT_EQ(ws::Text, client.read(msg));
EXPECT_EQ("hello", msg);
client.close();
}
// ...and a CA file that does not cover the server still fails, so it is the
// path above that decides the outcome
TEST_F(WebSocketSSLCATest, WrongCaCertPathFailsVerification) {
ws::WebSocketClient client(url());
client.set_ca_cert_path(CLIENT_CA_CERT_FILE);
ASSERT_FALSE(client.connect());
}
// Regression test: reconnecting with a native custom CA store used to reuse
// a store handle the previous TLS context had already freed (use-after-free
// under the OpenSSL backend). The context now lives as long as the client.