Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / io_thread.cc
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/base64.h"
10 #include "base/bind.h"
11 #include "base/bind_helpers.h"
12 #include "base/command_line.h"
13 #include "base/compiler_specific.h"
14 #include "base/debug/leak_tracker.h"
15 #include "base/debug/trace_event.h"
16 #include "base/logging.h"
17 #include "base/metrics/field_trial.h"
18 #include "base/prefs/pref_registry_simple.h"
19 #include "base/prefs/pref_service.h"
20 #include "base/stl_util.h"
21 #include "base/strings/string_number_conversions.h"
22 #include "base/strings/string_split.h"
23 #include "base/strings/string_util.h"
24 #include "base/threading/sequenced_worker_pool.h"
25 #include "base/threading/thread.h"
26 #include "base/threading/worker_pool.h"
27 #include "base/time/default_tick_clock.h"
28 #include "base/time/time.h"
29 #include "build/build_config.h"
30 #include "chrome/browser/browser_process.h"
31 #include "chrome/browser/extensions/event_router_forwarder.h"
32 #include "chrome/browser/net/async_dns_field_trial.h"
33 #include "chrome/browser/net/chrome_net_log.h"
34 #include "chrome/browser/net/chrome_network_delegate.h"
35 #include "chrome/browser/net/chrome_url_request_context.h"
36 #include "chrome/browser/net/connect_interceptor.h"
37 #include "chrome/browser/net/dns_probe_service.h"
38 #include "chrome/browser/net/http_pipelining_compatibility_client.h"
39 #include "chrome/browser/net/pref_proxy_config_tracker.h"
40 #include "chrome/browser/net/proxy_service_factory.h"
41 #include "chrome/browser/net/sdch_dictionary_fetcher.h"
42 #include "chrome/common/chrome_content_client.h"
43 #include "chrome/common/chrome_switches.h"
44 #include "chrome/common/chrome_version_info.h"
45 #include "chrome/common/pref_names.h"
46 #include "chrome/common/url_constants.h"
47 #include "components/data_reduction_proxy/browser/data_reduction_proxy_prefs.h"
48 #include "components/data_reduction_proxy/browser/http_auth_handler_data_reduction_proxy.h"
49 #include "components/policy/core/common/policy_service.h"
50 #include "content/public/browser/browser_thread.h"
51 #include "content/public/browser/cookie_store_factory.h"
52 #include "net/base/host_mapping_rules.h"
53 #include "net/base/net_util.h"
54 #include "net/base/network_time_notifier.h"
55 #include "net/base/sdch_manager.h"
56 #include "net/cert/cert_verifier.h"
57 #include "net/cert/cert_verify_proc.h"
58 #include "net/cert/ct_known_logs.h"
59 #include "net/cert/ct_verifier.h"
60 #include "net/cert/multi_threaded_cert_verifier.h"
61 #include "net/cookies/cookie_store.h"
62 #include "net/dns/host_cache.h"
63 #include "net/dns/host_resolver.h"
64 #include "net/dns/mapped_host_resolver.h"
65 #include "net/ftp/ftp_network_layer.h"
66 #include "net/http/http_auth_filter.h"
67 #include "net/http/http_auth_handler_factory.h"
68 #include "net/http/http_network_layer.h"
69 #include "net/http/http_server_properties_impl.h"
70 #include "net/proxy/proxy_config_service.h"
71 #include "net/proxy/proxy_script_fetcher_impl.h"
72 #include "net/proxy/proxy_service.h"
73 #include "net/quic/quic_protocol.h"
74 #include "net/socket/tcp_client_socket.h"
75 #include "net/spdy/spdy_session.h"
76 #include "net/ssl/default_server_bound_cert_store.h"
77 #include "net/ssl/server_bound_cert_service.h"
78 #include "net/url_request/data_protocol_handler.h"
79 #include "net/url_request/file_protocol_handler.h"
80 #include "net/url_request/ftp_protocol_handler.h"
81 #include "net/url_request/static_http_user_agent_settings.h"
82 #include "net/url_request/url_fetcher.h"
83 #include "net/url_request/url_request_job_factory_impl.h"
84 #include "net/url_request/url_request_throttler_manager.h"
85 #include "net/websockets/websocket_job.h"
86
87 #if defined(ENABLE_CONFIGURATION_POLICY)
88 #include "policy/policy_constants.h"
89 #endif
90
91 #if !defined(USE_OPENSSL)
92 #include "net/cert/ct_log_verifier.h"
93 #include "net/cert/multi_log_ct_verifier.h"
94 #endif
95
96 #if defined(USE_NSS) || defined(OS_IOS)
97 #include "net/ocsp/nss_ocsp.h"
98 #endif
99
100 #if defined(OS_ANDROID) || defined(OS_IOS)
101 #include "components/data_reduction_proxy/browser/data_reduction_proxy_settings.h"
102 #endif
103
104 #if defined(OS_CHROMEOS)
105 #include "chrome/browser/chromeos/login/user_manager.h"
106 #include "chrome/browser/chromeos/net/cert_verify_proc_chromeos.h"
107 #endif
108
109 using content::BrowserThread;
110
111 #if defined(OS_ANDROID) || defined(OS_IOS)
112 using data_reduction_proxy::DataReductionProxySettings;
113 #endif
114
115 class SafeBrowsingURLRequestContext;
116
117 // The IOThread object must outlive any tasks posted to the IO thread before the
118 // Quit task, so base::Bind() calls are not refcounted.
119
120 namespace {
121
122 const char kQuicFieldTrialName[] = "QUIC";
123 const char kQuicFieldTrialEnabledGroupName[] = "Enabled";
124 const char kQuicFieldTrialHttpsEnabledGroupName[] = "HttpsEnabled";
125 const char kQuicFieldTrialPacketLengthSuffix[] = "BytePackets";
126 const char kQuicFieldTrialPacingSuffix[] = "WithPacing";
127 const char kQuicFieldTrialTimeBasedLossDetectionSuffix[] =
128     "WithTimeBasedLossDetection";
129
130 const char kSpdyFieldTrialName[] = "SPDY";
131 const char kSpdyFieldTrialDisabledGroupName[] = "SpdyDisabled";
132
133 #if defined(OS_MACOSX) && !defined(OS_IOS)
134 void ObserveKeychainEvents() {
135   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
136   net::CertDatabase::GetInstance()->SetMessageLoopForKeychainEvents();
137 }
138 #endif
139
140 // Used for the "system" URLRequestContext.
141 class SystemURLRequestContext : public net::URLRequestContext {
142  public:
143   SystemURLRequestContext() {
144 #if defined(USE_NSS) || defined(OS_IOS)
145     net::SetURLRequestContextForNSSHttpIO(this);
146 #endif
147   }
148
149  private:
150   virtual ~SystemURLRequestContext() {
151 #if defined(USE_NSS) || defined(OS_IOS)
152     net::SetURLRequestContextForNSSHttpIO(NULL);
153 #endif
154   }
155 };
156
157 scoped_ptr<net::HostResolver> CreateGlobalHostResolver(net::NetLog* net_log) {
158   TRACE_EVENT0("startup", "IOThread::CreateGlobalHostResolver");
159   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
160
161   net::HostResolver::Options options;
162
163   // Use the concurrency override from the command-line, if any.
164   if (command_line.HasSwitch(switches::kHostResolverParallelism)) {
165     std::string s =
166         command_line.GetSwitchValueASCII(switches::kHostResolverParallelism);
167
168     // Parse the switch (it should be a positive integer formatted as decimal).
169     int n;
170     if (base::StringToInt(s, &n) && n > 0) {
171       options.max_concurrent_resolves = static_cast<size_t>(n);
172     } else {
173       LOG(ERROR) << "Invalid switch for host resolver parallelism: " << s;
174     }
175   }
176
177   // Use the retry attempts override from the command-line, if any.
178   if (command_line.HasSwitch(switches::kHostResolverRetryAttempts)) {
179     std::string s =
180         command_line.GetSwitchValueASCII(switches::kHostResolverRetryAttempts);
181     // Parse the switch (it should be a non-negative integer).
182     int n;
183     if (base::StringToInt(s, &n) && n >= 0) {
184       options.max_retry_attempts = static_cast<size_t>(n);
185     } else {
186       LOG(ERROR) << "Invalid switch for host resolver retry attempts: " << s;
187     }
188   }
189
190   scoped_ptr<net::HostResolver> global_host_resolver(
191       net::HostResolver::CreateSystemResolver(options, net_log));
192
193   // Determine if we should disable IPv6 support.
194   if (command_line.HasSwitch(switches::kEnableIPv6)) {
195     // Disable IPv6 probing.
196     global_host_resolver->SetDefaultAddressFamily(
197         net::ADDRESS_FAMILY_UNSPECIFIED);
198   } else if (command_line.HasSwitch(switches::kDisableIPv6)) {
199     global_host_resolver->SetDefaultAddressFamily(net::ADDRESS_FAMILY_IPV4);
200   }
201
202   // If hostname remappings were specified on the command-line, layer these
203   // rules on top of the real host resolver. This allows forwarding all requests
204   // through a designated test server.
205   if (!command_line.HasSwitch(switches::kHostResolverRules))
206     return global_host_resolver.PassAs<net::HostResolver>();
207
208   scoped_ptr<net::MappedHostResolver> remapped_resolver(
209       new net::MappedHostResolver(global_host_resolver.Pass()));
210   remapped_resolver->SetRulesFromString(
211       command_line.GetSwitchValueASCII(switches::kHostResolverRules));
212   return remapped_resolver.PassAs<net::HostResolver>();
213 }
214
215 // TODO(willchan): Remove proxy script fetcher context since it's not necessary
216 // now that I got rid of refcounting URLRequestContexts.
217 // See IOThread::Globals for details.
218 net::URLRequestContext*
219 ConstructProxyScriptFetcherContext(IOThread::Globals* globals,
220                                    net::NetLog* net_log) {
221   net::URLRequestContext* context = new net::URLRequestContext;
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_cert_transparency_verifier(
228       globals->cert_transparency_verifier.get());
229   context->set_http_auth_handler_factory(
230       globals->http_auth_handler_factory.get());
231   context->set_proxy_service(globals->proxy_script_fetcher_proxy_service.get());
232   context->set_http_transaction_factory(
233       globals->proxy_script_fetcher_http_transaction_factory.get());
234   context->set_job_factory(
235       globals->proxy_script_fetcher_url_request_job_factory.get());
236   context->set_cookie_store(globals->system_cookie_store.get());
237   context->set_server_bound_cert_service(
238       globals->system_server_bound_cert_service.get());
239   context->set_network_delegate(globals->system_network_delegate.get());
240   context->set_http_user_agent_settings(
241       globals->http_user_agent_settings.get());
242   // TODO(rtenneti): We should probably use HttpServerPropertiesManager for the
243   // system URLRequestContext too. There's no reason this should be tied to a
244   // profile.
245   return context;
246 }
247
248 net::URLRequestContext*
249 ConstructSystemRequestContext(IOThread::Globals* globals,
250                               net::NetLog* net_log) {
251   net::URLRequestContext* context = new SystemURLRequestContext;
252   context->set_net_log(net_log);
253   context->set_host_resolver(globals->host_resolver.get());
254   context->set_cert_verifier(globals->cert_verifier.get());
255   context->set_transport_security_state(
256       globals->transport_security_state.get());
257   context->set_cert_transparency_verifier(
258       globals->cert_transparency_verifier.get());
259   context->set_http_auth_handler_factory(
260       globals->http_auth_handler_factory.get());
261   context->set_proxy_service(globals->system_proxy_service.get());
262   context->set_http_transaction_factory(
263       globals->system_http_transaction_factory.get());
264   context->set_cookie_store(globals->system_cookie_store.get());
265   context->set_server_bound_cert_service(
266       globals->system_server_bound_cert_service.get());
267   context->set_throttler_manager(globals->throttler_manager.get());
268   context->set_network_delegate(globals->system_network_delegate.get());
269   context->set_http_user_agent_settings(
270       globals->http_user_agent_settings.get());
271   return context;
272 }
273
274 int GetSwitchValueAsInt(const CommandLine& command_line,
275                         const std::string& switch_name) {
276   int value;
277   if (!base::StringToInt(command_line.GetSwitchValueASCII(switch_name),
278                          &value)) {
279     return 0;
280   }
281   return value;
282 }
283
284 }  // namespace
285
286 class IOThread::LoggingNetworkChangeObserver
287     : public net::NetworkChangeNotifier::IPAddressObserver,
288       public net::NetworkChangeNotifier::ConnectionTypeObserver,
289       public net::NetworkChangeNotifier::NetworkChangeObserver {
290  public:
291   // |net_log| must remain valid throughout our lifetime.
292   explicit LoggingNetworkChangeObserver(net::NetLog* net_log)
293       : net_log_(net_log) {
294     net::NetworkChangeNotifier::AddIPAddressObserver(this);
295     net::NetworkChangeNotifier::AddConnectionTypeObserver(this);
296     net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
297   }
298
299   virtual ~LoggingNetworkChangeObserver() {
300     net::NetworkChangeNotifier::RemoveIPAddressObserver(this);
301     net::NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
302     net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
303   }
304
305   // NetworkChangeNotifier::IPAddressObserver implementation.
306   virtual void OnIPAddressChanged() OVERRIDE {
307     VLOG(1) << "Observed a change to the network IP addresses";
308
309     net_log_->AddGlobalEntry(net::NetLog::TYPE_NETWORK_IP_ADDRESSES_CHANGED);
310   }
311
312   // NetworkChangeNotifier::ConnectionTypeObserver implementation.
313   virtual void OnConnectionTypeChanged(
314       net::NetworkChangeNotifier::ConnectionType type) OVERRIDE {
315     std::string type_as_string =
316         net::NetworkChangeNotifier::ConnectionTypeToString(type);
317
318     VLOG(1) << "Observed a change to network connectivity state "
319             << type_as_string;
320
321     net_log_->AddGlobalEntry(
322         net::NetLog::TYPE_NETWORK_CONNECTIVITY_CHANGED,
323         net::NetLog::StringCallback("new_connection_type", &type_as_string));
324   }
325
326   // NetworkChangeNotifier::NetworkChangeObserver implementation.
327   virtual void OnNetworkChanged(
328       net::NetworkChangeNotifier::ConnectionType type) OVERRIDE {
329     std::string type_as_string =
330         net::NetworkChangeNotifier::ConnectionTypeToString(type);
331
332     VLOG(1) << "Observed a network change to state " << type_as_string;
333
334     net_log_->AddGlobalEntry(
335         net::NetLog::TYPE_NETWORK_CHANGED,
336         net::NetLog::StringCallback("new_connection_type", &type_as_string));
337   }
338
339  private:
340   net::NetLog* net_log_;
341   DISALLOW_COPY_AND_ASSIGN(LoggingNetworkChangeObserver);
342 };
343
344 class SystemURLRequestContextGetter : public net::URLRequestContextGetter {
345  public:
346   explicit SystemURLRequestContextGetter(IOThread* io_thread);
347
348   // Implementation for net::UrlRequestContextGetter.
349   virtual net::URLRequestContext* GetURLRequestContext() OVERRIDE;
350   virtual scoped_refptr<base::SingleThreadTaskRunner>
351       GetNetworkTaskRunner() const OVERRIDE;
352
353  protected:
354   virtual ~SystemURLRequestContextGetter();
355
356  private:
357   IOThread* const io_thread_;  // Weak pointer, owned by BrowserProcess.
358   scoped_refptr<base::SingleThreadTaskRunner> network_task_runner_;
359
360   base::debug::LeakTracker<SystemURLRequestContextGetter> leak_tracker_;
361 };
362
363 SystemURLRequestContextGetter::SystemURLRequestContextGetter(
364     IOThread* io_thread)
365     : io_thread_(io_thread),
366       network_task_runner_(
367           BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO)) {
368 }
369
370 SystemURLRequestContextGetter::~SystemURLRequestContextGetter() {}
371
372 net::URLRequestContext* SystemURLRequestContextGetter::GetURLRequestContext() {
373   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
374   DCHECK(io_thread_->globals()->system_request_context.get());
375
376   return io_thread_->globals()->system_request_context.get();
377 }
378
379 scoped_refptr<base::SingleThreadTaskRunner>
380 SystemURLRequestContextGetter::GetNetworkTaskRunner() const {
381   return network_task_runner_;
382 }
383
384 IOThread::Globals::
385 SystemRequestContextLeakChecker::SystemRequestContextLeakChecker(
386     Globals* globals)
387     : globals_(globals) {
388   DCHECK(globals_);
389 }
390
391 IOThread::Globals::
392 SystemRequestContextLeakChecker::~SystemRequestContextLeakChecker() {
393   if (globals_->system_request_context.get())
394     globals_->system_request_context->AssertNoURLRequests();
395 }
396
397 IOThread::Globals::Globals()
398     : system_request_context_leak_checker(this),
399       ignore_certificate_errors(false),
400       http_pipelining_enabled(false),
401       testing_fixed_http_port(0),
402       testing_fixed_https_port(0),
403       enable_user_alternate_protocol_ports(false) {
404 }
405
406 IOThread::Globals::~Globals() {}
407
408 // |local_state| is passed in explicitly in order to (1) reduce implicit
409 // dependencies and (2) make IOThread more flexible for testing.
410 IOThread::IOThread(
411     PrefService* local_state,
412     policy::PolicyService* policy_service,
413     ChromeNetLog* net_log,
414     extensions::EventRouterForwarder* extension_event_router_forwarder)
415     : net_log_(net_log),
416       extension_event_router_forwarder_(extension_event_router_forwarder),
417       globals_(NULL),
418       sdch_manager_(NULL),
419       is_spdy_disabled_by_policy_(false),
420       weak_factory_(this),
421       creation_time_(base::TimeTicks::Now()) {
422   auth_schemes_ = local_state->GetString(prefs::kAuthSchemes);
423   negotiate_disable_cname_lookup_ = local_state->GetBoolean(
424       prefs::kDisableAuthNegotiateCnameLookup);
425   negotiate_enable_port_ = local_state->GetBoolean(
426       prefs::kEnableAuthNegotiatePort);
427   auth_server_whitelist_ = local_state->GetString(prefs::kAuthServerWhitelist);
428   auth_delegate_whitelist_ = local_state->GetString(
429       prefs::kAuthNegotiateDelegateWhitelist);
430   gssapi_library_name_ = local_state->GetString(prefs::kGSSAPILibraryName);
431   pref_proxy_config_tracker_.reset(
432       ProxyServiceFactory::CreatePrefProxyConfigTrackerOfLocalState(
433           local_state));
434   ChromeNetworkDelegate::InitializePrefsOnUIThread(
435       &system_enable_referrers_,
436       NULL,
437       NULL,
438       local_state);
439   ssl_config_service_manager_.reset(
440       SSLConfigServiceManager::CreateDefaultManager(local_state));
441
442   base::Value* dns_client_enabled_default = new base::FundamentalValue(
443       chrome_browser_net::ConfigureAsyncDnsFieldTrial());
444   local_state->SetDefaultPrefValue(prefs::kBuiltInDnsClientEnabled,
445                                    dns_client_enabled_default);
446
447   dns_client_enabled_.Init(prefs::kBuiltInDnsClientEnabled,
448                            local_state,
449                            base::Bind(&IOThread::UpdateDnsClientEnabled,
450                                       base::Unretained(this)));
451   dns_client_enabled_.MoveToThread(
452       BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO));
453
454   quick_check_enabled_.Init(prefs::kQuickCheckEnabled,
455                             local_state);
456   quick_check_enabled_.MoveToThread(
457       BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO));
458
459 #if defined(ENABLE_CONFIGURATION_POLICY)
460   is_spdy_disabled_by_policy_ = policy_service->GetPolicies(
461       policy::PolicyNamespace(policy::POLICY_DOMAIN_CHROME, std::string())).Get(
462           policy::key::kDisableSpdy) != NULL;
463 #endif  // ENABLE_CONFIGURATION_POLICY
464
465   BrowserThread::SetDelegate(BrowserThread::IO, this);
466 }
467
468 IOThread::~IOThread() {
469   // This isn't needed for production code, but in tests, IOThread may
470   // be multiply constructed.
471   BrowserThread::SetDelegate(BrowserThread::IO, NULL);
472
473   pref_proxy_config_tracker_->DetachFromPrefService();
474   DCHECK(!globals_);
475 }
476
477 IOThread::Globals* IOThread::globals() {
478   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
479   return globals_;
480 }
481
482 void IOThread::SetGlobalsForTesting(Globals* globals) {
483   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
484   DCHECK(!globals || !globals_);
485   globals_ = globals;
486 }
487
488 ChromeNetLog* IOThread::net_log() {
489   return net_log_;
490 }
491
492 void IOThread::ChangedToOnTheRecord() {
493   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
494   BrowserThread::PostTask(
495       BrowserThread::IO,
496       FROM_HERE,
497       base::Bind(&IOThread::ChangedToOnTheRecordOnIOThread,
498                  base::Unretained(this)));
499 }
500
501 net::URLRequestContextGetter* IOThread::system_url_request_context_getter() {
502   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
503   if (!system_url_request_context_getter_.get()) {
504     InitSystemRequestContext();
505   }
506   return system_url_request_context_getter_.get();
507 }
508
509 void IOThread::Init() {
510   // Prefer to use InitAsync unless you need initialization to block
511   // the UI thread
512 }
513
514 void IOThread::InitAsync() {
515   TRACE_EVENT0("startup", "IOThread::InitAsync");
516   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
517
518 #if defined(USE_NSS) || defined(OS_IOS)
519   net::SetMessageLoopForNSSHttpIO();
520 #endif
521
522   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
523
524   DCHECK(!globals_);
525   globals_ = new Globals;
526
527   // Add an observer that will emit network change events to the ChromeNetLog.
528   // Assuming NetworkChangeNotifier dispatches in FIFO order, we should be
529   // logging the network change before other IO thread consumers respond to it.
530   network_change_observer_.reset(
531       new LoggingNetworkChangeObserver(net_log_));
532
533   // Setup the HistogramWatcher to run on the IO thread.
534   net::NetworkChangeNotifier::InitHistogramWatcher();
535
536   globals_->extension_event_router_forwarder =
537       extension_event_router_forwarder_;
538   ChromeNetworkDelegate* network_delegate =
539       new ChromeNetworkDelegate(extension_event_router_forwarder_,
540                                 &system_enable_referrers_);
541   if (command_line.HasSwitch(switches::kEnableClientHints))
542     network_delegate->SetEnableClientHints();
543   if (command_line.HasSwitch(switches::kDisableExtensionsHttpThrottling))
544     network_delegate->NeverThrottleRequests();
545   globals_->system_network_delegate.reset(network_delegate);
546   globals_->host_resolver = CreateGlobalHostResolver(net_log_);
547   UpdateDnsClientEnabled();
548 #if defined(OS_CHROMEOS)
549   if (chromeos::UserManager::IsMultipleProfilesAllowed()) {
550     // Creates a CertVerifyProc that doesn't allow any profile-provided certs.
551     globals_->cert_verifier.reset(new net::MultiThreadedCertVerifier(
552         new chromeos::CertVerifyProcChromeOS()));
553   } else  // NOLINT Fallthrough to normal verifier if multiprofiles not allowed.
554 #endif
555   {
556     globals_->cert_verifier.reset(new net::MultiThreadedCertVerifier(
557         net::CertVerifyProc::CreateDefault()));
558   }
559   globals_->transport_security_state.reset(new net::TransportSecurityState());
560 #if !defined(USE_OPENSSL)
561   // For now, Certificate Transparency is only implemented for platforms
562   // that use NSS.
563   net::MultiLogCTVerifier* ct_verifier = new net::MultiLogCTVerifier();
564   globals_->cert_transparency_verifier.reset(ct_verifier);
565
566   // Add built-in logs
567   ct_verifier->AddLog(net::ct::CreateGooglePilotLogVerifier().Pass());
568   ct_verifier->AddLog(net::ct::CreateGoogleAviatorLogVerifier().Pass());
569   ct_verifier->AddLog(net::ct::CreateGoogleRocketeerLogVerifier().Pass());
570
571   // Add logs from command line
572   if (command_line.HasSwitch(switches::kCertificateTransparencyLog)) {
573     std::string switch_value = command_line.GetSwitchValueASCII(
574         switches::kCertificateTransparencyLog);
575     std::vector<std::string> logs;
576     base::SplitString(switch_value, ',', &logs);
577     for (std::vector<std::string>::iterator it = logs.begin(); it != logs.end();
578          ++it) {
579       const std::string& curr_log = *it;
580       size_t delim_pos = curr_log.find(":");
581       CHECK(delim_pos != std::string::npos)
582           << "CT log description not provided (switch format"
583              " is 'description:base64_key')";
584       std::string log_description(curr_log.substr(0, delim_pos));
585       std::string ct_public_key_data;
586       CHECK(base::Base64Decode(curr_log.substr(delim_pos + 1),
587                                &ct_public_key_data))
588           << "Unable to decode CT public key.";
589       scoped_ptr<net::CTLogVerifier> external_log_verifier(
590           net::CTLogVerifier::Create(ct_public_key_data, log_description));
591       CHECK(external_log_verifier) << "Unable to parse CT public key.";
592       VLOG(1) << "Adding log with description " << log_description;
593       ct_verifier->AddLog(external_log_verifier.Pass());
594     }
595   }
596 #else
597   if (command_line.HasSwitch(switches::kCertificateTransparencyLog)) {
598     LOG(DFATAL) << "Certificate Transparency is not yet supported in Chrome "
599                    "builds using OpenSSL.";
600   }
601 #endif
602   globals_->ssl_config_service = GetSSLConfigService();
603 #if defined(OS_ANDROID) || defined(OS_IOS)
604   if (DataReductionProxySettings::IsIncludedInFieldTrialOrFlags()) {
605     spdyproxy_auth_origins_ =
606         DataReductionProxySettings::GetDataReductionProxies();
607   }
608 #endif  // defined(OS_ANDROID) || defined(OS_IOS)
609   globals_->http_auth_handler_factory.reset(CreateDefaultAuthHandlerFactory(
610       globals_->host_resolver.get()));
611   globals_->http_server_properties.reset(new net::HttpServerPropertiesImpl());
612   // For the ProxyScriptFetcher, we use a direct ProxyService.
613   globals_->proxy_script_fetcher_proxy_service.reset(
614       net::ProxyService::CreateDirectWithNetLog(net_log_));
615   // In-memory cookie store.
616   globals_->system_cookie_store =
617         content::CreateCookieStore(content::CookieStoreConfig());
618   // In-memory server bound cert store.
619   globals_->system_server_bound_cert_service.reset(
620       new net::ServerBoundCertService(
621           new net::DefaultServerBoundCertStore(NULL),
622           base::WorkerPool::GetTaskRunner(true)));
623   globals_->dns_probe_service.reset(new chrome_browser_net::DnsProbeService());
624   globals_->host_mapping_rules.reset(new net::HostMappingRules());
625   globals_->http_user_agent_settings.reset(
626       new net::StaticHttpUserAgentSettings(std::string(), GetUserAgent()));
627   if (command_line.HasSwitch(switches::kHostRules)) {
628     TRACE_EVENT_BEGIN0("startup", "IOThread::InitAsync:SetRulesFromString");
629     globals_->host_mapping_rules->SetRulesFromString(
630         command_line.GetSwitchValueASCII(switches::kHostRules));
631     TRACE_EVENT_END0("startup", "IOThread::InitAsync:SetRulesFromString");
632   }
633   if (command_line.HasSwitch(switches::kIgnoreCertificateErrors))
634     globals_->ignore_certificate_errors = true;
635   if (command_line.HasSwitch(switches::kTestingFixedHttpPort)) {
636     globals_->testing_fixed_http_port =
637         GetSwitchValueAsInt(command_line, switches::kTestingFixedHttpPort);
638   }
639   if (command_line.HasSwitch(switches::kTestingFixedHttpsPort)) {
640     globals_->testing_fixed_https_port =
641         GetSwitchValueAsInt(command_line, switches::kTestingFixedHttpsPort);
642   }
643   ConfigureQuic(command_line);
644   if (command_line.HasSwitch(
645           switches::kEnableUserAlternateProtocolPorts)) {
646     globals_->enable_user_alternate_protocol_ports = true;
647   }
648   InitializeNetworkOptions(command_line);
649
650   net::HttpNetworkSession::Params session_params;
651   InitializeNetworkSessionParams(&session_params);
652   session_params.net_log = net_log_;
653   session_params.proxy_service =
654       globals_->proxy_script_fetcher_proxy_service.get();
655
656   TRACE_EVENT_BEGIN0("startup", "IOThread::InitAsync:HttpNetworkSession");
657   scoped_refptr<net::HttpNetworkSession> network_session(
658       new net::HttpNetworkSession(session_params));
659   globals_->proxy_script_fetcher_http_transaction_factory
660       .reset(new net::HttpNetworkLayer(network_session.get()));
661   TRACE_EVENT_END0("startup", "IOThread::InitAsync:HttpNetworkSession");
662   scoped_ptr<net::URLRequestJobFactoryImpl> job_factory(
663       new net::URLRequestJobFactoryImpl());
664   job_factory->SetProtocolHandler(content::kDataScheme,
665                                   new net::DataProtocolHandler());
666   job_factory->SetProtocolHandler(
667       content::kFileScheme,
668       new net::FileProtocolHandler(
669           content::BrowserThread::GetBlockingPool()->
670               GetTaskRunnerWithShutdownBehavior(
671                   base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)));
672 #if !defined(DISABLE_FTP_SUPPORT)
673   globals_->proxy_script_fetcher_ftp_transaction_factory.reset(
674       new net::FtpNetworkLayer(globals_->host_resolver.get()));
675   job_factory->SetProtocolHandler(
676       content::kFtpScheme,
677       new net::FtpProtocolHandler(
678           globals_->proxy_script_fetcher_ftp_transaction_factory.get()));
679 #endif
680   globals_->proxy_script_fetcher_url_request_job_factory =
681       job_factory.PassAs<net::URLRequestJobFactory>();
682
683   globals_->throttler_manager.reset(new net::URLRequestThrottlerManager());
684   globals_->throttler_manager->set_net_log(net_log_);
685   // Always done in production, disabled only for unit tests.
686   globals_->throttler_manager->set_enable_thread_checks(true);
687
688   globals_->proxy_script_fetcher_context.reset(
689       ConstructProxyScriptFetcherContext(globals_, net_log_));
690
691   globals_->network_time_notifier.reset(
692       new net::NetworkTimeNotifier(
693           scoped_ptr<base::TickClock>(new base::DefaultTickClock())));
694
695   sdch_manager_ = new net::SdchManager();
696
697 #if defined(OS_MACOSX) && !defined(OS_IOS)
698   // Start observing Keychain events. This needs to be done on the UI thread,
699   // as Keychain services requires a CFRunLoop.
700   BrowserThread::PostTask(BrowserThread::UI,
701                           FROM_HERE,
702                           base::Bind(&ObserveKeychainEvents));
703 #endif
704
705   // InitSystemRequestContext turns right around and posts a task back
706   // to the IO thread, so we can't let it run until we know the IO
707   // thread has started.
708   //
709   // Note that since we are at BrowserThread::Init time, the UI thread
710   // is blocked waiting for the thread to start.  Therefore, posting
711   // this task to the main thread's message loop here is guaranteed to
712   // get it onto the message loop while the IOThread object still
713   // exists.  However, the message might not be processed on the UI
714   // thread until after IOThread is gone, so use a weak pointer.
715   BrowserThread::PostTask(BrowserThread::UI,
716                           FROM_HERE,
717                           base::Bind(&IOThread::InitSystemRequestContext,
718                                      weak_factory_.GetWeakPtr()));
719 }
720
721 void IOThread::CleanUp() {
722   base::debug::LeakTracker<SafeBrowsingURLRequestContext>::CheckForLeaks();
723
724   delete sdch_manager_;
725   sdch_manager_ = NULL;
726
727 #if defined(USE_NSS) || defined(OS_IOS)
728   net::ShutdownNSSHttpIO();
729 #endif
730
731   system_url_request_context_getter_ = NULL;
732
733   // Release objects that the net::URLRequestContext could have been pointing
734   // to.
735
736   // Shutdown the HistogramWatcher on the IO thread.
737   net::NetworkChangeNotifier::ShutdownHistogramWatcher();
738
739   // This must be reset before the ChromeNetLog is destroyed.
740   network_change_observer_.reset();
741
742   system_proxy_config_service_.reset();
743
744   delete globals_;
745   globals_ = NULL;
746
747   base::debug::LeakTracker<SystemURLRequestContextGetter>::CheckForLeaks();
748 }
749
750 void IOThread::InitializeNetworkOptions(const CommandLine& command_line) {
751   // Only handle use-spdy command line flags if "spdy.disabled" preference is
752   // not disabled via policy.
753   if (is_spdy_disabled_by_policy_) {
754     base::FieldTrial* trial = base::FieldTrialList::Find(kSpdyFieldTrialName);
755     if (trial)
756       trial->Disable();
757   } else {
758     std::string spdy_trial_group =
759         base::FieldTrialList::FindFullName(kSpdyFieldTrialName);
760
761     if (command_line.HasSwitch(switches::kEnableWebSocketOverSpdy)) {
762       // Enable WebSocket over SPDY.
763       net::WebSocketJob::set_websocket_over_spdy_enabled(true);
764     }
765
766     if (command_line.HasSwitch(switches::kTrustedSpdyProxy)) {
767       globals_->trusted_spdy_proxy.set(
768           command_line.GetSwitchValueASCII(switches::kTrustedSpdyProxy));
769     }
770     if (command_line.HasSwitch(switches::kIgnoreUrlFetcherCertRequests))
771       net::URLFetcher::SetIgnoreCertificateRequests(true);
772
773     if (command_line.HasSwitch(switches::kUseSpdy)) {
774       std::string spdy_mode =
775           command_line.GetSwitchValueASCII(switches::kUseSpdy);
776       EnableSpdy(spdy_mode);
777     } else if (command_line.HasSwitch(switches::kEnableSpdy4)) {
778       net::HttpStreamFactory::EnableNpnSpdy4Http2();
779     } else if (command_line.HasSwitch(switches::kDisableSpdy31)) {
780       net::HttpStreamFactory::EnableNpnSpdy3();
781     } else if (command_line.HasSwitch(switches::kEnableNpnHttpOnly)) {
782       net::HttpStreamFactory::EnableNpnHttpOnly();
783     } else {
784       if (spdy_trial_group == kSpdyFieldTrialDisabledGroupName &&
785           !command_line.HasSwitch(switches::kEnableWebSocketOverSpdy)) {
786          net::HttpStreamFactory::set_spdy_enabled(false);
787       } else {
788         // Use SPDY/3.1 by default.
789         net::HttpStreamFactory::EnableNpnSpdy31();
790       }
791     }
792   }
793
794   // TODO(rch): Make the client socket factory a per-network session
795   // instance, constructed from a NetworkSession::Params, to allow us
796   // to move this option to IOThread::Globals &
797   // HttpNetworkSession::Params.
798   if (command_line.HasSwitch(switches::kEnableTcpFastOpen))
799     net::SetTCPFastOpenEnabled(true);
800 }
801
802 void IOThread::EnableSpdy(const std::string& mode) {
803   static const char kOff[] = "off";
804   static const char kSSL[] = "ssl";
805   static const char kDisableSSL[] = "no-ssl";
806   static const char kDisablePing[] = "no-ping";
807   static const char kExclude[] = "exclude";  // Hosts to exclude
808   static const char kDisableCompression[] = "no-compress";
809   static const char kDisableAltProtocols[] = "no-alt-protocols";
810   static const char kForceAltProtocols[] = "force-alt-protocols";
811   static const char kSingleDomain[] = "single-domain";
812
813   static const char kInitialMaxConcurrentStreams[] = "init-max-streams";
814
815   std::vector<std::string> spdy_options;
816   base::SplitString(mode, ',', &spdy_options);
817
818   for (std::vector<std::string>::iterator it = spdy_options.begin();
819        it != spdy_options.end(); ++it) {
820     const std::string& element = *it;
821     std::vector<std::string> name_value;
822     base::SplitString(element, '=', &name_value);
823     const std::string& option =
824         name_value.size() > 0 ? name_value[0] : std::string();
825     const std::string value =
826         name_value.size() > 1 ? name_value[1] : std::string();
827
828     if (option == kOff) {
829       net::HttpStreamFactory::set_spdy_enabled(false);
830     } else if (option == kDisableSSL) {
831       globals_->spdy_default_protocol.set(net::kProtoSPDY3);
832       net::HttpStreamFactory::set_force_spdy_over_ssl(false);
833       net::HttpStreamFactory::set_force_spdy_always(true);
834     } else if (option == kSSL) {
835       globals_->spdy_default_protocol.set(net::kProtoSPDY3);
836       net::HttpStreamFactory::set_force_spdy_over_ssl(true);
837       net::HttpStreamFactory::set_force_spdy_always(true);
838     } else if (option == kDisablePing) {
839       globals_->enable_spdy_ping_based_connection_checking.set(false);
840     } else if (option == kExclude) {
841       net::HttpStreamFactory::add_forced_spdy_exclusion(value);
842     } else if (option == kDisableCompression) {
843       globals_->enable_spdy_compression.set(false);
844     } else if (option == kDisableAltProtocols) {
845       net::HttpStreamFactory::set_use_alternate_protocols(false);
846     } else if (option == kForceAltProtocols) {
847       net::PortAlternateProtocolPair pair;
848       pair.port = 443;
849       pair.protocol = net::NPN_SPDY_3;
850       net::HttpServerPropertiesImpl::ForceAlternateProtocol(pair);
851     } else if (option == kSingleDomain) {
852       DVLOG(1) << "FORCING SINGLE DOMAIN";
853       globals_->force_spdy_single_domain.set(true);
854     } else if (option == kInitialMaxConcurrentStreams) {
855       int streams;
856       if (base::StringToInt(value, &streams))
857         globals_->initial_max_spdy_concurrent_streams.set(streams);
858     } else if (option.empty() && it == spdy_options.begin()) {
859       continue;
860     } else {
861       LOG(DFATAL) << "Unrecognized spdy option: " << option;
862     }
863   }
864 }
865
866 // static
867 void IOThread::RegisterPrefs(PrefRegistrySimple* registry) {
868   registry->RegisterStringPref(prefs::kAuthSchemes,
869                                "basic,digest,ntlm,negotiate,"
870                                "spdyproxy");
871   registry->RegisterBooleanPref(prefs::kDisableAuthNegotiateCnameLookup, false);
872   registry->RegisterBooleanPref(prefs::kEnableAuthNegotiatePort, false);
873   registry->RegisterStringPref(prefs::kAuthServerWhitelist, std::string());
874   registry->RegisterStringPref(prefs::kAuthNegotiateDelegateWhitelist,
875                                std::string());
876   registry->RegisterStringPref(prefs::kGSSAPILibraryName, std::string());
877   registry->RegisterStringPref(
878       data_reduction_proxy::prefs::kDataReductionProxy, std::string());
879   registry->RegisterBooleanPref(prefs::kEnableReferrers, true);
880   data_reduction_proxy::RegisterPrefs(registry);
881   registry->RegisterBooleanPref(prefs::kBuiltInDnsClientEnabled, true);
882   registry->RegisterBooleanPref(prefs::kQuickCheckEnabled, true);
883 }
884
885 net::HttpAuthHandlerFactory* IOThread::CreateDefaultAuthHandlerFactory(
886     net::HostResolver* resolver) {
887   net::HttpAuthFilterWhitelist* auth_filter_default_credentials = NULL;
888   if (!auth_server_whitelist_.empty()) {
889     auth_filter_default_credentials =
890         new net::HttpAuthFilterWhitelist(auth_server_whitelist_);
891   }
892   net::HttpAuthFilterWhitelist* auth_filter_delegate = NULL;
893   if (!auth_delegate_whitelist_.empty()) {
894     auth_filter_delegate =
895         new net::HttpAuthFilterWhitelist(auth_delegate_whitelist_);
896   }
897   globals_->url_security_manager.reset(
898       net::URLSecurityManager::Create(auth_filter_default_credentials,
899                                       auth_filter_delegate));
900   std::vector<std::string> supported_schemes;
901   base::SplitString(auth_schemes_, ',', &supported_schemes);
902
903   scoped_ptr<net::HttpAuthHandlerRegistryFactory> registry_factory(
904       net::HttpAuthHandlerRegistryFactory::Create(
905           supported_schemes, globals_->url_security_manager.get(),
906           resolver, gssapi_library_name_, negotiate_disable_cname_lookup_,
907           negotiate_enable_port_));
908
909   if (!spdyproxy_auth_origins_.empty()) {
910     registry_factory->RegisterSchemeFactory(
911         "spdyproxy",
912         new data_reduction_proxy::HttpAuthHandlerDataReductionProxy::Factory(
913             spdyproxy_auth_origins_));
914   }
915
916   return registry_factory.release();
917 }
918
919 void IOThread::ClearHostCache() {
920   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
921
922   net::HostCache* host_cache = globals_->host_resolver->GetHostCache();
923   if (host_cache)
924     host_cache->clear();
925 }
926
927 void IOThread::InitializeNetworkSessionParams(
928     net::HttpNetworkSession::Params* params) {
929   params->host_resolver = globals_->host_resolver.get();
930   params->cert_verifier = globals_->cert_verifier.get();
931   params->server_bound_cert_service =
932       globals_->system_server_bound_cert_service.get();
933   params->transport_security_state = globals_->transport_security_state.get();
934   params->ssl_config_service = globals_->ssl_config_service.get();
935   params->http_auth_handler_factory = globals_->http_auth_handler_factory.get();
936   params->http_server_properties =
937       globals_->http_server_properties->GetWeakPtr();
938   params->network_delegate = globals_->system_network_delegate.get();
939   params->host_mapping_rules = globals_->host_mapping_rules.get();
940   params->ignore_certificate_errors = globals_->ignore_certificate_errors;
941   params->http_pipelining_enabled = globals_->http_pipelining_enabled;
942   params->testing_fixed_http_port = globals_->testing_fixed_http_port;
943   params->testing_fixed_https_port = globals_->testing_fixed_https_port;
944
945   globals_->initial_max_spdy_concurrent_streams.CopyToIfSet(
946       &params->spdy_initial_max_concurrent_streams);
947   globals_->force_spdy_single_domain.CopyToIfSet(
948       &params->force_spdy_single_domain);
949   globals_->enable_spdy_compression.CopyToIfSet(
950       &params->enable_spdy_compression);
951   globals_->enable_spdy_ping_based_connection_checking.CopyToIfSet(
952       &params->enable_spdy_ping_based_connection_checking);
953   globals_->spdy_default_protocol.CopyToIfSet(
954       &params->spdy_default_protocol);
955   globals_->trusted_spdy_proxy.CopyToIfSet(
956       &params->trusted_spdy_proxy);
957   globals_->enable_quic.CopyToIfSet(&params->enable_quic);
958   globals_->enable_quic_https.CopyToIfSet(&params->enable_quic_https);
959   globals_->enable_quic_pacing.CopyToIfSet(
960       &params->enable_quic_pacing);
961   globals_->enable_quic_time_based_loss_detection.CopyToIfSet(
962       &params->enable_quic_time_based_loss_detection);
963   globals_->enable_quic_persist_server_info.CopyToIfSet(
964       &params->enable_quic_persist_server_info);
965   globals_->enable_quic_port_selection.CopyToIfSet(
966       &params->enable_quic_port_selection);
967   globals_->quic_max_packet_length.CopyToIfSet(&params->quic_max_packet_length);
968   globals_->quic_supported_versions.CopyToIfSet(
969       &params->quic_supported_versions);
970   globals_->origin_to_force_quic_on.CopyToIfSet(
971       &params->origin_to_force_quic_on);
972   params->enable_user_alternate_protocol_ports =
973       globals_->enable_user_alternate_protocol_ports;
974 }
975
976 base::TimeTicks IOThread::creation_time() const {
977   return creation_time_;
978 }
979
980 net::SSLConfigService* IOThread::GetSSLConfigService() {
981   return ssl_config_service_manager_->Get();
982 }
983
984 void IOThread::ChangedToOnTheRecordOnIOThread() {
985   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
986
987   // Clear the host cache to avoid showing entries from the OTR session
988   // in about:net-internals.
989   ClearHostCache();
990 }
991
992 void IOThread::InitSystemRequestContext() {
993   if (system_url_request_context_getter_.get())
994     return;
995   // If we're in unit_tests, IOThread may not be run.
996   if (!BrowserThread::IsMessageLoopValid(BrowserThread::IO))
997     return;
998   system_proxy_config_service_.reset(
999       ProxyServiceFactory::CreateProxyConfigService(
1000           pref_proxy_config_tracker_.get()));
1001   system_url_request_context_getter_ =
1002       new SystemURLRequestContextGetter(this);
1003   // Safe to post an unretained this pointer, since IOThread is
1004   // guaranteed to outlive the IO BrowserThread.
1005   BrowserThread::PostTask(
1006       BrowserThread::IO,
1007       FROM_HERE,
1008       base::Bind(&IOThread::InitSystemRequestContextOnIOThread,
1009                  base::Unretained(this)));
1010 }
1011
1012 void IOThread::InitSystemRequestContextOnIOThread() {
1013   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1014   DCHECK(!globals_->system_proxy_service.get());
1015   DCHECK(system_proxy_config_service_.get());
1016
1017   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
1018   globals_->system_proxy_service.reset(
1019       ProxyServiceFactory::CreateProxyService(
1020           net_log_,
1021           globals_->proxy_script_fetcher_context.get(),
1022           globals_->system_network_delegate.get(),
1023           system_proxy_config_service_.release(),
1024           command_line,
1025           quick_check_enabled_.GetValue()));
1026
1027   net::HttpNetworkSession::Params system_params;
1028   InitializeNetworkSessionParams(&system_params);
1029   system_params.net_log = net_log_;
1030   system_params.proxy_service = globals_->system_proxy_service.get();
1031
1032   globals_->system_http_transaction_factory.reset(
1033       new net::HttpNetworkLayer(
1034           new net::HttpNetworkSession(system_params)));
1035   globals_->system_request_context.reset(
1036       ConstructSystemRequestContext(globals_, net_log_));
1037
1038   sdch_manager_->set_sdch_fetcher(
1039       new SdchDictionaryFetcher(system_url_request_context_getter_.get()));
1040 }
1041
1042 void IOThread::UpdateDnsClientEnabled() {
1043   globals()->host_resolver->SetDnsClientEnabled(*dns_client_enabled_);
1044 }
1045
1046 void IOThread::ConfigureQuic(const CommandLine& command_line) {
1047   // Always fetch the field trial group to ensure it is reported correctly.
1048   // The command line flags will be associated with a group that is reported
1049   // so long as trial is actually queried.
1050   std::string quic_trial_group =
1051       base::FieldTrialList::FindFullName(kQuicFieldTrialName);
1052
1053   bool enable_quic = ShouldEnableQuic(command_line, quic_trial_group);
1054   globals_->enable_quic.set(enable_quic);
1055   if (enable_quic) {
1056     globals_->enable_quic_https.set(
1057         ShouldEnableQuicHttps(command_line, quic_trial_group));
1058     globals_->enable_quic_pacing.set(
1059         ShouldEnableQuicPacing(command_line, quic_trial_group));
1060     globals_->enable_quic_time_based_loss_detection.set(
1061         ShouldEnableQuicTimeBasedLossDetection(command_line, quic_trial_group));
1062     globals_->enable_quic_persist_server_info.set(
1063         ShouldEnableQuicPersistServerInfo(command_line));
1064     globals_->enable_quic_port_selection.set(
1065         ShouldEnableQuicPortSelection(command_line));
1066   }
1067
1068   size_t max_packet_length = GetQuicMaxPacketLength(command_line,
1069                                                     quic_trial_group);
1070   if (max_packet_length != 0) {
1071     globals_->quic_max_packet_length.set(max_packet_length);
1072   }
1073
1074   net::QuicVersion version = GetQuicVersion(command_line);
1075   if (version != net::QUIC_VERSION_UNSUPPORTED) {
1076     net::QuicVersionVector supported_versions;
1077     supported_versions.push_back(version);
1078     globals_->quic_supported_versions.set(supported_versions);
1079   }
1080
1081   if (command_line.HasSwitch(switches::kOriginToForceQuicOn)) {
1082     net::HostPortPair quic_origin =
1083         net::HostPortPair::FromString(
1084             command_line.GetSwitchValueASCII(switches::kOriginToForceQuicOn));
1085     if (!quic_origin.IsEmpty()) {
1086       globals_->origin_to_force_quic_on.set(quic_origin);
1087     }
1088   }
1089 }
1090
1091 bool IOThread::ShouldEnableQuic(const CommandLine& command_line,
1092                                 base::StringPiece quic_trial_group) {
1093   if (command_line.HasSwitch(switches::kDisableQuic))
1094     return false;
1095
1096   if (command_line.HasSwitch(switches::kEnableQuic))
1097     return true;
1098
1099   return quic_trial_group.starts_with(kQuicFieldTrialEnabledGroupName) ||
1100       quic_trial_group.starts_with(kQuicFieldTrialHttpsEnabledGroupName);
1101 }
1102
1103 bool IOThread::ShouldEnableQuicHttps(const CommandLine& command_line,
1104                                      base::StringPiece quic_trial_group) {
1105   if (command_line.HasSwitch(switches::kDisableQuicHttps))
1106     return false;
1107
1108   if (command_line.HasSwitch(switches::kEnableQuicHttps))
1109     return true;
1110
1111   return quic_trial_group.starts_with(kQuicFieldTrialHttpsEnabledGroupName);
1112 }
1113
1114 bool IOThread::ShouldEnableQuicPortSelection(
1115       const CommandLine& command_line) {
1116   if (command_line.HasSwitch(switches::kDisableQuicPortSelection))
1117     return false;
1118
1119   if (command_line.HasSwitch(switches::kEnableQuicPortSelection))
1120     return true;
1121
1122 #if defined(OS_WIN)
1123   chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel();
1124   // Avoid picking ports (which might induce a security dialog) when we have a
1125   // beta or stable release.  Allow in all other cases, including when we do a
1126   // developer build (CHANNEL_UNKNOWN).
1127   if (channel == chrome::VersionInfo::CHANNEL_STABLE ||
1128       channel == chrome::VersionInfo::CHANNEL_BETA) {
1129     // TODO(grt) bug=329255: Detect presence of rule on Windows that allows us
1130     // to do port selection without inducing a dialog.
1131     // When we have an API to see if the administrative security manager will
1132     // allow port selection without a security dialog, we may return true if
1133     // we're sure there will be no security dialog.
1134     return false;
1135   }
1136   return true;
1137 #else
1138   return true;
1139 #endif
1140 }
1141
1142 bool IOThread::ShouldEnableQuicPacing(const CommandLine& command_line,
1143                                       base::StringPiece quic_trial_group) {
1144   if (command_line.HasSwitch(switches::kEnableQuicPacing))
1145     return true;
1146
1147   if (command_line.HasSwitch(switches::kDisableQuicPacing))
1148     return false;
1149
1150   return quic_trial_group.ends_with(kQuicFieldTrialPacingSuffix);
1151 }
1152
1153 bool IOThread::ShouldEnableQuicTimeBasedLossDetection(
1154     const CommandLine& command_line,
1155     base::StringPiece quic_trial_group) {
1156   if (command_line.HasSwitch(switches::kEnableQuicTimeBasedLossDetection))
1157     return true;
1158
1159   if (command_line.HasSwitch(switches::kDisableQuicTimeBasedLossDetection))
1160     return false;
1161
1162   return quic_trial_group.ends_with(
1163       kQuicFieldTrialTimeBasedLossDetectionSuffix);
1164 }
1165
1166 bool IOThread::ShouldEnableQuicPersistServerInfo(
1167     const CommandLine& command_line) {
1168   chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel();
1169   // Avoid persisting of Quic server config information to disk cache when we
1170   // have a beta or stable release.  Allow in all other cases, including when we
1171   // do a developer build (CHANNEL_UNKNOWN).
1172   if (channel == chrome::VersionInfo::CHANNEL_STABLE ||
1173       channel == chrome::VersionInfo::CHANNEL_BETA) {
1174     return false;
1175   }
1176   return true;
1177 }
1178
1179 size_t IOThread::GetQuicMaxPacketLength(const CommandLine& command_line,
1180                                         base::StringPiece quic_trial_group) {
1181   if (command_line.HasSwitch(switches::kQuicMaxPacketLength)) {
1182     unsigned value;
1183     if (!base::StringToUint(
1184             command_line.GetSwitchValueASCII(switches::kQuicMaxPacketLength),
1185             &value)) {
1186       return 0;
1187     }
1188     return value;
1189   }
1190
1191   // Format of the packet length group names is:
1192   //   (Https)?Enabled<length>BytePackets.
1193   base::StringPiece length_str(quic_trial_group);
1194   if (length_str.starts_with(kQuicFieldTrialEnabledGroupName)) {
1195     length_str.remove_prefix(strlen(kQuicFieldTrialEnabledGroupName));
1196   } else if (length_str.starts_with(kQuicFieldTrialHttpsEnabledGroupName)) {
1197     length_str.remove_prefix(strlen(kQuicFieldTrialHttpsEnabledGroupName));
1198   } else {
1199     return 0;
1200   }
1201   if (!length_str.ends_with(kQuicFieldTrialPacketLengthSuffix)) {
1202     return 0;
1203   }
1204   length_str.remove_suffix(strlen(kQuicFieldTrialPacketLengthSuffix));
1205   unsigned value;
1206   if (!base::StringToUint(length_str, &value)) {
1207     return 0;
1208   }
1209   return value;
1210 }
1211
1212 net::QuicVersion IOThread::GetQuicVersion(const CommandLine& command_line) {
1213   if (!command_line.HasSwitch(switches::kQuicVersion)) {
1214     return net::QUIC_VERSION_UNSUPPORTED;
1215   }
1216   net::QuicVersionVector supported_versions = net::QuicSupportedVersions();
1217   std::string version_flag =
1218       command_line.GetSwitchValueASCII(switches::kQuicVersion);
1219   for (size_t i = 0; i < supported_versions.size(); ++i) {
1220     net::QuicVersion version = supported_versions[i];
1221     if (net::QuicVersionToString(version) == version_flag) {
1222       return version;
1223     }
1224   }
1225   return net::QUIC_VERSION_UNSUPPORTED;
1226 }