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_impl_io_data.h" 6 7 #include "base/command_line.h" 8 #include "base/file_util.h" 9 #include "base/logging.h" 10 #include "base/stl_util-inl.h" 11 #include "chrome/browser/io_thread.h" 12 #include "chrome/browser/net/chrome_net_log.h" 13 #include "chrome/browser/net/chrome_network_delegate.h" 14 #include "chrome/browser/net/sqlite_persistent_cookie_store.h" 15 #include "chrome/common/chrome_constants.h" 16 #include "chrome/common/chrome_switches.h" 17 #include "chrome/common/pref_names.h" 18 #include "chrome/common/url_constants.h" 19 #include "content/browser/browser_thread.h" 20 #include "content/browser/resource_context.h" 21 #include "net/ftp/ftp_network_layer.h" 22 #include "net/http/http_cache.h" 23 24 ProfileImplIOData::Handle::Handle(Profile* profile) 25 : io_data_(new ProfileImplIOData), 26 profile_(profile), 27 initialized_(false) { 28 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 29 DCHECK(profile); 30 } 31 32 ProfileImplIOData::Handle::~Handle() { 33 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 34 if (main_request_context_getter_) 35 main_request_context_getter_->CleanupOnUIThread(); 36 if (media_request_context_getter_) 37 media_request_context_getter_->CleanupOnUIThread(); 38 if (extensions_request_context_getter_) 39 extensions_request_context_getter_->CleanupOnUIThread(); 40 41 // Clean up all isolated app request contexts. 42 for (ChromeURLRequestContextGetterMap::iterator iter = 43 app_request_context_getter_map_.begin(); 44 iter != app_request_context_getter_map_.end(); 45 ++iter) { 46 iter->second->CleanupOnUIThread(); 47 } 48 49 io_data_->ShutdownOnUIThread(); 50 } 51 52 void ProfileImplIOData::Handle::Init(const FilePath& cookie_path, 53 const FilePath& cache_path, 54 int cache_max_size, 55 const FilePath& media_cache_path, 56 int media_cache_max_size, 57 const FilePath& extensions_cookie_path, 58 const FilePath& app_path) { 59 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 60 DCHECK(!io_data_->lazy_params_.get()); 61 LazyParams* lazy_params = new LazyParams; 62 63 lazy_params->cookie_path = cookie_path; 64 lazy_params->cache_path = cache_path; 65 lazy_params->cache_max_size = cache_max_size; 66 lazy_params->media_cache_path = media_cache_path; 67 lazy_params->media_cache_max_size = media_cache_max_size; 68 lazy_params->extensions_cookie_path = extensions_cookie_path; 69 70 io_data_->lazy_params_.reset(lazy_params); 71 72 // Keep track of isolated app path separately so we can use it on demand. 73 io_data_->app_path_ = app_path; 74 } 75 76 const content::ResourceContext& 77 ProfileImplIOData::Handle::GetResourceContext() const { 78 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 79 LazyInitialize(); 80 return io_data_->GetResourceContext(); 81 } 82 83 scoped_refptr<ChromeURLRequestContextGetter> 84 ProfileImplIOData::Handle::GetMainRequestContextGetter() const { 85 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 86 LazyInitialize(); 87 if (!main_request_context_getter_) { 88 main_request_context_getter_ = 89 ChromeURLRequestContextGetter::CreateOriginal( 90 profile_, io_data_); 91 } 92 return main_request_context_getter_; 93 } 94 95 scoped_refptr<ChromeURLRequestContextGetter> 96 ProfileImplIOData::Handle::GetMediaRequestContextGetter() const { 97 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 98 LazyInitialize(); 99 if (!media_request_context_getter_) { 100 media_request_context_getter_ = 101 ChromeURLRequestContextGetter::CreateOriginalForMedia( 102 profile_, io_data_); 103 } 104 return media_request_context_getter_; 105 } 106 107 scoped_refptr<ChromeURLRequestContextGetter> 108 ProfileImplIOData::Handle::GetExtensionsRequestContextGetter() const { 109 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 110 LazyInitialize(); 111 if (!extensions_request_context_getter_) { 112 extensions_request_context_getter_ = 113 ChromeURLRequestContextGetter::CreateOriginalForExtensions( 114 profile_, io_data_); 115 } 116 return extensions_request_context_getter_; 117 } 118 119 scoped_refptr<ChromeURLRequestContextGetter> 120 ProfileImplIOData::Handle::GetIsolatedAppRequestContextGetter( 121 const std::string& app_id) const { 122 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 123 DCHECK(!app_id.empty()); 124 LazyInitialize(); 125 126 // Keep a map of request context getters, one per requested app ID. 127 ChromeURLRequestContextGetterMap::iterator iter = 128 app_request_context_getter_map_.find(app_id); 129 if (iter != app_request_context_getter_map_.end()) 130 return iter->second; 131 132 ChromeURLRequestContextGetter* context = 133 ChromeURLRequestContextGetter::CreateOriginalForIsolatedApp( 134 profile_, io_data_, app_id); 135 app_request_context_getter_map_[app_id] = context; 136 137 return context; 138 } 139 140 void ProfileImplIOData::Handle::LazyInitialize() const { 141 if (!initialized_) { 142 io_data_->InitializeProfileParams(profile_); 143 ChromeNetworkDelegate::InitializeReferrersEnabled( 144 io_data_->enable_referrers(), profile_->GetPrefs()); 145 initialized_ = true; 146 } 147 } 148 149 ProfileImplIOData::LazyParams::LazyParams() 150 : cache_max_size(0), 151 media_cache_max_size(0) {} 152 ProfileImplIOData::LazyParams::~LazyParams() {} 153 154 ProfileImplIOData::ProfileImplIOData() 155 : ProfileIOData(false), 156 clear_local_state_on_exit_(false) {} 157 ProfileImplIOData::~ProfileImplIOData() { 158 STLDeleteValues(&app_http_factory_map_); 159 } 160 161 void ProfileImplIOData::LazyInitializeInternal( 162 ProfileParams* profile_params) const { 163 // Keep track of clear_local_state_on_exit for isolated apps. 164 clear_local_state_on_exit_ = profile_params->clear_local_state_on_exit; 165 166 ChromeURLRequestContext* main_context = main_request_context(); 167 ChromeURLRequestContext* extensions_context = extensions_request_context(); 168 media_request_context_ = new RequestContext; 169 170 IOThread* const io_thread = profile_params->io_thread; 171 IOThread::Globals* const io_thread_globals = io_thread->globals(); 172 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); 173 bool record_mode = chrome::kRecordModeEnabled && 174 command_line.HasSwitch(switches::kRecordMode); 175 bool playback_mode = command_line.HasSwitch(switches::kPlaybackMode); 176 177 // Initialize context members. 178 179 ApplyProfileParamsToContext(main_context); 180 ApplyProfileParamsToContext(media_request_context_); 181 ApplyProfileParamsToContext(extensions_context); 182 183 main_context->set_cookie_policy(cookie_policy()); 184 media_request_context_->set_cookie_policy(cookie_policy()); 185 extensions_context->set_cookie_policy(cookie_policy()); 186 187 main_context->set_net_log(io_thread->net_log()); 188 media_request_context_->set_net_log(io_thread->net_log()); 189 extensions_context->set_net_log(io_thread->net_log()); 190 191 main_context->set_network_delegate(network_delegate()); 192 media_request_context_->set_network_delegate(network_delegate()); 193 194 main_context->set_host_resolver( 195 io_thread_globals->host_resolver.get()); 196 media_request_context_->set_host_resolver( 197 io_thread_globals->host_resolver.get()); 198 main_context->set_cert_verifier( 199 io_thread_globals->cert_verifier.get()); 200 media_request_context_->set_cert_verifier( 201 io_thread_globals->cert_verifier.get()); 202 main_context->set_dnsrr_resolver( 203 io_thread_globals->dnsrr_resolver.get()); 204 media_request_context_->set_dnsrr_resolver( 205 io_thread_globals->dnsrr_resolver.get()); 206 main_context->set_http_auth_handler_factory( 207 io_thread_globals->http_auth_handler_factory.get()); 208 media_request_context_->set_http_auth_handler_factory( 209 io_thread_globals->http_auth_handler_factory.get()); 210 211 main_context->set_dns_cert_checker(dns_cert_checker()); 212 media_request_context_->set_dns_cert_checker(dns_cert_checker()); 213 214 main_context->set_proxy_service(proxy_service()); 215 media_request_context_->set_proxy_service(proxy_service()); 216 217 net::HttpCache::DefaultBackend* main_backend = 218 new net::HttpCache::DefaultBackend( 219 net::DISK_CACHE, 220 lazy_params_->cache_path, 221 lazy_params_->cache_max_size, 222 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE)); 223 net::HttpCache* main_cache = new net::HttpCache( 224 main_context->host_resolver(), 225 main_context->cert_verifier(), 226 main_context->dnsrr_resolver(), 227 main_context->dns_cert_checker(), 228 main_context->proxy_service(), 229 main_context->ssl_config_service(), 230 main_context->http_auth_handler_factory(), 231 main_context->network_delegate(), 232 main_context->net_log(), 233 main_backend); 234 235 net::HttpCache::DefaultBackend* media_backend = 236 new net::HttpCache::DefaultBackend( 237 net::MEDIA_CACHE, lazy_params_->media_cache_path, 238 lazy_params_->media_cache_max_size, 239 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE)); 240 net::HttpNetworkSession* main_network_session = main_cache->GetSession(); 241 net::HttpCache* media_cache = 242 new net::HttpCache(main_network_session, media_backend); 243 244 scoped_refptr<net::CookieStore> cookie_store = NULL; 245 if (record_mode || playback_mode) { 246 // Don't use existing cookies and use an in-memory store. 247 cookie_store = new net::CookieMonster( 248 NULL, profile_params->cookie_monster_delegate); 249 main_cache->set_mode( 250 record_mode ? net::HttpCache::RECORD : net::HttpCache::PLAYBACK); 251 } 252 253 // setup cookie store 254 if (!cookie_store) { 255 DCHECK(!lazy_params_->cookie_path.empty()); 256 257 scoped_refptr<SQLitePersistentCookieStore> cookie_db = 258 new SQLitePersistentCookieStore(lazy_params_->cookie_path); 259 cookie_db->SetClearLocalStateOnExit( 260 profile_params->clear_local_state_on_exit); 261 cookie_store = 262 new net::CookieMonster(cookie_db.get(), 263 profile_params->cookie_monster_delegate); 264 } 265 266 net::CookieMonster* extensions_cookie_store = 267 new net::CookieMonster( 268 new SQLitePersistentCookieStore( 269 lazy_params_->extensions_cookie_path), NULL); 270 // Enable cookies for devtools and extension URLs. 271 const char* schemes[] = {chrome::kChromeDevToolsScheme, 272 chrome::kExtensionScheme}; 273 extensions_cookie_store->SetCookieableSchemes(schemes, 2); 274 275 main_context->set_cookie_store(cookie_store); 276 media_request_context_->set_cookie_store(cookie_store); 277 extensions_context->set_cookie_store( 278 extensions_cookie_store); 279 280 main_http_factory_.reset(main_cache); 281 media_http_factory_.reset(media_cache); 282 main_context->set_http_transaction_factory(main_cache); 283 media_request_context_->set_http_transaction_factory(media_cache); 284 285 main_context->set_ftp_transaction_factory( 286 new net::FtpNetworkLayer(io_thread_globals->host_resolver.get())); 287 288 lazy_params_.reset(); 289 } 290 291 scoped_refptr<ProfileIOData::RequestContext> 292 ProfileImplIOData::InitializeAppRequestContext( 293 scoped_refptr<ChromeURLRequestContext> main_context, 294 const std::string& app_id) const { 295 scoped_refptr<ProfileIOData::RequestContext> context = new RequestContext; 296 297 // Copy most state from the main context. 298 context->CopyFrom(main_context); 299 300 FilePath app_path = app_path_.AppendASCII(app_id); 301 FilePath cookie_path = app_path.Append(chrome::kCookieFilename); 302 FilePath cache_path = app_path.Append(chrome::kCacheDirname); 303 // TODO(creis): Determine correct cache size. 304 int cache_max_size = 0; 305 306 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); 307 bool record_mode = chrome::kRecordModeEnabled && 308 command_line.HasSwitch(switches::kRecordMode); 309 bool playback_mode = command_line.HasSwitch(switches::kPlaybackMode); 310 311 // Use a separate HTTP disk cache for isolated apps. 312 net::HttpCache::DefaultBackend* app_backend = 313 new net::HttpCache::DefaultBackend( 314 net::DISK_CACHE, 315 cache_path, 316 cache_max_size, 317 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE)); 318 net::HttpNetworkSession* main_network_session = 319 main_http_factory_->GetSession(); 320 net::HttpCache* app_http_cache = 321 new net::HttpCache(main_network_session, app_backend); 322 323 scoped_refptr<net::CookieStore> cookie_store = NULL; 324 if (record_mode || playback_mode) { 325 // Don't use existing cookies and use an in-memory store. 326 // TODO(creis): We should have a cookie delegate for notifying the cookie 327 // extensions API, but we need to update it to understand isolated apps 328 // first. 329 cookie_store = new net::CookieMonster(NULL, NULL); 330 app_http_cache->set_mode( 331 record_mode ? net::HttpCache::RECORD : net::HttpCache::PLAYBACK); 332 } 333 334 // Use an app-specific cookie store. 335 if (!cookie_store) { 336 DCHECK(!cookie_path.empty()); 337 338 scoped_refptr<SQLitePersistentCookieStore> cookie_db = 339 new SQLitePersistentCookieStore(cookie_path); 340 cookie_db->SetClearLocalStateOnExit(clear_local_state_on_exit_); 341 // TODO(creis): We should have a cookie delegate for notifying the cookie 342 // extensions API, but we need to update it to understand isolated apps 343 // first. 344 cookie_store = new net::CookieMonster(cookie_db.get(), NULL); 345 } 346 347 context->set_cookie_store(cookie_store); 348 349 // Keep track of app_http_cache to delete it when we go away. 350 DCHECK(!app_http_factory_map_[app_id]); 351 app_http_factory_map_[app_id] = app_http_cache; 352 context->set_http_transaction_factory(app_http_cache); 353 354 return context; 355 } 356 357 scoped_refptr<ChromeURLRequestContext> 358 ProfileImplIOData::AcquireMediaRequestContext() const { 359 DCHECK(media_request_context_); 360 scoped_refptr<ChromeURLRequestContext> context = media_request_context_; 361 media_request_context_->set_profile_io_data(this); 362 media_request_context_ = NULL; 363 return context; 364 } 365 366 scoped_refptr<ChromeURLRequestContext> 367 ProfileImplIOData::AcquireIsolatedAppRequestContext( 368 scoped_refptr<ChromeURLRequestContext> main_context, 369 const std::string& app_id) const { 370 // We create per-app contexts on demand, unlike the others above. 371 scoped_refptr<RequestContext> app_request_context = 372 InitializeAppRequestContext(main_context, app_id); 373 DCHECK(app_request_context); 374 app_request_context->set_profile_io_data(this); 375 return app_request_context; 376 } 377