@@ -814,23 +814,6 @@ static std::vector<X509*>& GetSystemStoreCACertificates() {
814814 return system_store_certs;
815815}
816816
817- static void LoadSystemCACertificates (void * data) {
818- GetSystemStoreCACertificates ();
819- }
820-
821- static uv_thread_t system_ca_thread;
822- static bool system_ca_thread_started = false ;
823- int LoadSystemCACertificatesOffThread () {
824- // This is only run once during the initialization of the process, so
825- // it is safe to use a static thread here.
826- int r =
827- uv_thread_create (&system_ca_thread, LoadSystemCACertificates, nullptr );
828- if (r == 0 ) {
829- system_ca_thread_started = true ;
830- }
831- return r;
832- }
833-
834817static std::vector<X509*> InitializeExtraCACertificates () {
835818 std::vector<X509*> extra_certs;
836819 unsigned long err = LoadCertsFromFile ( // NOLINT(runtime/int)
@@ -854,6 +837,53 @@ static std::vector<X509*>& GetExtraCACertificates() {
854837 return extra_certs;
855838}
856839
840+ static void LoadCACertificates (void * data) {
841+ per_process::Debug (DebugCategory::CRYPTO,
842+ " Started loading system root certificates off-thread\n " );
843+ GetSystemStoreCACertificates ();
844+ }
845+
846+ static std::atomic<bool > tried_cert_loading_off_thread = false ;
847+ static std::atomic<bool > cert_loading_thread_started = false ;
848+ static Mutex start_cert_loading_thread_mutex;
849+ static uv_thread_t cert_loading_thread;
850+
851+ void StartLoadingCertificatesOffThread (
852+ const FunctionCallbackInfo<Value>& args) {
853+ // Load the CA certificates eagerly off the main thread to avoid
854+ // blocking the main thread when the first TLS connection is made. We
855+ // don't need to wait for the thread to finish with code here, as
856+ // Get*CACertificates() functions has a function-local static and any
857+ // actual user of it will wait for that to complete initialization.
858+
859+ {
860+ Mutex::ScopedLock cli_lock (node::per_process::cli_options_mutex);
861+ if (!per_process::cli_options->use_system_ca ) {
862+ return ;
863+ }
864+ }
865+
866+ // Only try to start the thread once. If it ever fails, we won't try again.
867+ if (tried_cert_loading_off_thread.load ()) {
868+ return ;
869+ }
870+ {
871+ Mutex::ScopedLock lock (start_cert_loading_thread_mutex);
872+ // Re-check under the lock.
873+ if (tried_cert_loading_off_thread.load ()) {
874+ return ;
875+ }
876+ tried_cert_loading_off_thread.store (true );
877+ int r = uv_thread_create (&cert_loading_thread, LoadCACertificates, nullptr );
878+ cert_loading_thread_started.store (r == 0 );
879+ if (r != 0 ) {
880+ FPrintF (stderr,
881+ " Warning: Failed to load CA certificates off thread: %s\n " ,
882+ uv_strerror (r));
883+ }
884+ }
885+ }
886+
857887// Due to historical reasons the various options of CA certificates
858888// may invalid one another. The current rule is:
859889// 1. If the configure-time option --openssl-use-def-ca-store is NOT used
@@ -942,9 +972,12 @@ void CleanupCachedRootCertificates() {
942972 X509_free (cert);
943973 }
944974 }
945- if (system_ca_thread_started) {
946- uv_thread_join (&system_ca_thread);
947- system_ca_thread_started = false ;
975+
976+ // Serialize with starter to avoid the race window.
977+ Mutex::ScopedLock lock (start_cert_loading_thread_mutex);
978+ if (tried_cert_loading_off_thread.load () &&
979+ cert_loading_thread_started.load ()) {
980+ uv_thread_join (&cert_loading_thread);
948981 }
949982}
950983
@@ -1233,6 +1266,10 @@ void SecureContext::Initialize(Environment* env, Local<Object> target) {
12331266 SetMethod (context, target, " resetRootCertStore" , ResetRootCertStore);
12341267 SetMethodNoSideEffect (
12351268 context, target, " getUserRootCertificates" , GetUserRootCertificates);
1269+ SetMethod (context,
1270+ target,
1271+ " startLoadingCertificatesOffThread" ,
1272+ StartLoadingCertificatesOffThread);
12361273}
12371274
12381275void SecureContext::RegisterExternalReferences (
@@ -1277,6 +1314,7 @@ void SecureContext::RegisterExternalReferences(
12771314 registry->Register (GetExtraCACertificates);
12781315 registry->Register (ResetRootCertStore);
12791316 registry->Register (GetUserRootCertificates);
1317+ registry->Register (StartLoadingCertificatesOffThread);
12801318}
12811319
12821320SecureContext* SecureContext::Create (Environment* env) {
0 commit comments