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