Home | History | Annotate | Download | only in profiles
      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