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_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