| Index: net/socket/client_socket_factory.cc
 | 
| diff --git a/net/socket/client_socket_factory.cc b/net/socket/client_socket_factory.cc
 | 
| index 42f6d4f20cebcf90c4d82d2c1be78d6d38ed099c..ade687454a99efa329aa354f086e5ab3cc5e87c7 100644
 | 
| --- a/net/socket/client_socket_factory.cc
 | 
| +++ b/net/socket/client_socket_factory.cc
 | 
| @@ -5,6 +5,8 @@
 | 
|  #include "net/socket/client_socket_factory.h"
 | 
|  
 | 
|  #include "base/lazy_instance.h"
 | 
| +#include "base/thread_task_runner_handle.h"
 | 
| +#include "base/threading/thread.h"
 | 
|  #include "build/build_config.h"
 | 
|  #include "net/base/cert_database.h"
 | 
|  #include "net/socket/client_socket_handle.h"
 | 
| @@ -31,14 +33,31 @@ namespace {
 | 
|  
 | 
|  bool g_use_system_ssl = false;
 | 
|  
 | 
| +// ChromeOS uses a hardware TPM module that may cause NSS operations to
 | 
| +// block for upwards of several seconds. To avoid blocking all network and
 | 
| +// IPC activity, run NSS SSL functions on a dedicated thread.
 | 
| +#if defined(OS_CHROMEOS)
 | 
| +bool g_use_dedicated_nss_thread = true;
 | 
| +#else
 | 
| +bool g_use_dedicated_nss_thread = false;
 | 
| +#endif
 | 
| +
 | 
|  class DefaultClientSocketFactory : public ClientSocketFactory,
 | 
|                                     public CertDatabase::Observer {
 | 
|   public:
 | 
|    DefaultClientSocketFactory() {
 | 
| +    if (g_use_dedicated_nss_thread) {
 | 
| +      nss_thread_.reset(new base::Thread("NSS SSL Thread"));
 | 
| +      if (nss_thread_->Start())
 | 
| +        nss_thread_task_runner_ = nss_thread_->message_loop_proxy();
 | 
| +    }
 | 
| +
 | 
|      CertDatabase::AddObserver(this);
 | 
|    }
 | 
|  
 | 
|    virtual ~DefaultClientSocketFactory() {
 | 
| +    // Note: This code never runs, as the factory is defined as a Leaky
 | 
| +    // singleton.
 | 
|      CertDatabase::RemoveObserver(this);
 | 
|    }
 | 
|  
 | 
| @@ -76,26 +95,43 @@ class DefaultClientSocketFactory : public ClientSocketFactory,
 | 
|        const SSLClientSocketContext& context) {
 | 
|      scoped_ptr<SSLHostInfo> shi(ssl_host_info);
 | 
|  
 | 
| -#if defined(OS_WIN)
 | 
| +    // nss_thread_task_runner_ may be NULL if g_use_dedicated_nss_thread is
 | 
| +    // false or if the dedicated NSS thread failed to start. If so, cause NSS
 | 
| +    // functions to execute on the current task runner.
 | 
| +    //
 | 
| +    // Note: The current task runner is obtained on each call due to unit
 | 
| +    // tests, which may create and tear down the current thread's TaskRunner
 | 
| +    // between each test. Because the DefaultClientSocketFactory is leaky, it
 | 
| +    // may span multiple tests, and thus the current task runner may change
 | 
| +    // from call to call.
 | 
| +    scoped_refptr<base::SingleThreadTaskRunner> nss_task_runner(
 | 
| +        nss_thread_task_runner_);
 | 
| +    if (!nss_task_runner)
 | 
| +      nss_task_runner = base::ThreadTaskRunnerHandle::Get();
 | 
| +
 | 
| +#if defined(USE_OPENSSL)
 | 
| +    return new SSLClientSocketOpenSSL(transport_socket, host_and_port,
 | 
| +                                      ssl_config, context);
 | 
| +#elif defined(USE_NSS)
 | 
| +    return new SSLClientSocketNSS(nss_task_runner, transport_socket,
 | 
| +                                  host_and_port, ssl_config, shi.release(),
 | 
| +                                  context);
 | 
| +#elif defined(OS_WIN)
 | 
|      if (g_use_system_ssl) {
 | 
|        return new SSLClientSocketWin(transport_socket, host_and_port,
 | 
|                                      ssl_config, context);
 | 
|      }
 | 
| -    return new SSLClientSocketNSS(transport_socket, host_and_port, ssl_config,
 | 
| -                                  shi.release(), context);
 | 
| -#elif defined(USE_OPENSSL)
 | 
| -    return new SSLClientSocketOpenSSL(transport_socket, host_and_port,
 | 
| -                                      ssl_config, context);
 | 
| -#elif defined(USE_NSS)
 | 
| -    return new SSLClientSocketNSS(transport_socket, host_and_port, ssl_config,
 | 
| -                                  shi.release(), context);
 | 
| +    return new SSLClientSocketNSS(nss_task_runner, transport_socket,
 | 
| +                                  host_and_port, ssl_config, shi.release(),
 | 
| +                                  context);
 | 
|  #elif defined(OS_MACOSX)
 | 
|      if (g_use_system_ssl) {
 | 
|        return new SSLClientSocketMac(transport_socket, host_and_port,
 | 
|                                      ssl_config, context);
 | 
|      }
 | 
| -    return new SSLClientSocketNSS(transport_socket, host_and_port, ssl_config,
 | 
| -                                  shi.release(), context);
 | 
| +    return new SSLClientSocketNSS(nss_task_runner, transport_socket,
 | 
| +                                  host_and_port, ssl_config, shi.release(),
 | 
| +                                  context);
 | 
|  #else
 | 
|      NOTIMPLEMENTED();
 | 
|      return NULL;
 | 
| @@ -106,9 +142,12 @@ class DefaultClientSocketFactory : public ClientSocketFactory,
 | 
|      SSLClientSocket::ClearSessionCache();
 | 
|    }
 | 
|  
 | 
| + private:
 | 
| +  scoped_ptr<base::Thread> nss_thread_;
 | 
| +  scoped_refptr<base::SingleThreadTaskRunner> nss_thread_task_runner_;
 | 
|  };
 | 
|  
 | 
| -static base::LazyInstance<DefaultClientSocketFactory>
 | 
| +static base::LazyInstance<DefaultClientSocketFactory>::Leaky
 | 
|      g_default_client_socket_factory = LAZY_INSTANCE_INITIALIZER;
 | 
|  
 | 
|  }  // namespace
 | 
| 
 |