Home | History | Annotate | Download | only in browser
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/io_thread.h"
      6 
      7 #include <vector>
      8 
      9 #include "base/bind.h"
     10 #include "base/bind_helpers.h"
     11 #include "base/command_line.h"
     12 #include "base/compiler_specific.h"
     13 #include "base/debug/leak_tracker.h"
     14 #include "base/debug/trace_event.h"
     15 #include "base/logging.h"
     16 #include "base/metrics/field_trial.h"
     17 #include "base/prefs/pref_registry_simple.h"
     18 #include "base/prefs/pref_service.h"
     19 #include "base/stl_util.h"
     20 #include "base/strings/string_number_conversions.h"
     21 #include "base/strings/string_split.h"
     22 #include "base/strings/string_util.h"
     23 #include "base/threading/thread.h"
     24 #include "base/threading/worker_pool.h"
     25 #include "base/time/default_tick_clock.h"
     26 #include "build/build_config.h"
     27 #include "chrome/browser/browser_process.h"
     28 #include "chrome/browser/extensions/event_router_forwarder.h"
     29 #include "chrome/browser/net/async_dns_field_trial.h"
     30 #include "chrome/browser/net/basic_http_user_agent_settings.h"
     31 #include "chrome/browser/net/chrome_net_log.h"
     32 #include "chrome/browser/net/chrome_network_delegate.h"
     33 #include "chrome/browser/net/chrome_url_request_context.h"
     34 #include "chrome/browser/net/connect_interceptor.h"
     35 #include "chrome/browser/net/dns_probe_service.h"
     36 #include "chrome/browser/net/http_pipelining_compatibility_client.h"
     37 #include "chrome/browser/net/load_time_stats.h"
     38 #include "chrome/browser/net/pref_proxy_config_tracker.h"
     39 #include "chrome/browser/net/proxy_service_factory.h"
     40 #include "chrome/browser/net/sdch_dictionary_fetcher.h"
     41 #include "chrome/browser/net/spdyproxy/http_auth_handler_spdyproxy.h"
     42 #include "chrome/browser/policy/policy_service.h"
     43 #include "chrome/common/chrome_switches.h"
     44 #include "chrome/common/pref_names.h"
     45 #include "chrome/common/url_constants.h"
     46 #include "content/public/browser/browser_thread.h"
     47 #include "net/base/host_mapping_rules.h"
     48 #include "net/base/net_util.h"
     49 #include "net/base/network_time_notifier.h"
     50 #include "net/base/sdch_manager.h"
     51 #include "net/cert/cert_verifier.h"
     52 #include "net/cookies/cookie_monster.h"
     53 #include "net/dns/host_cache.h"
     54 #include "net/dns/host_resolver.h"
     55 #include "net/dns/mapped_host_resolver.h"
     56 #include "net/ftp/ftp_network_layer.h"
     57 #include "net/http/http_auth_filter.h"
     58 #include "net/http/http_auth_handler_factory.h"
     59 #include "net/http/http_network_layer.h"
     60 #include "net/http/http_server_properties_impl.h"
     61 #include "net/proxy/proxy_config_service.h"
     62 #include "net/proxy/proxy_script_fetcher_impl.h"
     63 #include "net/proxy/proxy_service.h"
     64 #include "net/socket/tcp_client_socket.h"
     65 #include "net/spdy/spdy_session.h"
     66 #include "net/ssl/default_server_bound_cert_store.h"
     67 #include "net/ssl/server_bound_cert_service.h"
     68 #include "net/url_request/data_protocol_handler.h"
     69 #include "net/url_request/file_protocol_handler.h"
     70 #include "net/url_request/ftp_protocol_handler.h"
     71 #include "net/url_request/url_fetcher.h"
     72 #include "net/url_request/url_request_job_factory_impl.h"
     73 #include "net/url_request/url_request_throttler_manager.h"
     74 #include "net/websockets/websocket_job.h"
     75 
     76 #if defined(OS_WIN)
     77 #include "win8/util/win8_util.h"
     78 #endif
     79 
     80 #if defined(ENABLE_CONFIGURATION_POLICY)
     81 #include "policy/policy_constants.h"
     82 #endif
     83 
     84 #if defined(USE_NSS) || defined(OS_IOS)
     85 #include "net/ocsp/nss_ocsp.h"
     86 #endif
     87 
     88 #if !defined(OS_IOS) && !defined(OS_ANDROID)
     89 #include "net/proxy/proxy_resolver_v8.h"
     90 #endif
     91 
     92 using content::BrowserThread;
     93 
     94 class SafeBrowsingURLRequestContext;
     95 
     96 // The IOThread object must outlive any tasks posted to the IO thread before the
     97 // Quit task, so base::Bind() calls are not refcounted.
     98 
     99 namespace {
    100 
    101 const char kQuicFieldTrialName[] = "QUIC";
    102 const char kQuicFieldTrialEnabledGroupName[] = "Enabled";
    103 const char kQuicFieldTrialHttpsEnabledGroupName[] = "HttpsEnabled";
    104 
    105 #if defined(OS_MACOSX) && !defined(OS_IOS)
    106 void ObserveKeychainEvents() {
    107   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    108   net::CertDatabase::GetInstance()->SetMessageLoopForKeychainEvents();
    109 }
    110 #endif
    111 
    112 // Used for the "system" URLRequestContext.
    113 class SystemURLRequestContext : public net::URLRequestContext {
    114  public:
    115   SystemURLRequestContext() {
    116 #if defined(USE_NSS) || defined(OS_IOS)
    117     net::SetURLRequestContextForNSSHttpIO(this);
    118 #endif
    119   }
    120 
    121  private:
    122   virtual ~SystemURLRequestContext() {
    123 #if defined(USE_NSS) || defined(OS_IOS)
    124     net::SetURLRequestContextForNSSHttpIO(NULL);
    125 #endif
    126   }
    127 };
    128 
    129 scoped_ptr<net::HostResolver> CreateGlobalHostResolver(net::NetLog* net_log) {
    130   TRACE_EVENT0("startup", "IOThread::CreateGlobalHostResolver");
    131   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
    132 
    133   net::HostResolver::Options options;
    134 
    135   // Use the concurrency override from the command-line, if any.
    136   if (command_line.HasSwitch(switches::kHostResolverParallelism)) {
    137     std::string s =
    138         command_line.GetSwitchValueASCII(switches::kHostResolverParallelism);
    139 
    140     // Parse the switch (it should be a positive integer formatted as decimal).
    141     int n;
    142     if (base::StringToInt(s, &n) && n > 0) {
    143       options.max_concurrent_resolves = static_cast<size_t>(n);
    144     } else {
    145       LOG(ERROR) << "Invalid switch for host resolver parallelism: " << s;
    146     }
    147   }
    148 
    149   // Use the retry attempts override from the command-line, if any.
    150   if (command_line.HasSwitch(switches::kHostResolverRetryAttempts)) {
    151     std::string s =
    152         command_line.GetSwitchValueASCII(switches::kHostResolverRetryAttempts);
    153     // Parse the switch (it should be a non-negative integer).
    154     int n;
    155     if (base::StringToInt(s, &n) && n >= 0) {
    156       options.max_retry_attempts = static_cast<size_t>(n);
    157     } else {
    158       LOG(ERROR) << "Invalid switch for host resolver retry attempts: " << s;
    159     }
    160   }
    161 
    162   scoped_ptr<net::HostResolver> global_host_resolver(
    163       net::HostResolver::CreateSystemResolver(options, net_log));
    164 
    165   // Determine if we should disable IPv6 support.
    166   if (command_line.HasSwitch(switches::kEnableIPv6)) {
    167     // Disable IPv6 probing.
    168     global_host_resolver->SetDefaultAddressFamily(
    169         net::ADDRESS_FAMILY_UNSPECIFIED);
    170   } else if (command_line.HasSwitch(switches::kDisableIPv6)) {
    171     global_host_resolver->SetDefaultAddressFamily(net::ADDRESS_FAMILY_IPV4);
    172   }
    173 
    174   // If hostname remappings were specified on the command-line, layer these
    175   // rules on top of the real host resolver. This allows forwarding all requests
    176   // through a designated test server.
    177   if (!command_line.HasSwitch(switches::kHostResolverRules))
    178     return global_host_resolver.PassAs<net::HostResolver>();
    179 
    180   scoped_ptr<net::MappedHostResolver> remapped_resolver(
    181       new net::MappedHostResolver(global_host_resolver.Pass()));
    182   remapped_resolver->SetRulesFromString(
    183       command_line.GetSwitchValueASCII(switches::kHostResolverRules));
    184   return remapped_resolver.PassAs<net::HostResolver>();
    185 }
    186 
    187 // TODO(willchan): Remove proxy script fetcher context since it's not necessary
    188 // now that I got rid of refcounting URLRequestContexts.
    189 // See IOThread::Globals for details.
    190 net::URLRequestContext*
    191 ConstructProxyScriptFetcherContext(IOThread::Globals* globals,
    192                                    net::NetLog* net_log) {
    193   net::URLRequestContext* context = new net::URLRequestContext;
    194   context->set_net_log(net_log);
    195   context->set_host_resolver(globals->host_resolver.get());
    196   context->set_cert_verifier(globals->cert_verifier.get());
    197   context->set_transport_security_state(
    198       globals->transport_security_state.get());
    199   context->set_http_auth_handler_factory(
    200       globals->http_auth_handler_factory.get());
    201   context->set_proxy_service(globals->proxy_script_fetcher_proxy_service.get());
    202   context->set_http_transaction_factory(
    203       globals->proxy_script_fetcher_http_transaction_factory.get());
    204   context->set_job_factory(
    205       globals->proxy_script_fetcher_url_request_job_factory.get());
    206   context->set_cookie_store(globals->system_cookie_store.get());
    207   context->set_server_bound_cert_service(
    208       globals->system_server_bound_cert_service.get());
    209   context->set_network_delegate(globals->system_network_delegate.get());
    210   context->set_http_user_agent_settings(
    211       globals->http_user_agent_settings.get());
    212   // TODO(rtenneti): We should probably use HttpServerPropertiesManager for the
    213   // system URLRequestContext too. There's no reason this should be tied to a
    214   // profile.
    215   return context;
    216 }
    217 
    218 net::URLRequestContext*
    219 ConstructSystemRequestContext(IOThread::Globals* globals,
    220                               net::NetLog* net_log) {
    221   net::URLRequestContext* context = new SystemURLRequestContext;
    222   context->set_net_log(net_log);
    223   context->set_host_resolver(globals->host_resolver.get());
    224   context->set_cert_verifier(globals->cert_verifier.get());
    225   context->set_transport_security_state(
    226       globals->transport_security_state.get());
    227   context->set_http_auth_handler_factory(
    228       globals->http_auth_handler_factory.get());
    229   context->set_proxy_service(globals->system_proxy_service.get());
    230   context->set_http_transaction_factory(
    231       globals->system_http_transaction_factory.get());
    232   context->set_cookie_store(globals->system_cookie_store.get());
    233   context->set_server_bound_cert_service(
    234       globals->system_server_bound_cert_service.get());
    235   context->set_throttler_manager(globals->throttler_manager.get());
    236   context->set_network_delegate(globals->system_network_delegate.get());
    237   context->set_http_user_agent_settings(
    238       globals->http_user_agent_settings.get());
    239   return context;
    240 }
    241 
    242 int GetSwitchValueAsInt(const CommandLine& command_line,
    243                         const std::string& switch_name) {
    244   int value;
    245   if (!base::StringToInt(command_line.GetSwitchValueASCII(switch_name),
    246                          &value)) {
    247     return 0;
    248   }
    249   return value;
    250 }
    251 
    252 }  // namespace
    253 
    254 class IOThread::LoggingNetworkChangeObserver
    255     : public net::NetworkChangeNotifier::IPAddressObserver,
    256       public net::NetworkChangeNotifier::ConnectionTypeObserver,
    257       public net::NetworkChangeNotifier::NetworkChangeObserver {
    258  public:
    259   // |net_log| must remain valid throughout our lifetime.
    260   explicit LoggingNetworkChangeObserver(net::NetLog* net_log)
    261       : net_log_(net_log) {
    262     net::NetworkChangeNotifier::AddIPAddressObserver(this);
    263     net::NetworkChangeNotifier::AddConnectionTypeObserver(this);
    264     net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
    265   }
    266 
    267   virtual ~LoggingNetworkChangeObserver() {
    268     net::NetworkChangeNotifier::RemoveIPAddressObserver(this);
    269     net::NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
    270     net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
    271   }
    272 
    273   // NetworkChangeNotifier::IPAddressObserver implementation.
    274   virtual void OnIPAddressChanged() OVERRIDE {
    275     VLOG(1) << "Observed a change to the network IP addresses";
    276 
    277     net_log_->AddGlobalEntry(net::NetLog::TYPE_NETWORK_IP_ADDRESSES_CHANGED);
    278   }
    279 
    280   // NetworkChangeNotifier::ConnectionTypeObserver implementation.
    281   virtual void OnConnectionTypeChanged(
    282       net::NetworkChangeNotifier::ConnectionType type) OVERRIDE {
    283     std::string type_as_string =
    284         net::NetworkChangeNotifier::ConnectionTypeToString(type);
    285 
    286     VLOG(1) << "Observed a change to network connectivity state "
    287             << type_as_string;
    288 
    289     net_log_->AddGlobalEntry(
    290         net::NetLog::TYPE_NETWORK_CONNECTIVITY_CHANGED,
    291         net::NetLog::StringCallback("new_connection_type", &type_as_string));
    292   }
    293 
    294   // NetworkChangeNotifier::NetworkChangeObserver implementation.
    295   virtual void OnNetworkChanged(
    296       net::NetworkChangeNotifier::ConnectionType type) OVERRIDE {
    297     std::string type_as_string =
    298         net::NetworkChangeNotifier::ConnectionTypeToString(type);
    299 
    300     VLOG(1) << "Observed a network change to state " << type_as_string;
    301 
    302     net_log_->AddGlobalEntry(
    303         net::NetLog::TYPE_NETWORK_CHANGED,
    304         net::NetLog::StringCallback("new_connection_type", &type_as_string));
    305   }
    306 
    307  private:
    308   net::NetLog* net_log_;
    309   DISALLOW_COPY_AND_ASSIGN(LoggingNetworkChangeObserver);
    310 };
    311 
    312 class SystemURLRequestContextGetter : public net::URLRequestContextGetter {
    313  public:
    314   explicit SystemURLRequestContextGetter(IOThread* io_thread);
    315 
    316   // Implementation for net::UrlRequestContextGetter.
    317   virtual net::URLRequestContext* GetURLRequestContext() OVERRIDE;
    318   virtual scoped_refptr<base::SingleThreadTaskRunner>
    319       GetNetworkTaskRunner() const OVERRIDE;
    320 
    321  protected:
    322   virtual ~SystemURLRequestContextGetter();
    323 
    324  private:
    325   IOThread* const io_thread_;  // Weak pointer, owned by BrowserProcess.
    326   scoped_refptr<base::SingleThreadTaskRunner> network_task_runner_;
    327 
    328   base::debug::LeakTracker<SystemURLRequestContextGetter> leak_tracker_;
    329 };
    330 
    331 SystemURLRequestContextGetter::SystemURLRequestContextGetter(
    332     IOThread* io_thread)
    333     : io_thread_(io_thread),
    334       network_task_runner_(
    335           BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO)) {
    336 }
    337 
    338 SystemURLRequestContextGetter::~SystemURLRequestContextGetter() {}
    339 
    340 net::URLRequestContext* SystemURLRequestContextGetter::GetURLRequestContext() {
    341   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    342   DCHECK(io_thread_->globals()->system_request_context.get());
    343 
    344   return io_thread_->globals()->system_request_context.get();
    345 }
    346 
    347 scoped_refptr<base::SingleThreadTaskRunner>
    348 SystemURLRequestContextGetter::GetNetworkTaskRunner() const {
    349   return network_task_runner_;
    350 }
    351 
    352 IOThread::Globals::
    353 SystemRequestContextLeakChecker::SystemRequestContextLeakChecker(
    354     Globals* globals)
    355     : globals_(globals) {
    356   DCHECK(globals_);
    357 }
    358 
    359 IOThread::Globals::
    360 SystemRequestContextLeakChecker::~SystemRequestContextLeakChecker() {
    361   if (globals_->system_request_context.get())
    362     globals_->system_request_context->AssertNoURLRequests();
    363 }
    364 
    365 IOThread::Globals::Globals()
    366     : system_request_context_leak_checker(this),
    367       ignore_certificate_errors(false),
    368       http_pipelining_enabled(false),
    369       testing_fixed_http_port(0),
    370       testing_fixed_https_port(0),
    371       enable_user_alternate_protocol_ports(false) {
    372 }
    373 
    374 IOThread::Globals::~Globals() {}
    375 
    376 // |local_state| is passed in explicitly in order to (1) reduce implicit
    377 // dependencies and (2) make IOThread more flexible for testing.
    378 IOThread::IOThread(
    379     PrefService* local_state,
    380     policy::PolicyService* policy_service,
    381     ChromeNetLog* net_log,
    382     extensions::EventRouterForwarder* extension_event_router_forwarder)
    383     : net_log_(net_log),
    384       extension_event_router_forwarder_(extension_event_router_forwarder),
    385       globals_(NULL),
    386       sdch_manager_(NULL),
    387       is_spdy_disabled_by_policy_(false),
    388       weak_factory_(this) {
    389 #if !defined(OS_IOS) && !defined(OS_ANDROID)
    390 #if defined(OS_WIN)
    391   if (!win8::IsSingleWindowMetroMode())
    392     net::ProxyResolverV8::RememberDefaultIsolate();
    393   else
    394     net::ProxyResolverV8::CreateIsolate();
    395 #else
    396   net::ProxyResolverV8::RememberDefaultIsolate();
    397 #endif
    398 #endif
    399   auth_schemes_ = local_state->GetString(prefs::kAuthSchemes);
    400   negotiate_disable_cname_lookup_ = local_state->GetBoolean(
    401       prefs::kDisableAuthNegotiateCnameLookup);
    402   negotiate_enable_port_ = local_state->GetBoolean(
    403       prefs::kEnableAuthNegotiatePort);
    404   auth_server_whitelist_ = local_state->GetString(prefs::kAuthServerWhitelist);
    405   auth_delegate_whitelist_ = local_state->GetString(
    406       prefs::kAuthNegotiateDelegateWhitelist);
    407   gssapi_library_name_ = local_state->GetString(prefs::kGSSAPILibraryName);
    408   pref_proxy_config_tracker_.reset(
    409       ProxyServiceFactory::CreatePrefProxyConfigTrackerOfLocalState(
    410           local_state));
    411   ChromeNetworkDelegate::InitializePrefsOnUIThread(
    412       &system_enable_referrers_,
    413       NULL,
    414       NULL,
    415       local_state);
    416   ssl_config_service_manager_.reset(
    417       SSLConfigServiceManager::CreateDefaultManager(local_state));
    418 
    419   base::Value* dns_client_enabled_default = new base::FundamentalValue(
    420       chrome_browser_net::ConfigureAsyncDnsFieldTrial());
    421   local_state->SetDefaultPrefValue(prefs::kBuiltInDnsClientEnabled,
    422                                    dns_client_enabled_default);
    423 
    424   dns_client_enabled_.Init(prefs::kBuiltInDnsClientEnabled,
    425                            local_state,
    426                            base::Bind(&IOThread::UpdateDnsClientEnabled,
    427                                       base::Unretained(this)));
    428   dns_client_enabled_.MoveToThread(
    429       BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO));
    430 
    431 #if defined(ENABLE_CONFIGURATION_POLICY)
    432   is_spdy_disabled_by_policy_ = policy_service->GetPolicies(
    433       policy::PolicyNamespace(policy::POLICY_DOMAIN_CHROME, std::string())).Get(
    434           policy::key::kDisableSpdy) != NULL;
    435 #endif  // ENABLE_CONFIGURATION_POLICY
    436 
    437   BrowserThread::SetDelegate(BrowserThread::IO, this);
    438 }
    439 
    440 IOThread::~IOThread() {
    441   // This isn't needed for production code, but in tests, IOThread may
    442   // be multiply constructed.
    443   BrowserThread::SetDelegate(BrowserThread::IO, NULL);
    444 
    445   pref_proxy_config_tracker_->DetachFromPrefService();
    446   DCHECK(!globals_);
    447 }
    448 
    449 IOThread::Globals* IOThread::globals() {
    450   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    451   return globals_;
    452 }
    453 
    454 void IOThread::SetGlobalsForTesting(Globals* globals) {
    455   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    456   DCHECK(!globals || !globals_);
    457   globals_ = globals;
    458 }
    459 
    460 ChromeNetLog* IOThread::net_log() {
    461   return net_log_;
    462 }
    463 
    464 void IOThread::ChangedToOnTheRecord() {
    465   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    466   BrowserThread::PostTask(
    467       BrowserThread::IO,
    468       FROM_HERE,
    469       base::Bind(&IOThread::ChangedToOnTheRecordOnIOThread,
    470                  base::Unretained(this)));
    471 }
    472 
    473 net::URLRequestContextGetter* IOThread::system_url_request_context_getter() {
    474   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    475   if (!system_url_request_context_getter_.get()) {
    476     InitSystemRequestContext();
    477   }
    478   return system_url_request_context_getter_.get();
    479 }
    480 
    481 void IOThread::Init() {
    482   // Prefer to use InitAsync unless you need initialization to block
    483   // the UI thread
    484 }
    485 
    486 void IOThread::InitAsync() {
    487   TRACE_EVENT0("startup", "IOThread::InitAsync");
    488   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    489 
    490 #if defined(USE_NSS) || defined(OS_IOS)
    491   net::SetMessageLoopForNSSHttpIO();
    492 #endif
    493 
    494   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
    495 
    496   DCHECK(!globals_);
    497   globals_ = new Globals;
    498 
    499   // Add an observer that will emit network change events to the ChromeNetLog.
    500   // Assuming NetworkChangeNotifier dispatches in FIFO order, we should be
    501   // logging the network change before other IO thread consumers respond to it.
    502   network_change_observer_.reset(
    503       new LoggingNetworkChangeObserver(net_log_));
    504 
    505   // Setup the HistogramWatcher to run on the IO thread.
    506   net::NetworkChangeNotifier::InitHistogramWatcher();
    507 
    508   globals_->extension_event_router_forwarder =
    509       extension_event_router_forwarder_;
    510   ChromeNetworkDelegate* network_delegate =
    511       new ChromeNetworkDelegate(extension_event_router_forwarder_,
    512                                 &system_enable_referrers_);
    513   if (command_line.HasSwitch(switches::kDisableExtensionsHttpThrottling))
    514     network_delegate->NeverThrottleRequests();
    515   globals_->system_network_delegate.reset(network_delegate);
    516   globals_->host_resolver = CreateGlobalHostResolver(net_log_);
    517   UpdateDnsClientEnabled();
    518   globals_->cert_verifier.reset(net::CertVerifier::CreateDefault());
    519   globals_->transport_security_state.reset(new net::TransportSecurityState());
    520   globals_->ssl_config_service = GetSSLConfigService();
    521   if (command_line.HasSwitch(switches::kSpdyProxyAuthOrigin)) {
    522     spdyproxy_auth_origin_ =
    523         command_line.GetSwitchValueASCII(switches::kSpdyProxyAuthOrigin);
    524   } else {
    525 #if defined(SPDY_PROXY_AUTH_ORIGIN)
    526     spdyproxy_auth_origin_ = SPDY_PROXY_AUTH_ORIGIN;
    527 #endif
    528   }
    529   globals_->http_auth_handler_factory.reset(CreateDefaultAuthHandlerFactory(
    530       globals_->host_resolver.get()));
    531   globals_->http_server_properties.reset(new net::HttpServerPropertiesImpl());
    532   // For the ProxyScriptFetcher, we use a direct ProxyService.
    533   globals_->proxy_script_fetcher_proxy_service.reset(
    534       net::ProxyService::CreateDirectWithNetLog(net_log_));
    535   // In-memory cookie store.
    536   globals_->system_cookie_store = new net::CookieMonster(NULL, NULL);
    537   // In-memory server bound cert store.
    538   globals_->system_server_bound_cert_service.reset(
    539       new net::ServerBoundCertService(
    540           new net::DefaultServerBoundCertStore(NULL),
    541           base::WorkerPool::GetTaskRunner(true)));
    542   globals_->dns_probe_service.reset(new chrome_browser_net::DnsProbeService());
    543   globals_->load_time_stats.reset(new chrome_browser_net::LoadTimeStats());
    544   globals_->host_mapping_rules.reset(new net::HostMappingRules());
    545   globals_->http_user_agent_settings.reset(
    546       new BasicHttpUserAgentSettings(std::string()));
    547   if (command_line.HasSwitch(switches::kHostRules)) {
    548     TRACE_EVENT_BEGIN0("startup", "IOThread::InitAsync:SetRulesFromString");
    549     globals_->host_mapping_rules->SetRulesFromString(
    550         command_line.GetSwitchValueASCII(switches::kHostRules));
    551     TRACE_EVENT_END0("startup", "IOThread::InitAsync:SetRulesFromString");
    552   }
    553   if (command_line.HasSwitch(switches::kIgnoreCertificateErrors))
    554     globals_->ignore_certificate_errors = true;
    555   if (command_line.HasSwitch(switches::kTestingFixedHttpPort)) {
    556     globals_->testing_fixed_http_port =
    557         GetSwitchValueAsInt(command_line, switches::kTestingFixedHttpPort);
    558   }
    559   if (command_line.HasSwitch(switches::kTestingFixedHttpsPort)) {
    560     globals_->testing_fixed_https_port =
    561         GetSwitchValueAsInt(command_line, switches::kTestingFixedHttpsPort);
    562   }
    563   bool enable_quic = ShouldEnableQuic(command_line);
    564   globals_->enable_quic.set(enable_quic);
    565   if (enable_quic)
    566     globals_->enable_quic_https.set(ShouldEnableQuicHttps(command_line));
    567   if (command_line.HasSwitch(switches::kOriginToForceQuicOn)) {
    568     net::HostPortPair quic_origin =
    569         net::HostPortPair::FromString(
    570             command_line.GetSwitchValueASCII(switches::kOriginToForceQuicOn));
    571     if (!quic_origin.IsEmpty()) {
    572       globals_->origin_to_force_quic_on.set(quic_origin);
    573     }
    574   }
    575   if (command_line.HasSwitch(
    576           switches::kEnableUserAlternateProtocolPorts)) {
    577     globals_->enable_user_alternate_protocol_ports = true;
    578   }
    579   InitializeNetworkOptions(command_line);
    580 
    581   net::HttpNetworkSession::Params session_params;
    582   InitializeNetworkSessionParams(&session_params);
    583   session_params.net_log = net_log_;
    584   session_params.proxy_service =
    585       globals_->proxy_script_fetcher_proxy_service.get();
    586 
    587   TRACE_EVENT_BEGIN0("startup", "IOThread::InitAsync:HttpNetworkSession");
    588   scoped_refptr<net::HttpNetworkSession> network_session(
    589       new net::HttpNetworkSession(session_params));
    590   globals_->proxy_script_fetcher_http_transaction_factory
    591       .reset(new net::HttpNetworkLayer(network_session.get()));
    592   TRACE_EVENT_END0("startup", "IOThread::InitAsync:HttpNetworkSession");
    593   scoped_ptr<net::URLRequestJobFactoryImpl> job_factory(
    594       new net::URLRequestJobFactoryImpl());
    595   job_factory->SetProtocolHandler(chrome::kDataScheme,
    596                                   new net::DataProtocolHandler());
    597   job_factory->SetProtocolHandler(chrome::kFileScheme,
    598                                   new net::FileProtocolHandler());
    599 #if !defined(DISABLE_FTP_SUPPORT)
    600   globals_->proxy_script_fetcher_ftp_transaction_factory.reset(
    601       new net::FtpNetworkLayer(globals_->host_resolver.get()));
    602   job_factory->SetProtocolHandler(
    603       chrome::kFtpScheme,
    604       new net::FtpProtocolHandler(
    605           globals_->proxy_script_fetcher_ftp_transaction_factory.get()));
    606 #endif
    607   globals_->proxy_script_fetcher_url_request_job_factory =
    608       job_factory.PassAs<net::URLRequestJobFactory>();
    609 
    610   globals_->throttler_manager.reset(new net::URLRequestThrottlerManager());
    611   globals_->throttler_manager->set_net_log(net_log_);
    612   // Always done in production, disabled only for unit tests.
    613   globals_->throttler_manager->set_enable_thread_checks(true);
    614 
    615   globals_->proxy_script_fetcher_context.reset(
    616       ConstructProxyScriptFetcherContext(globals_, net_log_));
    617 
    618   globals_->network_time_notifier.reset(
    619       new net::NetworkTimeNotifier(
    620           scoped_ptr<base::TickClock>(new base::DefaultTickClock())));
    621 
    622   sdch_manager_ = new net::SdchManager();
    623 
    624 #if defined(OS_MACOSX) && !defined(OS_IOS)
    625   // Start observing Keychain events. This needs to be done on the UI thread,
    626   // as Keychain services requires a CFRunLoop.
    627   BrowserThread::PostTask(BrowserThread::UI,
    628                           FROM_HERE,
    629                           base::Bind(&ObserveKeychainEvents));
    630 #endif
    631 
    632   // InitSystemRequestContext turns right around and posts a task back
    633   // to the IO thread, so we can't let it run until we know the IO
    634   // thread has started.
    635   //
    636   // Note that since we are at BrowserThread::Init time, the UI thread
    637   // is blocked waiting for the thread to start.  Therefore, posting
    638   // this task to the main thread's message loop here is guaranteed to
    639   // get it onto the message loop while the IOThread object still
    640   // exists.  However, the message might not be processed on the UI
    641   // thread until after IOThread is gone, so use a weak pointer.
    642   BrowserThread::PostTask(BrowserThread::UI,
    643                           FROM_HERE,
    644                           base::Bind(&IOThread::InitSystemRequestContext,
    645                                      weak_factory_.GetWeakPtr()));
    646 }
    647 
    648 void IOThread::CleanUp() {
    649   base::debug::LeakTracker<SafeBrowsingURLRequestContext>::CheckForLeaks();
    650 
    651   delete sdch_manager_;
    652   sdch_manager_ = NULL;
    653 
    654 #if defined(USE_NSS) || defined(OS_IOS)
    655   net::ShutdownNSSHttpIO();
    656 #endif
    657 
    658   system_url_request_context_getter_ = NULL;
    659 
    660   // Release objects that the net::URLRequestContext could have been pointing
    661   // to.
    662 
    663   // This must be reset before the ChromeNetLog is destroyed.
    664   network_change_observer_.reset();
    665 
    666   system_proxy_config_service_.reset();
    667 
    668   delete globals_;
    669   globals_ = NULL;
    670 
    671   base::debug::LeakTracker<SystemURLRequestContextGetter>::CheckForLeaks();
    672 }
    673 
    674 void IOThread::InitializeNetworkOptions(const CommandLine& command_line) {
    675   if (command_line.HasSwitch(switches::kEnableFileCookies)) {
    676     // Enable cookie storage for file:// URLs.  Must do this before the first
    677     // Profile (and therefore the first CookieMonster) is created.
    678     net::CookieMonster::EnableFileScheme();
    679   }
    680 
    681   // Only handle use-spdy command line flags if "spdy.disabled" preference is
    682   // not disabled via policy.
    683   if (!is_spdy_disabled_by_policy_) {
    684     if (command_line.HasSwitch(switches::kEnableIPPooling))
    685       globals_->enable_spdy_ip_pooling.set(true);
    686 
    687     if (command_line.HasSwitch(switches::kDisableIPPooling))
    688       globals_->enable_spdy_ip_pooling.set(false);
    689 
    690     if (command_line.HasSwitch(switches::kEnableSpdyCredentialFrames))
    691       globals_->enable_spdy_credential_frames.set(true);
    692 
    693     if (command_line.HasSwitch(switches::kEnableWebSocketOverSpdy)) {
    694       // Enable WebSocket over SPDY.
    695       net::WebSocketJob::set_websocket_over_spdy_enabled(true);
    696     }
    697     if (command_line.HasSwitch(switches::kMaxSpdyConcurrentStreams)) {
    698       globals_->max_spdy_concurrent_streams_limit.set(
    699           GetSwitchValueAsInt(command_line,
    700                               switches::kMaxSpdyConcurrentStreams));
    701     }
    702     if (command_line.HasSwitch(switches::kTrustedSpdyProxy)) {
    703       globals_->trusted_spdy_proxy.set(
    704           command_line.GetSwitchValueASCII(switches::kTrustedSpdyProxy));
    705     }
    706     if (command_line.HasSwitch(switches::kIgnoreUrlFetcherCertRequests))
    707       net::URLFetcher::SetIgnoreCertificateRequests(true);
    708 
    709     if (command_line.HasSwitch(switches::kUseSpdy)) {
    710       std::string spdy_mode =
    711           command_line.GetSwitchValueASCII(switches::kUseSpdy);
    712       EnableSpdy(spdy_mode);
    713     } else if (command_line.HasSwitch(switches::kEnableHttp2Draft04)) {
    714       net::HttpStreamFactory::EnableNpnHttp2Draft04();
    715     } else if (command_line.HasSwitch(switches::kEnableSpdy4a2)) {
    716       net::HttpStreamFactory::EnableNpnSpdy4a2();
    717     } else if (command_line.HasSwitch(switches::kDisableSpdy31)) {
    718       net::HttpStreamFactory::EnableNpnSpdy3();
    719     } else if (command_line.HasSwitch(switches::kEnableNpn)) {
    720       net::HttpStreamFactory::EnableNpnSpdy();
    721     } else if (command_line.HasSwitch(switches::kEnableNpnHttpOnly)) {
    722       net::HttpStreamFactory::EnableNpnHttpOnly();
    723     } else {
    724       // Use SPDY/3.1 by default.
    725       net::HttpStreamFactory::EnableNpnSpdy31();
    726     }
    727   }
    728 
    729   // TODO(rch): Make the client socket factory a per-network session
    730   // instance, constructed from a NetworkSession::Params, to allow us
    731   // to move this option to IOThread::Globals &
    732   // HttpNetworkSession::Params.
    733   if (command_line.HasSwitch(switches::kEnableTcpFastOpen))
    734     net::SetTCPFastOpenEnabled(true);
    735 }
    736 
    737 void IOThread::EnableSpdy(const std::string& mode) {
    738   static const char kOff[] = "off";
    739   static const char kSSL[] = "ssl";
    740   static const char kDisableSSL[] = "no-ssl";
    741   static const char kDisablePing[] = "no-ping";
    742   static const char kExclude[] = "exclude";  // Hosts to exclude
    743   static const char kDisableCompression[] = "no-compress";
    744   static const char kDisableAltProtocols[] = "no-alt-protocols";
    745   static const char kForceAltProtocols[] = "force-alt-protocols";
    746   static const char kSingleDomain[] = "single-domain";
    747 
    748   static const char kInitialMaxConcurrentStreams[] = "init-max-streams";
    749 
    750   std::vector<std::string> spdy_options;
    751   base::SplitString(mode, ',', &spdy_options);
    752 
    753   for (std::vector<std::string>::iterator it = spdy_options.begin();
    754        it != spdy_options.end(); ++it) {
    755     const std::string& element = *it;
    756     std::vector<std::string> name_value;
    757     base::SplitString(element, '=', &name_value);
    758     const std::string& option =
    759         name_value.size() > 0 ? name_value[0] : std::string();
    760     const std::string value =
    761         name_value.size() > 1 ? name_value[1] : std::string();
    762 
    763     if (option == kOff) {
    764       net::HttpStreamFactory::set_spdy_enabled(false);
    765     } else if (option == kDisableSSL) {
    766       globals_->spdy_default_protocol.set(net::kProtoSPDY2);
    767       net::HttpStreamFactory::set_force_spdy_over_ssl(false);
    768       net::HttpStreamFactory::set_force_spdy_always(true);
    769     } else if (option == kSSL) {
    770       globals_->spdy_default_protocol.set(net::kProtoSPDY2);
    771       net::HttpStreamFactory::set_force_spdy_over_ssl(true);
    772       net::HttpStreamFactory::set_force_spdy_always(true);
    773     } else if (option == kDisablePing) {
    774       globals_->enable_spdy_ping_based_connection_checking.set(false);
    775     } else if (option == kExclude) {
    776       net::HttpStreamFactory::add_forced_spdy_exclusion(value);
    777     } else if (option == kDisableCompression) {
    778       globals_->enable_spdy_compression.set(false);
    779     } else if (option == kDisableAltProtocols) {
    780       net::HttpStreamFactory::set_use_alternate_protocols(false);
    781     } else if (option == kForceAltProtocols) {
    782       net::PortAlternateProtocolPair pair;
    783       pair.port = 443;
    784       pair.protocol = net::NPN_SPDY_2;
    785       net::HttpServerPropertiesImpl::ForceAlternateProtocol(pair);
    786     } else if (option == kSingleDomain) {
    787       DLOG(INFO) << "FORCING SINGLE DOMAIN";
    788       globals_->force_spdy_single_domain.set(true);
    789     } else if (option == kInitialMaxConcurrentStreams) {
    790       int streams;
    791       if (base::StringToInt(value, &streams))
    792         globals_->initial_max_spdy_concurrent_streams.set(streams);
    793     } else if (option.empty() && it == spdy_options.begin()) {
    794       continue;
    795     } else {
    796       LOG(DFATAL) << "Unrecognized spdy option: " << option;
    797     }
    798   }
    799 }
    800 
    801 // static
    802 void IOThread::RegisterPrefs(PrefRegistrySimple* registry) {
    803   registry->RegisterStringPref(prefs::kAuthSchemes,
    804                                "basic,digest,ntlm,negotiate,"
    805                                "spdyproxy");
    806   registry->RegisterBooleanPref(prefs::kDisableAuthNegotiateCnameLookup, false);
    807   registry->RegisterBooleanPref(prefs::kEnableAuthNegotiatePort, false);
    808   registry->RegisterStringPref(prefs::kAuthServerWhitelist, std::string());
    809   registry->RegisterStringPref(prefs::kAuthNegotiateDelegateWhitelist,
    810                                std::string());
    811   registry->RegisterStringPref(prefs::kGSSAPILibraryName, std::string());
    812   registry->RegisterStringPref(prefs::kSpdyProxyAuthOrigin, std::string());
    813   registry->RegisterBooleanPref(prefs::kEnableReferrers, true);
    814   registry->RegisterInt64Pref(prefs::kHttpReceivedContentLength, 0);
    815   registry->RegisterInt64Pref(prefs::kHttpOriginalContentLength, 0);
    816 #if defined(OS_ANDROID) || defined(OS_IOS)
    817   registry->RegisterListPref(prefs::kDailyHttpOriginalContentLength);
    818   registry->RegisterListPref(prefs::kDailyHttpReceivedContentLength);
    819   registry->RegisterListPref(
    820       prefs::kDailyHttpReceivedContentLengthViaDataReductionProxy);
    821   registry->RegisterListPref(
    822       prefs::kDailyHttpReceivedContentLengthWithDataReductionProxyEnabled);
    823   registry->RegisterInt64Pref(prefs::kDailyHttpContentLengthLastUpdateDate, 0L);
    824 #endif
    825   registry->RegisterBooleanPref(prefs::kBuiltInDnsClientEnabled, true);
    826 }
    827 
    828 net::HttpAuthHandlerFactory* IOThread::CreateDefaultAuthHandlerFactory(
    829     net::HostResolver* resolver) {
    830   net::HttpAuthFilterWhitelist* auth_filter_default_credentials = NULL;
    831   if (!auth_server_whitelist_.empty()) {
    832     auth_filter_default_credentials =
    833         new net::HttpAuthFilterWhitelist(auth_server_whitelist_);
    834   }
    835   net::HttpAuthFilterWhitelist* auth_filter_delegate = NULL;
    836   if (!auth_delegate_whitelist_.empty()) {
    837     auth_filter_delegate =
    838         new net::HttpAuthFilterWhitelist(auth_delegate_whitelist_);
    839   }
    840   globals_->url_security_manager.reset(
    841       net::URLSecurityManager::Create(auth_filter_default_credentials,
    842                                       auth_filter_delegate));
    843   std::vector<std::string> supported_schemes;
    844   base::SplitString(auth_schemes_, ',', &supported_schemes);
    845 
    846   scoped_ptr<net::HttpAuthHandlerRegistryFactory> registry_factory(
    847       net::HttpAuthHandlerRegistryFactory::Create(
    848           supported_schemes, globals_->url_security_manager.get(),
    849           resolver, gssapi_library_name_, negotiate_disable_cname_lookup_,
    850           negotiate_enable_port_));
    851 
    852   if (!spdyproxy_auth_origin_.empty()) {
    853     GURL origin_url(spdyproxy_auth_origin_);
    854     if (origin_url.is_valid()) {
    855       registry_factory->RegisterSchemeFactory(
    856           "spdyproxy",
    857           new spdyproxy::HttpAuthHandlerSpdyProxy::Factory(origin_url));
    858     } else {
    859       LOG(WARNING) << "Skipping creation of SpdyProxy auth handler since "
    860                    << "authorized origin is invalid: "
    861                    << spdyproxy_auth_origin_;
    862     }
    863   }
    864 
    865   return registry_factory.release();
    866 }
    867 
    868 void IOThread::ClearHostCache() {
    869   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    870 
    871   net::HostCache* host_cache = globals_->host_resolver->GetHostCache();
    872   if (host_cache)
    873     host_cache->clear();
    874 }
    875 
    876 void IOThread::InitializeNetworkSessionParams(
    877     net::HttpNetworkSession::Params* params) {
    878   params->host_resolver = globals_->host_resolver.get();
    879   params->cert_verifier = globals_->cert_verifier.get();
    880   params->server_bound_cert_service =
    881       globals_->system_server_bound_cert_service.get();
    882   params->transport_security_state = globals_->transport_security_state.get();
    883   params->ssl_config_service = globals_->ssl_config_service.get();
    884   params->http_auth_handler_factory = globals_->http_auth_handler_factory.get();
    885   params->http_server_properties =
    886       globals_->http_server_properties->GetWeakPtr();
    887   params->network_delegate = globals_->system_network_delegate.get();
    888   params->host_mapping_rules = globals_->host_mapping_rules.get();
    889   params->ignore_certificate_errors = globals_->ignore_certificate_errors;
    890   params->http_pipelining_enabled = globals_->http_pipelining_enabled;
    891   params->testing_fixed_http_port = globals_->testing_fixed_http_port;
    892   params->testing_fixed_https_port = globals_->testing_fixed_https_port;
    893 
    894   globals_->initial_max_spdy_concurrent_streams.CopyToIfSet(
    895       &params->spdy_initial_max_concurrent_streams);
    896   globals_->max_spdy_concurrent_streams_limit.CopyToIfSet(
    897       &params->spdy_max_concurrent_streams_limit);
    898   globals_->force_spdy_single_domain.CopyToIfSet(
    899       &params->force_spdy_single_domain);
    900   globals_->enable_spdy_ip_pooling.CopyToIfSet(
    901       &params->enable_spdy_ip_pooling);
    902   globals_->enable_spdy_credential_frames.CopyToIfSet(
    903       &params->enable_spdy_credential_frames);
    904   globals_->enable_spdy_compression.CopyToIfSet(
    905       &params->enable_spdy_compression);
    906   globals_->enable_spdy_ping_based_connection_checking.CopyToIfSet(
    907       &params->enable_spdy_ping_based_connection_checking);
    908   globals_->spdy_default_protocol.CopyToIfSet(
    909       &params->spdy_default_protocol);
    910   globals_->trusted_spdy_proxy.CopyToIfSet(
    911       &params->trusted_spdy_proxy);
    912   globals_->enable_quic.CopyToIfSet(&params->enable_quic);
    913   globals_->enable_quic_https.CopyToIfSet(&params->enable_quic_https);
    914   globals_->origin_to_force_quic_on.CopyToIfSet(
    915       &params->origin_to_force_quic_on);
    916   params->enable_user_alternate_protocol_ports =
    917       globals_->enable_user_alternate_protocol_ports;
    918 }
    919 
    920 net::SSLConfigService* IOThread::GetSSLConfigService() {
    921   return ssl_config_service_manager_->Get();
    922 }
    923 
    924 void IOThread::ChangedToOnTheRecordOnIOThread() {
    925   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    926 
    927   // Clear the host cache to avoid showing entries from the OTR session
    928   // in about:net-internals.
    929   ClearHostCache();
    930 }
    931 
    932 void IOThread::InitSystemRequestContext() {
    933   if (system_url_request_context_getter_.get())
    934     return;
    935   // If we're in unit_tests, IOThread may not be run.
    936   if (!BrowserThread::IsMessageLoopValid(BrowserThread::IO))
    937     return;
    938   system_proxy_config_service_.reset(
    939       ProxyServiceFactory::CreateProxyConfigService(
    940           pref_proxy_config_tracker_.get()));
    941   system_url_request_context_getter_ =
    942       new SystemURLRequestContextGetter(this);
    943   // Safe to post an unretained this pointer, since IOThread is
    944   // guaranteed to outlive the IO BrowserThread.
    945   BrowserThread::PostTask(
    946       BrowserThread::IO,
    947       FROM_HERE,
    948       base::Bind(&IOThread::InitSystemRequestContextOnIOThread,
    949                  base::Unretained(this)));
    950 }
    951 
    952 void IOThread::InitSystemRequestContextOnIOThread() {
    953   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    954   DCHECK(!globals_->system_proxy_service.get());
    955   DCHECK(system_proxy_config_service_.get());
    956 
    957   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
    958   globals_->system_proxy_service.reset(
    959       ProxyServiceFactory::CreateProxyService(
    960           net_log_,
    961           globals_->proxy_script_fetcher_context.get(),
    962           globals_->system_network_delegate.get(),
    963           system_proxy_config_service_.release(),
    964           command_line));
    965 
    966   net::HttpNetworkSession::Params system_params;
    967   InitializeNetworkSessionParams(&system_params);
    968   system_params.net_log = net_log_;
    969   system_params.proxy_service = globals_->system_proxy_service.get();
    970 
    971   globals_->system_http_transaction_factory.reset(
    972       new net::HttpNetworkLayer(
    973           new net::HttpNetworkSession(system_params)));
    974   globals_->system_request_context.reset(
    975       ConstructSystemRequestContext(globals_, net_log_));
    976 
    977   sdch_manager_->set_sdch_fetcher(
    978       new SdchDictionaryFetcher(system_url_request_context_getter_.get()));
    979 }
    980 
    981 void IOThread::UpdateDnsClientEnabled() {
    982   globals()->host_resolver->SetDnsClientEnabled(*dns_client_enabled_);
    983 }
    984 
    985 bool IOThread::ShouldEnableQuic(const CommandLine& command_line) {
    986   // Always fetch the field trial group to ensure it is reported correctly.
    987   // The command line flags will be associated with a group that is reported
    988   // so long as trial is actually queried.
    989   std::string quic_trial_group =
    990       base::FieldTrialList::FindFullName(kQuicFieldTrialName);
    991 
    992   if (command_line.HasSwitch(switches::kDisableQuic))
    993     return false;
    994 
    995   if (command_line.HasSwitch(switches::kEnableQuic))
    996     return true;
    997 
    998   // QUIC should be enabled if we are in either field trial group.
    999   return quic_trial_group == kQuicFieldTrialEnabledGroupName ||
   1000       quic_trial_group == kQuicFieldTrialHttpsEnabledGroupName;
   1001 }
   1002 
   1003 bool IOThread::ShouldEnableQuicHttps(const CommandLine& command_line) {
   1004   // Always fetch the field trial group to ensure it is reported correctly.
   1005   // The command line flags will be associated with a group that is reported
   1006   // so long as trial is actually queried.
   1007   std::string quic_trial_group =
   1008       base::FieldTrialList::FindFullName(kQuicFieldTrialName);
   1009 
   1010   if (command_line.HasSwitch(switches::kDisableQuicHttps))
   1011     return false;
   1012 
   1013   if (command_line.HasSwitch(switches::kEnableQuicHttps))
   1014     return true;
   1015 
   1016   // HTTPS over QUIC should only be enabled if we are in the https
   1017   // field trial group.
   1018   return quic_trial_group == kQuicFieldTrialHttpsEnabledGroupName;
   1019 }
   1020