• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
ChromeCookieMonsterDelegate(Profile * profile)46   explicit ChromeCookieMonsterDelegate(Profile* profile) {
47     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
48     profile_getter_ = new ProfileGetter(profile);
49   }
50 
51   // net::CookieMonster::Delegate implementation.
OnCookieChanged(const net::CookieMonster::CanonicalCookie & cookie,bool removed,net::CookieMonster::Delegate::ChangeCause cause)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:
ProfileGetter(Profile * profile)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.
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)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 
get()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 
~ProfileGetter()104     virtual ~ProfileGetter() {}
105 
106     NotificationRegistrar registrar_;
107 
108     Profile* profile_;
109   };
110 
~ChromeCookieMonsterDelegate()111   virtual ~ChromeCookieMonsterDelegate() {}
112 
OnCookieChangedAsyncHelper(const net::CookieMonster::CanonicalCookie & cookie,bool removed,net::CookieMonster::Delegate::ChangeCause cause)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 
InitializeProfileParams(Profile * profile)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 
RequestContext()191 ProfileIOData::RequestContext::RequestContext() {}
~RequestContext()192 ProfileIOData::RequestContext::~RequestContext() {}
193 
ProfileParams()194 ProfileIOData::ProfileParams::ProfileParams()
195     : is_incognito(false),
196       clear_local_state_on_exit(false),
197       profile_id(Profile::kInvalidProfileId) {}
~ProfileParams()198 ProfileIOData::ProfileParams::~ProfileParams() {}
199 
ProfileIOData(bool is_incognito)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 
~ProfileIOData()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>
GetMainRequestContext() const218 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>
GetMediaRequestContext() const227 ProfileIOData::GetMediaRequestContext() const {
228   LazyInitialize();
229   scoped_refptr<ChromeURLRequestContext> context =
230       AcquireMediaRequestContext();
231   DCHECK(context);
232   return context;
233 }
234 
235 scoped_refptr<ChromeURLRequestContext>
GetExtensionsRequestContext() const236 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>
GetIsolatedAppRequestContext(scoped_refptr<ChromeURLRequestContext> main_context,const std::string & app_id) const246 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 
GetResourceContext() const256 const content::ResourceContext& ProfileIOData::GetResourceContext() const {
257   return resource_context_;
258 }
259 
ResourceContext(const ProfileIOData * io_data)260 ProfileIOData::ResourceContext::ResourceContext(const ProfileIOData* io_data)
261     : io_data_(io_data) {
262   DCHECK(io_data);
263 }
264 
~ResourceContext()265 ProfileIOData::ResourceContext::~ResourceContext() {}
266 
EnsureInitialized() const267 void ProfileIOData::ResourceContext::EnsureInitialized() const {
268   io_data_->LazyInitialize();
269 }
270 
LazyInitialize() const271 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 
ApplyProfileParamsToContext(ChromeURLRequestContext * context) const327 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 
ShutdownOnUIThread()347 void ProfileIOData::ShutdownOnUIThread() {
348   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
349   enable_referrers_.Destroy();
350 }
351