1 // Copyright (c) 2011 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/command_line.h" 11 #include "base/compiler_specific.h" 12 #include "base/logging.h" 13 #include "base/stl_util-inl.h" 14 #include "base/string_number_conversions.h" 15 #include "chrome/browser/browser_process.h" 16 #include "chrome/browser/custom_handlers/protocol_handler_registry.h" 17 #include "chrome/browser/extensions/user_script_master.h" 18 #include "chrome/browser/io_thread.h" 19 #include "chrome/browser/net/chrome_cookie_notification_details.h" 20 #include "chrome/browser/net/chrome_cookie_policy.h" 21 #include "chrome/browser/net/chrome_dns_cert_provenance_checker_factory.h" 22 #include "chrome/browser/net/chrome_net_log.h" 23 #include "chrome/browser/net/chrome_network_delegate.h" 24 #include "chrome/browser/net/pref_proxy_config_service.h" 25 #include "chrome/browser/net/proxy_service_factory.h" 26 #include "chrome/browser/prefs/pref_service.h" 27 #include "chrome/browser/profiles/profile.h" 28 #include "chrome/common/chrome_switches.h" 29 #include "chrome/common/pref_names.h" 30 #include "content/browser/browser_thread.h" 31 #include "content/browser/resource_context.h" 32 #include "content/common/notification_service.h" 33 #include "net/http/http_util.h" 34 #include "net/proxy/proxy_config_service_fixed.h" 35 #include "net/proxy/proxy_script_fetcher_impl.h" 36 #include "net/proxy/proxy_service.h" 37 #include "webkit/database/database_tracker.h" 38 39 namespace { 40 41 // ---------------------------------------------------------------------------- 42 // CookieMonster::Delegate implementation 43 // ---------------------------------------------------------------------------- 44 class ChromeCookieMonsterDelegate : public net::CookieMonster::Delegate { 45 public: 46 explicit ChromeCookieMonsterDelegate(Profile* profile) { 47 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 48 profile_getter_ = new ProfileGetter(profile); 49 } 50 51 // net::CookieMonster::Delegate implementation. 52 virtual void OnCookieChanged( 53 const net::CookieMonster::CanonicalCookie& cookie, 54 bool removed, 55 net::CookieMonster::Delegate::ChangeCause cause) { 56 BrowserThread::PostTask( 57 BrowserThread::UI, FROM_HERE, 58 NewRunnableMethod(this, 59 &ChromeCookieMonsterDelegate::OnCookieChangedAsyncHelper, 60 cookie, 61 removed, 62 cause)); 63 } 64 65 private: 66 // This class allows us to safely access the Profile pointer. The Delegate 67 // itself cannot observe the PROFILE_DESTROYED notification, since it cannot 68 // guarantee to be deleted on the UI thread and therefore unregister from 69 // the notifications. All methods of ProfileGetter must be invoked on the UI 70 // thread. 71 class ProfileGetter 72 : public base::RefCountedThreadSafe<ProfileGetter, 73 BrowserThread::DeleteOnUIThread>, 74 public NotificationObserver { 75 public: 76 explicit ProfileGetter(Profile* profile) : profile_(profile) { 77 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 78 registrar_.Add(this, 79 NotificationType::PROFILE_DESTROYED, 80 Source<Profile>(profile_)); 81 } 82 83 // NotificationObserver implementation. 84 void Observe(NotificationType type, 85 const NotificationSource& source, 86 const NotificationDetails& details) { 87 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 88 if (NotificationType::PROFILE_DESTROYED == type) { 89 Profile* profile = Source<Profile>(source).ptr(); 90 if (profile_ == profile) 91 profile_ = NULL; 92 } 93 } 94 95 Profile* get() { 96 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 97 return profile_; 98 } 99 100 private: 101 friend struct BrowserThread::DeleteOnThread<BrowserThread::UI>; 102 friend class DeleteTask<ProfileGetter>; 103 104 virtual ~ProfileGetter() {} 105 106 NotificationRegistrar registrar_; 107 108 Profile* profile_; 109 }; 110 111 virtual ~ChromeCookieMonsterDelegate() {} 112 113 void OnCookieChangedAsyncHelper( 114 const net::CookieMonster::CanonicalCookie& cookie, 115 bool removed, 116 net::CookieMonster::Delegate::ChangeCause cause) { 117 if (profile_getter_->get()) { 118 ChromeCookieDetails cookie_details(&cookie, removed, cause); 119 NotificationService::current()->Notify( 120 NotificationType::COOKIE_CHANGED, 121 Source<Profile>(profile_getter_->get()), 122 Details<ChromeCookieDetails>(&cookie_details)); 123 } 124 } 125 126 scoped_refptr<ProfileGetter> profile_getter_; 127 }; 128 129 } // namespace 130 131 void ProfileIOData::InitializeProfileParams(Profile* profile) { 132 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 133 PrefService* pref_service = profile->GetPrefs(); 134 135 scoped_ptr<ProfileParams> params(new ProfileParams); 136 params->is_incognito = profile->IsOffTheRecord(); 137 params->clear_local_state_on_exit = 138 pref_service->GetBoolean(prefs::kClearSiteDataOnExit); 139 140 params->appcache_service = profile->GetAppCacheService(); 141 142 // Set up Accept-Language and Accept-Charset header values 143 params->accept_language = net::HttpUtil::GenerateAcceptLanguageHeader( 144 pref_service->GetString(prefs::kAcceptLanguages)); 145 std::string default_charset = pref_service->GetString(prefs::kDefaultCharset); 146 params->accept_charset = 147 net::HttpUtil::GenerateAcceptCharsetHeader(default_charset); 148 149 // At this point, we don't know the charset of the referring page 150 // where a url request originates from. This is used to get a suggested 151 // filename from Content-Disposition header made of raw 8bit characters. 152 // Down the road, it can be overriden if it becomes known (for instance, 153 // when download request is made through the context menu in a web page). 154 // At the moment, it'll remain 'undeterministic' when a user 155 // types a URL in the omnibar or click on a download link in a page. 156 // For the latter, we need a change on the webkit-side. 157 // We initialize it to the default charset here and a user will 158 // have an *arguably* better default charset for interpreting a raw 8bit 159 // C-D header field. It means the native OS codepage fallback in 160 // net_util::GetSuggestedFilename is unlikely to be taken. 161 params->referrer_charset = default_charset; 162 163 params->io_thread = g_browser_process->io_thread(); 164 165 params->host_content_settings_map = profile->GetHostContentSettingsMap(); 166 params->host_zoom_map = profile->GetHostZoomMap(); 167 params->transport_security_state = profile->GetTransportSecurityState(); 168 169 if (profile->GetUserScriptMaster()) { 170 params->user_script_dir_path = 171 profile->GetUserScriptMaster()->user_script_dir(); 172 } 173 174 params->ssl_config_service = profile->GetSSLConfigService(); 175 params->cookie_monster_delegate = new ChromeCookieMonsterDelegate(profile); 176 params->database_tracker = profile->GetDatabaseTracker(); 177 params->appcache_service = profile->GetAppCacheService(); 178 params->blob_storage_context = profile->GetBlobStorageContext(); 179 params->file_system_context = profile->GetFileSystemContext(); 180 params->extension_info_map = profile->GetExtensionInfoMap(); 181 params->prerender_manager = profile->GetPrerenderManager(); 182 params->protocol_handler_registry = profile->GetProtocolHandlerRegistry(); 183 184 params->proxy_config_service.reset( 185 ProxyServiceFactory::CreateProxyConfigService( 186 profile->GetProxyConfigTracker())); 187 params->profile_id = profile->GetRuntimeId(); 188 profile_params_.reset(params.release()); 189 } 190 191 ProfileIOData::RequestContext::RequestContext() {} 192 ProfileIOData::RequestContext::~RequestContext() {} 193 194 ProfileIOData::ProfileParams::ProfileParams() 195 : is_incognito(false), 196 clear_local_state_on_exit(false), 197 profile_id(Profile::kInvalidProfileId) {} 198 ProfileIOData::ProfileParams::~ProfileParams() {} 199 200 ProfileIOData::ProfileIOData(bool is_incognito) 201 : initialized_(false), 202 ALLOW_THIS_IN_INITIALIZER_LIST(resource_context_(this)) { 203 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 204 } 205 206 ProfileIOData::~ProfileIOData() { 207 // If we have never initialized ProfileIOData, then Handle may hold the only 208 // reference to it. The important thing is to make sure it hasn't been 209 // initialized yet, because the lazily initialized variables are supposed to 210 // live on the IO thread. 211 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) 212 DCHECK(!initialized_); 213 else 214 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 215 } 216 217 scoped_refptr<ChromeURLRequestContext> 218 ProfileIOData::GetMainRequestContext() const { 219 LazyInitialize(); 220 scoped_refptr<RequestContext> context = main_request_context_; 221 context->set_profile_io_data(this); 222 main_request_context_ = NULL; 223 return context; 224 } 225 226 scoped_refptr<ChromeURLRequestContext> 227 ProfileIOData::GetMediaRequestContext() const { 228 LazyInitialize(); 229 scoped_refptr<ChromeURLRequestContext> context = 230 AcquireMediaRequestContext(); 231 DCHECK(context); 232 return context; 233 } 234 235 scoped_refptr<ChromeURLRequestContext> 236 ProfileIOData::GetExtensionsRequestContext() const { 237 LazyInitialize(); 238 scoped_refptr<RequestContext> context = 239 extensions_request_context_; 240 context->set_profile_io_data(this); 241 extensions_request_context_ = NULL; 242 return context; 243 } 244 245 scoped_refptr<ChromeURLRequestContext> 246 ProfileIOData::GetIsolatedAppRequestContext( 247 scoped_refptr<ChromeURLRequestContext> main_context, 248 const std::string& app_id) const { 249 LazyInitialize(); 250 scoped_refptr<ChromeURLRequestContext> context = 251 AcquireIsolatedAppRequestContext(main_context, app_id); 252 DCHECK(context); 253 return context; 254 } 255 256 const content::ResourceContext& ProfileIOData::GetResourceContext() const { 257 return resource_context_; 258 } 259 260 ProfileIOData::ResourceContext::ResourceContext(const ProfileIOData* io_data) 261 : io_data_(io_data) { 262 DCHECK(io_data); 263 } 264 265 ProfileIOData::ResourceContext::~ResourceContext() {} 266 267 void ProfileIOData::ResourceContext::EnsureInitialized() const { 268 io_data_->LazyInitialize(); 269 } 270 271 void ProfileIOData::LazyInitialize() const { 272 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 273 if (initialized_) 274 return; 275 DCHECK(profile_params_.get()); 276 277 IOThread* const io_thread = profile_params_->io_thread; 278 IOThread::Globals* const io_thread_globals = io_thread->globals(); 279 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); 280 281 // Create the common request contexts. 282 main_request_context_ = new RequestContext; 283 extensions_request_context_ = new RequestContext; 284 285 profile_params_->appcache_service->set_request_context(main_request_context_); 286 287 // Create objects pointed to by URLRequestContext. 288 cookie_policy_.reset( 289 new ChromeCookiePolicy(profile_params_->host_content_settings_map)); 290 291 network_delegate_.reset(new ChromeNetworkDelegate( 292 io_thread_globals->extension_event_router_forwarder.get(), 293 profile_params_->profile_id, 294 &enable_referrers_, 295 profile_params_->protocol_handler_registry)); 296 297 dns_cert_checker_.reset( 298 CreateDnsCertProvenanceChecker(io_thread_globals->dnsrr_resolver.get(), 299 main_request_context_)); 300 301 proxy_service_ = 302 ProxyServiceFactory::CreateProxyService( 303 io_thread->net_log(), 304 io_thread_globals->proxy_script_fetcher_context.get(), 305 profile_params_->proxy_config_service.release(), 306 command_line); 307 308 // Take ownership over these parameters. 309 database_tracker_ = profile_params_->database_tracker; 310 appcache_service_ = profile_params_->appcache_service; 311 blob_storage_context_ = profile_params_->blob_storage_context; 312 file_system_context_ = profile_params_->file_system_context; 313 314 resource_context_.set_host_resolver(io_thread_globals->host_resolver.get()); 315 resource_context_.set_request_context(main_request_context_); 316 resource_context_.set_database_tracker(database_tracker_); 317 resource_context_.set_appcache_service(appcache_service_); 318 resource_context_.set_blob_storage_context(blob_storage_context_); 319 resource_context_.set_file_system_context(file_system_context_); 320 321 LazyInitializeInternal(profile_params_.get()); 322 323 profile_params_.reset(); 324 initialized_ = true; 325 } 326 327 void ProfileIOData::ApplyProfileParamsToContext( 328 ChromeURLRequestContext* context) const { 329 context->set_is_incognito(profile_params_->is_incognito); 330 context->set_accept_language(profile_params_->accept_language); 331 context->set_accept_charset(profile_params_->accept_charset); 332 context->set_referrer_charset(profile_params_->referrer_charset); 333 context->set_user_script_dir_path(profile_params_->user_script_dir_path); 334 context->set_host_content_settings_map( 335 profile_params_->host_content_settings_map); 336 context->set_host_zoom_map(profile_params_->host_zoom_map); 337 context->set_transport_security_state( 338 profile_params_->transport_security_state); 339 context->set_ssl_config_service(profile_params_->ssl_config_service); 340 context->set_appcache_service(profile_params_->appcache_service); 341 context->set_blob_storage_context(profile_params_->blob_storage_context); 342 context->set_file_system_context(profile_params_->file_system_context); 343 context->set_extension_info_map(profile_params_->extension_info_map); 344 context->set_prerender_manager(profile_params_->prerender_manager); 345 } 346 347 void ProfileIOData::ShutdownOnUIThread() { 348 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 349 enable_referrers_.Destroy(); 350 } 351