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