• 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_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 
Handle(Profile * profile)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 
~Handle()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 
Init(const FilePath & cookie_path,const FilePath & cache_path,int cache_max_size,const FilePath & media_cache_path,int media_cache_max_size,const FilePath & extensions_cookie_path,const FilePath & app_path)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&
GetResourceContext() const77 ProfileImplIOData::Handle::GetResourceContext() const {
78   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
79   LazyInitialize();
80   return io_data_->GetResourceContext();
81 }
82 
83 scoped_refptr<ChromeURLRequestContextGetter>
GetMainRequestContextGetter() const84 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>
GetMediaRequestContextGetter() const96 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>
GetExtensionsRequestContextGetter() const108 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>
GetIsolatedAppRequestContextGetter(const std::string & app_id) const120 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 
LazyInitialize() const140 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 
LazyParams()149 ProfileImplIOData::LazyParams::LazyParams()
150     : cache_max_size(0),
151       media_cache_max_size(0) {}
~LazyParams()152 ProfileImplIOData::LazyParams::~LazyParams() {}
153 
ProfileImplIOData()154 ProfileImplIOData::ProfileImplIOData()
155     : ProfileIOData(false),
156       clear_local_state_on_exit_(false) {}
~ProfileImplIOData()157 ProfileImplIOData::~ProfileImplIOData() {
158   STLDeleteValues(&app_http_factory_map_);
159 }
160 
LazyInitializeInternal(ProfileParams * profile_params) const161 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>
InitializeAppRequestContext(scoped_refptr<ChromeURLRequestContext> main_context,const std::string & app_id) const292 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>
AcquireMediaRequestContext() const358 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>
AcquireIsolatedAppRequestContext(scoped_refptr<ChromeURLRequestContext> main_context,const std::string & app_id) const367 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