profile_io_data.cc revision 558790d6acca3451cf3a6b497803a5f07d0bec58
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/profiles/profile_io_data.h"
6
7#include <string>
8
9#include "base/basictypes.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/alias.h"
15#include "base/logging.h"
16#include "base/path_service.h"
17#include "base/prefs/pref_service.h"
18#include "base/stl_util.h"
19#include "base/strings/string_number_conversions.h"
20#include "base/strings/string_util.h"
21#include "base/strings/stringprintf.h"
22#include "chrome/browser/browser_process.h"
23#include "chrome/browser/chrome_notification_types.h"
24#include "chrome/browser/content_settings/cookie_settings.h"
25#include "chrome/browser/content_settings/host_content_settings_map.h"
26#include "chrome/browser/custom_handlers/protocol_handler_registry.h"
27#include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h"
28#include "chrome/browser/download/download_service.h"
29#include "chrome/browser/download/download_service_factory.h"
30#include "chrome/browser/extensions/extension_info_map.h"
31#include "chrome/browser/extensions/extension_protocols.h"
32#include "chrome/browser/extensions/extension_resource_protocols.h"
33#include "chrome/browser/extensions/extension_system.h"
34#include "chrome/browser/io_thread.h"
35#include "chrome/browser/net/about_protocol_handler.h"
36#include "chrome/browser/net/chrome_cookie_notification_details.h"
37#include "chrome/browser/net/chrome_fraudulent_certificate_reporter.h"
38#include "chrome/browser/net/chrome_http_user_agent_settings.h"
39#include "chrome/browser/net/chrome_net_log.h"
40#include "chrome/browser/net/chrome_network_delegate.h"
41#include "chrome/browser/net/evicted_domain_cookie_counter.h"
42#include "chrome/browser/net/load_time_stats.h"
43#include "chrome/browser/net/proxy_service_factory.h"
44#include "chrome/browser/net/resource_prefetch_predictor_observer.h"
45#include "chrome/browser/net/transport_security_persister.h"
46#include "chrome/browser/notifications/desktop_notification_service_factory.h"
47#include "chrome/browser/policy/url_blacklist_manager.h"
48#include "chrome/browser/predictors/resource_prefetch_predictor.h"
49#include "chrome/browser/predictors/resource_prefetch_predictor_factory.h"
50#include "chrome/browser/profiles/profile.h"
51#include "chrome/browser/profiles/profile_manager.h"
52#include "chrome/browser/signin/signin_names_io_thread.h"
53#include "chrome/common/chrome_paths.h"
54#include "chrome/common/chrome_switches.h"
55#include "chrome/common/pref_names.h"
56#include "chrome/common/startup_metric_utils.h"
57#include "chrome/common/url_constants.h"
58#include "content/public/browser/browser_thread.h"
59#include "content/public/browser/host_zoom_map.h"
60#include "content/public/browser/notification_service.h"
61#include "content/public/browser/resource_context.h"
62#include "extensions/common/constants.h"
63#include "net/cert/cert_verifier.h"
64#include "net/cookies/canonical_cookie.h"
65#include "net/cookies/cookie_monster.h"
66#include "net/http/http_transaction_factory.h"
67#include "net/http/http_util.h"
68#include "net/proxy/proxy_config_service_fixed.h"
69#include "net/proxy/proxy_script_fetcher_impl.h"
70#include "net/proxy/proxy_service.h"
71#include "net/ssl/server_bound_cert_service.h"
72#include "net/url_request/data_protocol_handler.h"
73#include "net/url_request/file_protocol_handler.h"
74#include "net/url_request/ftp_protocol_handler.h"
75#include "net/url_request/protocol_intercept_job_factory.h"
76#include "net/url_request/url_request.h"
77#include "net/url_request/url_request_file_job.h"
78#include "net/url_request/url_request_job_factory_impl.h"
79
80#if defined(ENABLE_MANAGED_USERS)
81#include "chrome/browser/managed_mode/managed_mode_url_filter.h"
82#include "chrome/browser/managed_mode/managed_user_service.h"
83#include "chrome/browser/managed_mode/managed_user_service_factory.h"
84#endif
85
86#if defined(OS_CHROMEOS)
87#include "chrome/browser/chromeos/drive/drive_protocol_handler.h"
88#include "chrome/browser/chromeos/policy/policy_cert_verifier.h"
89#include "chrome/browser/chromeos/settings/cros_settings.h"
90#include "chrome/browser/chromeos/settings/cros_settings_names.h"
91#include "chrome/browser/policy/browser_policy_connector.h"
92#endif  // defined(OS_CHROMEOS)
93
94using content::BrowserContext;
95using content::BrowserThread;
96using content::ResourceContext;
97
98namespace {
99
100// ----------------------------------------------------------------------------
101// CookieMonster::Delegate implementation
102// ----------------------------------------------------------------------------
103class ChromeCookieMonsterDelegate : public net::CookieMonster::Delegate {
104 public:
105  explicit ChromeCookieMonsterDelegate(
106      const base::Callback<Profile*(void)>& profile_getter)
107      : profile_getter_(profile_getter) {
108    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
109  }
110
111  // net::CookieMonster::Delegate implementation.
112  virtual void OnCookieChanged(
113      const net::CanonicalCookie& cookie,
114      bool removed,
115      net::CookieMonster::Delegate::ChangeCause cause) OVERRIDE {
116    BrowserThread::PostTask(
117        BrowserThread::UI, FROM_HERE,
118        base::Bind(&ChromeCookieMonsterDelegate::OnCookieChangedAsyncHelper,
119                   this, cookie, removed, cause));
120  }
121
122 private:
123  virtual ~ChromeCookieMonsterDelegate() {}
124
125  void OnCookieChangedAsyncHelper(
126      const net::CanonicalCookie& cookie,
127      bool removed,
128      net::CookieMonster::Delegate::ChangeCause cause) {
129    Profile* profile = profile_getter_.Run();
130    if (profile) {
131      ChromeCookieDetails cookie_details(&cookie, removed, cause);
132      content::NotificationService::current()->Notify(
133          chrome::NOTIFICATION_COOKIE_CHANGED,
134          content::Source<Profile>(profile),
135          content::Details<ChromeCookieDetails>(&cookie_details));
136    }
137  }
138
139  const base::Callback<Profile*(void)> profile_getter_;
140};
141
142Profile* GetProfileOnUI(ProfileManager* profile_manager, Profile* profile) {
143  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
144  DCHECK(profile);
145  if (profile_manager->IsValidProfile(profile))
146    return profile;
147  return NULL;
148}
149
150#if defined(DEBUG_DEVTOOLS)
151bool IsSupportedDevToolsURL(const GURL& url, base::FilePath* path) {
152  std::string bundled_path_prefix(chrome::kChromeUIDevToolsBundledPath);
153  bundled_path_prefix = "/" + bundled_path_prefix + "/";
154
155  if (!url.SchemeIs(chrome::kChromeDevToolsScheme) ||
156      url.host() != chrome::kChromeUIDevToolsHost ||
157      !StartsWithASCII(url.path(), bundled_path_prefix, false)) {
158    return false;
159  }
160
161  if (!url.is_valid()) {
162    NOTREACHED();
163    return false;
164  }
165
166  // Remove Query and Ref from URL.
167  GURL stripped_url;
168  GURL::Replacements replacements;
169  replacements.ClearQuery();
170  replacements.ClearRef();
171  stripped_url = url.ReplaceComponents(replacements);
172
173  std::string relative_path;
174  const std::string& spec = stripped_url.possibly_invalid_spec();
175  const url_parse::Parsed& parsed =
176      stripped_url.parsed_for_possibly_invalid_spec();
177  int offset = parsed.CountCharactersBefore(url_parse::Parsed::PATH, false);
178  if (offset < static_cast<int>(spec.size()))
179    relative_path.assign(spec.substr(offset + bundled_path_prefix.length()));
180
181  // Check that |relative_path| is not an absolute path (otherwise
182  // AppendASCII() will DCHECK).  The awkward use of StringType is because on
183  // some systems FilePath expects a std::string, but on others a std::wstring.
184  base::FilePath p(
185      base::FilePath::StringType(relative_path.begin(), relative_path.end()));
186  if (p.IsAbsolute())
187    return false;
188
189  base::FilePath inspector_dir;
190  if (!PathService::Get(chrome::DIR_INSPECTOR, &inspector_dir))
191    return false;
192
193  if (inspector_dir.empty())
194    return false;
195
196  *path = inspector_dir.AppendASCII(relative_path);
197  return true;
198}
199
200class DebugDevToolsInterceptor
201    : public net::URLRequestJobFactory::ProtocolHandler {
202 public:
203  DebugDevToolsInterceptor() {}
204  virtual ~DebugDevToolsInterceptor() {}
205
206  virtual net::URLRequestJob* MaybeCreateJob(
207      net::URLRequest* request,
208      net::NetworkDelegate* network_delegate) const OVERRIDE {
209    base::FilePath path;
210    if (IsSupportedDevToolsURL(request->url(), &path))
211      return new net::URLRequestFileJob(request, network_delegate, path);
212
213    return NULL;
214  }
215};
216#endif  // defined(DEBUG_DEVTOOLS)
217
218}  // namespace
219
220void ProfileIOData::InitializeOnUIThread(Profile* profile) {
221  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
222  PrefService* pref_service = profile->GetPrefs();
223  PrefService* local_state_pref_service = g_browser_process->local_state();
224
225  scoped_ptr<ProfileParams> params(new ProfileParams);
226  params->path = profile->GetPath();
227
228  params->io_thread = g_browser_process->io_thread();
229
230  params->cookie_settings = CookieSettings::Factory::GetForProfile(profile);
231  params->host_content_settings_map = profile->GetHostContentSettingsMap();
232  params->ssl_config_service = profile->GetSSLConfigService();
233  base::Callback<Profile*(void)> profile_getter =
234      base::Bind(&GetProfileOnUI, g_browser_process->profile_manager(),
235                 profile);
236  params->cookie_monster_delegate =
237      new chrome_browser_net::EvictedDomainCookieCounter(
238          new ChromeCookieMonsterDelegate(profile_getter));
239  params->extension_info_map =
240      extensions::ExtensionSystem::Get(profile)->info_map();
241
242  if (predictors::ResourcePrefetchPredictor* predictor =
243          predictors::ResourcePrefetchPredictorFactory::GetForProfile(
244              profile)) {
245    resource_prefetch_predictor_observer_.reset(
246        new chrome_browser_net::ResourcePrefetchPredictorObserver(predictor));
247  }
248
249#if defined(ENABLE_NOTIFICATIONS)
250  params->notification_service =
251      DesktopNotificationServiceFactory::GetForProfile(profile);
252#endif
253
254  ProtocolHandlerRegistry* protocol_handler_registry =
255      ProtocolHandlerRegistryFactory::GetForProfile(profile);
256  DCHECK(protocol_handler_registry);
257
258  // The profile instance is only available here in the InitializeOnUIThread
259  // method, so we create the url job factory here, then save it for
260  // later delivery to the job factory in Init().
261  params->protocol_handler_interceptor =
262      protocol_handler_registry->CreateJobInterceptorFactory();
263
264  params->proxy_config_service
265      .reset(ProxyServiceFactory::CreateProxyConfigService(
266           profile->GetProxyConfigTracker()));
267#if defined(ENABLE_MANAGED_USERS)
268  ManagedUserService* managed_user_service =
269      ManagedUserServiceFactory::GetForProfile(profile);
270  params->managed_mode_url_filter =
271      managed_user_service->GetURLFilterForIOThread();
272#endif
273#if defined(OS_CHROMEOS)
274  policy::BrowserPolicyConnector* connector =
275      g_browser_process->browser_policy_connector();
276  params->trust_anchor_provider = connector->GetCertTrustAnchorProvider();
277#endif
278
279  params->profile = profile;
280  profile_params_.reset(params.release());
281
282  ChromeNetworkDelegate::InitializePrefsOnUIThread(
283      &enable_referrers_,
284      &enable_do_not_track_,
285      &force_safesearch_,
286      pref_service);
287
288  scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy =
289      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
290#if defined(ENABLE_PRINTING)
291  printing_enabled_.Init(prefs::kPrintingEnabled, pref_service);
292  printing_enabled_.MoveToThread(io_message_loop_proxy);
293#endif
294  chrome_http_user_agent_settings_.reset(
295      new ChromeHttpUserAgentSettings(pref_service));
296
297  // These members are used only for one click sign in, which is not enabled
298  // in incognito mode.  So no need to initialize them.
299  if (!is_incognito()) {
300    signin_names_.reset(new SigninNamesOnIOThread());
301
302    google_services_username_.Init(
303        prefs::kGoogleServicesUsername, pref_service);
304    google_services_username_.MoveToThread(io_message_loop_proxy);
305
306    google_services_username_pattern_.Init(
307        prefs::kGoogleServicesUsernamePattern, local_state_pref_service);
308    google_services_username_pattern_.MoveToThread(io_message_loop_proxy);
309
310    reverse_autologin_enabled_.Init(
311        prefs::kReverseAutologinEnabled, pref_service);
312    reverse_autologin_enabled_.MoveToThread(io_message_loop_proxy);
313
314    one_click_signin_rejected_email_list_.Init(
315        prefs::kReverseAutologinRejectedEmailList, pref_service);
316    one_click_signin_rejected_email_list_.MoveToThread(io_message_loop_proxy);
317
318    sync_disabled_.Init(prefs::kSyncManaged, pref_service);
319    sync_disabled_.MoveToThread(io_message_loop_proxy);
320
321    signin_allowed_.Init(prefs::kSigninAllowed, pref_service);
322    signin_allowed_.MoveToThread(io_message_loop_proxy);
323  }
324
325  // The URLBlacklistManager has to be created on the UI thread to register
326  // observers of |pref_service|, and it also has to clean up on
327  // ShutdownOnUIThread to release these observers on the right thread.
328  // Don't pass it in |profile_params_| to make sure it is correctly cleaned up,
329  // in particular when this ProfileIOData isn't |initialized_| during deletion.
330#if defined(ENABLE_CONFIGURATION_POLICY)
331  url_blacklist_manager_.reset(new policy::URLBlacklistManager(pref_service));
332#endif
333
334  initialized_on_UI_thread_ = true;
335
336  // We need to make sure that content initializes its own data structures that
337  // are associated with each ResourceContext because we might post this
338  // object to the IO thread after this function.
339  BrowserContext::EnsureResourceContextInitialized(profile);
340}
341
342ProfileIOData::MediaRequestContext::MediaRequestContext(
343    chrome_browser_net::LoadTimeStats* load_time_stats)
344    : ChromeURLRequestContext(ChromeURLRequestContext::CONTEXT_TYPE_MEDIA,
345                              load_time_stats) {
346}
347
348void ProfileIOData::MediaRequestContext::SetHttpTransactionFactory(
349    scoped_ptr<net::HttpTransactionFactory> http_factory) {
350  http_factory_ = http_factory.Pass();
351  set_http_transaction_factory(http_factory_.get());
352}
353
354ProfileIOData::MediaRequestContext::~MediaRequestContext() {}
355
356ProfileIOData::AppRequestContext::AppRequestContext(
357    chrome_browser_net::LoadTimeStats* load_time_stats)
358    : ChromeURLRequestContext(ChromeURLRequestContext::CONTEXT_TYPE_APP,
359                              load_time_stats) {
360}
361
362void ProfileIOData::AppRequestContext::SetCookieStore(
363    net::CookieStore* cookie_store) {
364  cookie_store_ = cookie_store;
365  set_cookie_store(cookie_store);
366}
367
368void ProfileIOData::AppRequestContext::SetHttpTransactionFactory(
369    scoped_ptr<net::HttpTransactionFactory> http_factory) {
370  http_factory_ = http_factory.Pass();
371  set_http_transaction_factory(http_factory_.get());
372}
373
374void ProfileIOData::AppRequestContext::SetJobFactory(
375    scoped_ptr<net::URLRequestJobFactory> job_factory) {
376  job_factory_ = job_factory.Pass();
377  set_job_factory(job_factory_.get());
378}
379
380ProfileIOData::AppRequestContext::~AppRequestContext() {}
381
382ProfileIOData::ProfileParams::ProfileParams()
383    : io_thread(NULL),
384#if defined(ENABLE_NOTIFICATIONS)
385      notification_service(NULL),
386#endif
387#if defined(OS_CHROMEOS)
388      trust_anchor_provider(NULL),
389#endif
390      profile(NULL) {
391}
392
393ProfileIOData::ProfileParams::~ProfileParams() {}
394
395ProfileIOData::ProfileIOData(bool is_incognito)
396    : initialized_(false),
397#if defined(ENABLE_NOTIFICATIONS)
398      notification_service_(NULL),
399#endif
400      resource_context_(new ResourceContext(this)),
401      load_time_stats_(NULL),
402      initialized_on_UI_thread_(false),
403      is_incognito_(is_incognito) {
404  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
405}
406
407ProfileIOData::~ProfileIOData() {
408  if (BrowserThread::IsMessageLoopValid(BrowserThread::IO))
409    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
410
411  // Pull the contents of the request context maps onto the stack for sanity
412  // checking of values in a minidump. http://crbug.com/260425
413  size_t num_app_contexts = app_request_context_map_.size();
414  size_t num_media_contexts = isolated_media_request_context_map_.size();
415  size_t current_context = 0;
416  static const size_t kMaxCachedContexts = 20;
417  ChromeURLRequestContext* app_context_cache[kMaxCachedContexts] = {0};
418  void* app_context_vtable_cache[kMaxCachedContexts] = {0};
419  ChromeURLRequestContext* media_context_cache[kMaxCachedContexts] = {0};
420  void* media_context_vtable_cache[kMaxCachedContexts] = {0};
421  void* tmp_vtable = NULL;
422  base::debug::Alias(&num_app_contexts);
423  base::debug::Alias(&num_media_contexts);
424  base::debug::Alias(&current_context);
425  base::debug::Alias(app_context_cache);
426  base::debug::Alias(app_context_vtable_cache);
427  base::debug::Alias(media_context_cache);
428  base::debug::Alias(media_context_vtable_cache);
429  base::debug::Alias(&tmp_vtable);
430
431  current_context = 0;
432  for (URLRequestContextMap::const_iterator it =
433           app_request_context_map_.begin();
434       current_context < kMaxCachedContexts &&
435           it != app_request_context_map_.end();
436       ++it, ++current_context) {
437    app_context_cache[current_context] = it->second;
438    memcpy(&app_context_vtable_cache[current_context],
439           static_cast<void*>(it->second), sizeof(void*));
440  }
441
442  current_context = 0;
443  for (URLRequestContextMap::const_iterator it =
444           isolated_media_request_context_map_.begin();
445       current_context < kMaxCachedContexts &&
446           it != isolated_media_request_context_map_.end();
447       ++it, ++current_context) {
448    media_context_cache[current_context] = it->second;
449    memcpy(&media_context_vtable_cache[current_context],
450           static_cast<void*>(it->second), sizeof(void*));
451  }
452
453  // TODO(ajwong): These AssertNoURLRequests() calls are unnecessary since they
454  // are already done in the URLRequestContext destructor.
455  if (main_request_context_)
456    main_request_context_->AssertNoURLRequests();
457  if (extensions_request_context_)
458    extensions_request_context_->AssertNoURLRequests();
459
460  current_context = 0;
461  for (URLRequestContextMap::iterator it = app_request_context_map_.begin();
462       it != app_request_context_map_.end(); ++it) {
463    if (current_context < kMaxCachedContexts) {
464      CHECK_EQ(app_context_cache[current_context], it->second);
465      memcpy(&tmp_vtable, static_cast<void*>(it->second), sizeof(void*));
466      CHECK_EQ(app_context_vtable_cache[current_context], tmp_vtable);
467    }
468    it->second->AssertNoURLRequests();
469    delete it->second;
470    current_context++;
471  }
472
473  current_context = 0;
474  for (URLRequestContextMap::iterator it =
475           isolated_media_request_context_map_.begin();
476       it != isolated_media_request_context_map_.end(); ++it) {
477    if (current_context < kMaxCachedContexts) {
478      CHECK_EQ(media_context_cache[current_context], it->second);
479      memcpy(&tmp_vtable, static_cast<void*>(it->second), sizeof(void*));
480      CHECK_EQ(media_context_vtable_cache[current_context], tmp_vtable);
481    }
482    it->second->AssertNoURLRequests();
483    delete it->second;
484    current_context++;
485  }
486}
487
488// static
489ProfileIOData* ProfileIOData::FromResourceContext(
490    content::ResourceContext* rc) {
491  return (static_cast<ResourceContext*>(rc))->io_data_;
492}
493
494// static
495bool ProfileIOData::IsHandledProtocol(const std::string& scheme) {
496  DCHECK_EQ(scheme, StringToLowerASCII(scheme));
497  static const char* const kProtocolList[] = {
498    chrome::kFileScheme,
499    chrome::kChromeDevToolsScheme,
500    extensions::kExtensionScheme,
501    chrome::kExtensionResourceScheme,
502    chrome::kChromeUIScheme,
503    chrome::kDataScheme,
504#if defined(OS_CHROMEOS)
505    chrome::kDriveScheme,
506#endif  // defined(OS_CHROMEOS)
507    chrome::kAboutScheme,
508#if !defined(DISABLE_FTP_SUPPORT)
509    chrome::kFtpScheme,
510#endif  // !defined(DISABLE_FTP_SUPPORT)
511    chrome::kBlobScheme,
512    chrome::kFileSystemScheme,
513    chrome::kChromeSearchScheme,
514  };
515  for (size_t i = 0; i < arraysize(kProtocolList); ++i) {
516    if (scheme == kProtocolList[i])
517      return true;
518  }
519  return net::URLRequest::IsHandledProtocol(scheme);
520}
521
522// static
523bool ProfileIOData::IsHandledURL(const GURL& url) {
524  if (!url.is_valid()) {
525    // We handle error cases.
526    return true;
527  }
528
529  return IsHandledProtocol(url.scheme());
530}
531
532// static
533void ProfileIOData::InstallProtocolHandlers(
534    net::URLRequestJobFactoryImpl* job_factory,
535    content::ProtocolHandlerMap* protocol_handlers) {
536  for (content::ProtocolHandlerMap::iterator it =
537           protocol_handlers->begin();
538       it != protocol_handlers->end();
539       ++it) {
540    bool set_protocol = job_factory->SetProtocolHandler(
541        it->first, it->second.release());
542    DCHECK(set_protocol);
543  }
544  protocol_handlers->clear();
545}
546
547content::ResourceContext* ProfileIOData::GetResourceContext() const {
548  return resource_context_.get();
549}
550
551ChromeURLRequestContext* ProfileIOData::GetMainRequestContext() const {
552  DCHECK(initialized_);
553  return main_request_context_.get();
554}
555
556ChromeURLRequestContext* ProfileIOData::GetMediaRequestContext() const {
557  DCHECK(initialized_);
558  ChromeURLRequestContext* context = AcquireMediaRequestContext();
559  DCHECK(context);
560  return context;
561}
562
563ChromeURLRequestContext* ProfileIOData::GetExtensionsRequestContext() const {
564  DCHECK(initialized_);
565  return extensions_request_context_.get();
566}
567
568ChromeURLRequestContext* ProfileIOData::GetIsolatedAppRequestContext(
569    ChromeURLRequestContext* main_context,
570    const StoragePartitionDescriptor& partition_descriptor,
571    scoped_ptr<ProtocolHandlerRegistry::JobInterceptorFactory>
572        protocol_handler_interceptor,
573    content::ProtocolHandlerMap* protocol_handlers) const {
574  DCHECK(initialized_);
575  ChromeURLRequestContext* context = NULL;
576  if (ContainsKey(app_request_context_map_, partition_descriptor)) {
577    context = app_request_context_map_[partition_descriptor];
578  } else {
579    context = AcquireIsolatedAppRequestContext(
580        main_context, partition_descriptor, protocol_handler_interceptor.Pass(),
581        protocol_handlers);
582    app_request_context_map_[partition_descriptor] = context;
583  }
584  DCHECK(context);
585  return context;
586}
587
588ChromeURLRequestContext* ProfileIOData::GetIsolatedMediaRequestContext(
589    ChromeURLRequestContext* app_context,
590    const StoragePartitionDescriptor& partition_descriptor) const {
591  DCHECK(initialized_);
592  ChromeURLRequestContext* context = NULL;
593  if (ContainsKey(isolated_media_request_context_map_, partition_descriptor)) {
594    context = isolated_media_request_context_map_[partition_descriptor];
595  } else {
596    context = AcquireIsolatedMediaRequestContext(app_context,
597                                                 partition_descriptor);
598    isolated_media_request_context_map_[partition_descriptor] = context;
599  }
600  DCHECK(context);
601  return context;
602}
603
604ExtensionInfoMap* ProfileIOData::GetExtensionInfoMap() const {
605  DCHECK(initialized_) << "ExtensionSystem not initialized";
606  return extension_info_map_.get();
607}
608
609CookieSettings* ProfileIOData::GetCookieSettings() const {
610  // Allow either Init() or SetCookieSettingsForTesting() to initialize.
611  DCHECK(initialized_ || cookie_settings_.get());
612  return cookie_settings_.get();
613}
614
615HostContentSettingsMap* ProfileIOData::GetHostContentSettingsMap() const {
616  DCHECK(initialized_);
617  return host_content_settings_map_.get();
618}
619
620#if defined(ENABLE_NOTIFICATIONS)
621DesktopNotificationService* ProfileIOData::GetNotificationService() const {
622  DCHECK(initialized_);
623  return notification_service_;
624}
625#endif
626
627void ProfileIOData::InitializeMetricsEnabledStateOnUIThread() {
628  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
629#if defined(OS_CHROMEOS)
630  // Just fetch the value from ChromeOS' settings while we're on the UI thread.
631  // TODO(stevet): For now, this value is only set on profile initialization.
632  // We will want to do something similar to the PrefMember method below in the
633  // future to more accurately capture this state.
634  chromeos::CrosSettings::Get()->GetBoolean(chromeos::kStatsReportingPref,
635                                            &enable_metrics_);
636#elif defined(OS_ANDROID)
637  // TODO(dwkang): rename or unify the pref for UMA once we have conclusion
638  // in crbugs.com/246495.
639  // Android has it's own preferences for metrics / crash uploading.
640  enable_metrics_.Init(prefs::kCrashReportingEnabled,
641                       g_browser_process->local_state());
642  enable_metrics_.MoveToThread(
643      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO));
644#else
645  // Prep the PrefMember and send it to the IO thread, since this value will be
646  // read from there.
647  enable_metrics_.Init(prefs::kMetricsReportingEnabled,
648                       g_browser_process->local_state());
649  enable_metrics_.MoveToThread(
650      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO));
651#endif  // defined(OS_CHROMEOS)
652}
653
654bool ProfileIOData::GetMetricsEnabledStateOnIOThread() const {
655  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
656#if defined(OS_CHROMEOS)
657  return enable_metrics_;
658#else
659  return enable_metrics_.GetValue();
660#endif  // defined(OS_CHROMEOS)
661}
662
663base::WeakPtr<net::HttpServerProperties>
664ProfileIOData::http_server_properties() const {
665  return http_server_properties_->GetWeakPtr();
666}
667
668void ProfileIOData::set_http_server_properties(
669    scoped_ptr<net::HttpServerProperties> http_server_properties) const {
670  http_server_properties_ = http_server_properties.Pass();
671}
672
673ProfileIOData::ResourceContext::ResourceContext(ProfileIOData* io_data)
674    : io_data_(io_data),
675      host_resolver_(NULL),
676      request_context_(NULL) {
677  DCHECK(io_data);
678}
679
680ProfileIOData::ResourceContext::~ResourceContext() {}
681
682net::HostResolver* ProfileIOData::ResourceContext::GetHostResolver()  {
683  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
684  DCHECK(io_data_->initialized_);
685  return host_resolver_;
686}
687
688net::URLRequestContext* ProfileIOData::ResourceContext::GetRequestContext()  {
689  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
690  DCHECK(io_data_->initialized_);
691  return request_context_;
692}
693
694// static
695std::string ProfileIOData::GetSSLSessionCacheShard() {
696  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
697  // The SSL session cache is partitioned by setting a string. This returns a
698  // unique string to partition the SSL session cache. Each time we create a
699  // new profile, we'll get a fresh SSL session cache which is separate from
700  // the other profiles.
701  static unsigned ssl_session_cache_instance = 0;
702  return base::StringPrintf("profile/%u", ssl_session_cache_instance++);
703}
704
705void ProfileIOData::Init(content::ProtocolHandlerMap* protocol_handlers) const {
706  // The basic logic is implemented here. The specific initialization
707  // is done in InitializeInternal(), implemented by subtypes. Static helper
708  // functions have been provided to assist in common operations.
709  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
710  DCHECK(!initialized_);
711
712  startup_metric_utils::ScopedSlowStartupUMA
713      scoped_timer("Startup.SlowStartupProfileIODataInit");
714
715  // TODO(jhawkins): Remove once crbug.com/102004 is fixed.
716  CHECK(initialized_on_UI_thread_);
717
718  // TODO(jhawkins): Return to DCHECK once crbug.com/102004 is fixed.
719  CHECK(profile_params_.get());
720
721  IOThread* const io_thread = profile_params_->io_thread;
722  IOThread::Globals* const io_thread_globals = io_thread->globals();
723  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
724  load_time_stats_ = GetLoadTimeStats(io_thread_globals);
725
726  // Create the common request contexts.
727  main_request_context_.reset(
728      new ChromeURLRequestContext(ChromeURLRequestContext::CONTEXT_TYPE_MAIN,
729                                  load_time_stats_));
730  extensions_request_context_.reset(
731      new ChromeURLRequestContext(
732          ChromeURLRequestContext::CONTEXT_TYPE_EXTENSIONS,
733          load_time_stats_));
734
735  ChromeNetworkDelegate* network_delegate =
736      new ChromeNetworkDelegate(
737          io_thread_globals->extension_event_router_forwarder.get(),
738          &enable_referrers_);
739  network_delegate->set_extension_info_map(
740      profile_params_->extension_info_map.get());
741  network_delegate->set_url_blacklist_manager(url_blacklist_manager_.get());
742  network_delegate->set_profile(profile_params_->profile);
743  network_delegate->set_cookie_settings(profile_params_->cookie_settings.get());
744  network_delegate->set_enable_do_not_track(&enable_do_not_track_);
745  network_delegate->set_force_google_safe_search(&force_safesearch_);
746  network_delegate->set_load_time_stats(load_time_stats_);
747  network_delegate_.reset(network_delegate);
748
749  fraudulent_certificate_reporter_.reset(
750      new chrome_browser_net::ChromeFraudulentCertificateReporter(
751          main_request_context_.get()));
752
753  // NOTE: Proxy service uses the default io thread network delegate, not the
754  // delegate just created.
755  proxy_service_.reset(
756      ProxyServiceFactory::CreateProxyService(
757          io_thread->net_log(),
758          io_thread_globals->proxy_script_fetcher_context.get(),
759          io_thread_globals->system_network_delegate.get(),
760          profile_params_->proxy_config_service.release(),
761          command_line));
762
763  transport_security_state_.reset(new net::TransportSecurityState());
764  transport_security_persister_.reset(
765      new TransportSecurityPersister(transport_security_state_.get(),
766                                     profile_params_->path,
767                                     is_incognito()));
768
769  // Take ownership over these parameters.
770  cookie_settings_ = profile_params_->cookie_settings;
771  host_content_settings_map_ = profile_params_->host_content_settings_map;
772#if defined(ENABLE_NOTIFICATIONS)
773  notification_service_ = profile_params_->notification_service;
774#endif
775  extension_info_map_ = profile_params_->extension_info_map;
776
777  resource_context_->host_resolver_ = io_thread_globals->host_resolver.get();
778  resource_context_->request_context_ = main_request_context_.get();
779
780  if (profile_params_->resource_prefetch_predictor_observer_) {
781    resource_prefetch_predictor_observer_.reset(
782        profile_params_->resource_prefetch_predictor_observer_.release());
783  }
784
785#if defined(ENABLE_MANAGED_USERS)
786  managed_mode_url_filter_ = profile_params_->managed_mode_url_filter;
787#endif
788
789#if defined(OS_CHROMEOS)
790  cert_verifier_.reset(new policy::PolicyCertVerifier(
791      profile_params_->profile, profile_params_->trust_anchor_provider));
792  main_request_context_->set_cert_verifier(cert_verifier_.get());
793#else
794  main_request_context_->set_cert_verifier(
795      io_thread_globals->cert_verifier.get());
796#endif
797
798  InitializeInternal(profile_params_.get(), protocol_handlers);
799
800  profile_params_.reset();
801  initialized_ = true;
802}
803
804void ProfileIOData::ApplyProfileParamsToContext(
805    ChromeURLRequestContext* context) const {
806  context->set_http_user_agent_settings(
807      chrome_http_user_agent_settings_.get());
808  context->set_ssl_config_service(profile_params_->ssl_config_service.get());
809}
810
811scoped_ptr<net::URLRequestJobFactory> ProfileIOData::SetUpJobFactoryDefaults(
812    scoped_ptr<net::URLRequestJobFactoryImpl> job_factory,
813    scoped_ptr<ProtocolHandlerRegistry::JobInterceptorFactory>
814        protocol_handler_interceptor,
815    net::NetworkDelegate* network_delegate,
816    net::FtpTransactionFactory* ftp_transaction_factory) const {
817  // NOTE(willchan): Keep these protocol handlers in sync with
818  // ProfileIOData::IsHandledProtocol().
819  bool set_protocol = job_factory->SetProtocolHandler(
820      chrome::kFileScheme, new net::FileProtocolHandler());
821  DCHECK(set_protocol);
822
823  DCHECK(extension_info_map_.get());
824  set_protocol = job_factory->SetProtocolHandler(
825      extensions::kExtensionScheme,
826      CreateExtensionProtocolHandler(is_incognito(),
827                                     extension_info_map_.get()));
828  DCHECK(set_protocol);
829  set_protocol = job_factory->SetProtocolHandler(
830      chrome::kExtensionResourceScheme,
831      CreateExtensionResourceProtocolHandler());
832  DCHECK(set_protocol);
833  set_protocol = job_factory->SetProtocolHandler(
834      chrome::kDataScheme, new net::DataProtocolHandler());
835  DCHECK(set_protocol);
836#if defined(OS_CHROMEOS)
837  if (!is_incognito() && profile_params_) {
838    set_protocol = job_factory->SetProtocolHandler(
839        chrome::kDriveScheme,
840        new drive::DriveProtocolHandler(profile_params_->profile));
841    DCHECK(set_protocol);
842  }
843#endif  // defined(OS_CHROMEOS)
844
845  job_factory->SetProtocolHandler(
846      chrome::kAboutScheme,
847      new chrome_browser_net::AboutProtocolHandler());
848#if !defined(DISABLE_FTP_SUPPORT)
849  DCHECK(ftp_transaction_factory);
850  job_factory->SetProtocolHandler(
851      chrome::kFtpScheme,
852      new net::FtpProtocolHandler(ftp_transaction_factory));
853#endif  // !defined(DISABLE_FTP_SUPPORT)
854
855  scoped_ptr<net::URLRequestJobFactory> top_job_factory =
856      job_factory.PassAs<net::URLRequestJobFactory>();
857#if defined(DEBUG_DEVTOOLS)
858  top_job_factory.reset(new net::ProtocolInterceptJobFactory(
859      top_job_factory.Pass(),
860      scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>(
861          new DebugDevToolsInterceptor)));
862#endif
863
864  if (protocol_handler_interceptor) {
865    protocol_handler_interceptor->Chain(top_job_factory.Pass());
866    return protocol_handler_interceptor.PassAs<net::URLRequestJobFactory>();
867  } else {
868    return top_job_factory.Pass();
869  }
870}
871
872void ProfileIOData::ShutdownOnUIThread() {
873  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
874
875  if (signin_names_)
876    signin_names_->ReleaseResourcesOnUIThread();
877
878  google_services_username_.Destroy();
879  google_services_username_pattern_.Destroy();
880  reverse_autologin_enabled_.Destroy();
881  one_click_signin_rejected_email_list_.Destroy();
882  enable_referrers_.Destroy();
883  enable_do_not_track_.Destroy();
884  force_safesearch_.Destroy();
885#if !defined(OS_CHROMEOS)
886  enable_metrics_.Destroy();
887#endif
888  safe_browsing_enabled_.Destroy();
889  printing_enabled_.Destroy();
890  sync_disabled_.Destroy();
891  signin_allowed_.Destroy();
892  session_startup_pref_.Destroy();
893#if defined(ENABLE_CONFIGURATION_POLICY)
894  if (url_blacklist_manager_)
895    url_blacklist_manager_->ShutdownOnUIThread();
896#endif
897  if (chrome_http_user_agent_settings_)
898    chrome_http_user_agent_settings_->CleanupOnUIThread();
899  bool posted = BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE, this);
900  if (!posted)
901    delete this;
902}
903
904void ProfileIOData::set_server_bound_cert_service(
905    net::ServerBoundCertService* server_bound_cert_service) const {
906  server_bound_cert_service_.reset(server_bound_cert_service);
907}
908
909void ProfileIOData::DestroyResourceContext() {
910  resource_context_.reset();
911}
912
913void ProfileIOData::PopulateNetworkSessionParams(
914    const ProfileParams* profile_params,
915    net::HttpNetworkSession::Params* params) const {
916
917  ChromeURLRequestContext* context = main_request_context();
918
919  IOThread* const io_thread = profile_params->io_thread;
920
921  io_thread->InitializeNetworkSessionParams(params);
922
923  params->host_resolver = context->host_resolver();
924  params->cert_verifier = context->cert_verifier();
925  params->server_bound_cert_service = context->server_bound_cert_service();
926  params->transport_security_state = context->transport_security_state();
927  params->proxy_service = context->proxy_service();
928  params->ssl_session_cache_shard = GetSSLSessionCacheShard();
929  params->ssl_config_service = context->ssl_config_service();
930  params->http_auth_handler_factory = context->http_auth_handler_factory();
931  params->network_delegate = network_delegate();
932  params->http_server_properties = context->http_server_properties();
933  params->net_log = context->net_log();
934}
935
936void ProfileIOData::SetCookieSettingsForTesting(
937    CookieSettings* cookie_settings) {
938  DCHECK(!cookie_settings_.get());
939  cookie_settings_ = cookie_settings;
940}
941
942void ProfileIOData::set_signin_names_for_testing(
943    SigninNamesOnIOThread* signin_names) {
944  signin_names_.reset(signin_names);
945}
946