1// Copyright (c) 2012 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/off_the_record_profile_io_data.h"
6
7#include "base/bind.h"
8#include "base/command_line.h"
9#include "base/logging.h"
10#include "base/prefs/pref_service.h"
11#include "base/stl_util.h"
12#include "base/threading/worker_pool.h"
13#include "build/build_config.h"
14#include "chrome/browser/browser_process.h"
15#include "chrome/browser/custom_handlers/protocol_handler_registry.h"
16#include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h"
17#include "chrome/browser/io_thread.h"
18#include "chrome/browser/net/about_protocol_handler.h"
19#include "chrome/browser/net/chrome_net_log.h"
20#include "chrome/browser/net/chrome_network_delegate.h"
21#include "chrome/browser/net/chrome_url_request_context.h"
22#include "chrome/browser/profiles/profile.h"
23#include "chrome/common/chrome_switches.h"
24#include "chrome/common/pref_names.h"
25#include "chrome/common/url_constants.h"
26#include "content/public/browser/browser_thread.h"
27#include "content/public/browser/resource_context.h"
28#include "extensions/common/constants.h"
29#include "extensions/common/extension.h"
30#include "net/ftp/ftp_network_layer.h"
31#include "net/http/http_cache.h"
32#include "net/http/http_network_session.h"
33#include "net/http/http_server_properties_impl.h"
34#include "net/ssl/default_server_bound_cert_store.h"
35#include "net/ssl/server_bound_cert_service.h"
36#include "net/url_request/protocol_intercept_job_factory.h"
37#include "net/url_request/url_request_job_factory_impl.h"
38#include "webkit/browser/database/database_tracker.h"
39
40using content::BrowserThread;
41
42OffTheRecordProfileIOData::Handle::Handle(Profile* profile)
43    : io_data_(new OffTheRecordProfileIOData),
44      profile_(profile),
45      initialized_(false) {
46  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
47  DCHECK(profile);
48}
49
50OffTheRecordProfileIOData::Handle::~Handle() {
51  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
52  io_data_->ShutdownOnUIThread();
53}
54
55content::ResourceContext*
56OffTheRecordProfileIOData::Handle::GetResourceContext() const {
57  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
58  LazyInitialize();
59  return GetResourceContextNoInit();
60}
61
62content::ResourceContext*
63OffTheRecordProfileIOData::Handle::GetResourceContextNoInit() const {
64  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
65  // Don't call LazyInitialize here, since the resource context is created at
66  // the beginning of initalization and is used by some members while they're
67  // being initialized (i.e. AppCacheService).
68  return io_data_->GetResourceContext();
69}
70
71scoped_refptr<ChromeURLRequestContextGetter>
72OffTheRecordProfileIOData::Handle::CreateMainRequestContextGetter(
73    content::ProtocolHandlerMap* protocol_handlers) const {
74  // TODO(oshima): Re-enable when ChromeOS only accesses the profile on the UI
75  // thread.
76#if !defined(OS_CHROMEOS)
77  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
78#endif  // defined(OS_CHROMEOS)
79  LazyInitialize();
80  DCHECK(!main_request_context_getter_.get());
81  main_request_context_getter_ =
82      ChromeURLRequestContextGetter::Create(
83          profile_, io_data_, protocol_handlers);
84  return main_request_context_getter_;
85}
86
87scoped_refptr<ChromeURLRequestContextGetter>
88OffTheRecordProfileIOData::Handle::GetExtensionsRequestContextGetter() const {
89  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
90  LazyInitialize();
91  if (!extensions_request_context_getter_.get()) {
92    extensions_request_context_getter_ =
93        ChromeURLRequestContextGetter::CreateForExtensions(profile_, io_data_);
94  }
95  return extensions_request_context_getter_;
96}
97
98scoped_refptr<ChromeURLRequestContextGetter>
99OffTheRecordProfileIOData::Handle::GetIsolatedAppRequestContextGetter(
100    const base::FilePath& partition_path,
101    bool in_memory) const {
102  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
103  DCHECK(!partition_path.empty());
104  LazyInitialize();
105
106  // Keep a map of request context getters, one per requested app ID.
107  StoragePartitionDescriptor descriptor(partition_path, in_memory);
108  ChromeURLRequestContextGetterMap::iterator iter =
109      app_request_context_getter_map_.find(descriptor);
110  CHECK(iter != app_request_context_getter_map_.end());
111  return iter->second;
112}
113
114scoped_refptr<ChromeURLRequestContextGetter>
115OffTheRecordProfileIOData::Handle::CreateIsolatedAppRequestContextGetter(
116    const base::FilePath& partition_path,
117    bool in_memory,
118    content::ProtocolHandlerMap* protocol_handlers) const {
119  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
120  DCHECK(!partition_path.empty());
121  LazyInitialize();
122
123  // Keep a map of request context getters, one per requested app ID.
124  StoragePartitionDescriptor descriptor(partition_path, in_memory);
125  DCHECK_EQ(app_request_context_getter_map_.count(descriptor), 0u);
126
127  scoped_ptr<ProtocolHandlerRegistry::JobInterceptorFactory>
128      protocol_handler_interceptor(
129          ProtocolHandlerRegistryFactory::GetForProfile(profile_)->
130              CreateJobInterceptorFactory());
131  ChromeURLRequestContextGetter* context =
132      ChromeURLRequestContextGetter::CreateForIsolatedApp(
133          profile_, io_data_, descriptor, protocol_handler_interceptor.Pass(),
134          protocol_handlers);
135  app_request_context_getter_map_[descriptor] = context;
136
137  return context;
138}
139
140void OffTheRecordProfileIOData::Handle::LazyInitialize() const {
141  if (initialized_)
142    return;
143
144  // Set initialized_ to true at the beginning in case any of the objects
145  // below try to get the ResourceContext pointer.
146  initialized_ = true;
147#if defined(FULL_SAFE_BROWSING) || defined(MOBILE_SAFE_BROWSING)
148  io_data_->safe_browsing_enabled()->Init(prefs::kSafeBrowsingEnabled,
149      profile_->GetPrefs());
150  io_data_->safe_browsing_enabled()->MoveToThread(
151      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO));
152#endif
153  io_data_->InitializeOnUIThread(profile_);
154}
155
156OffTheRecordProfileIOData::OffTheRecordProfileIOData()
157    : ProfileIOData(true) {}
158OffTheRecordProfileIOData::~OffTheRecordProfileIOData() {
159  DestroyResourceContext();
160}
161
162void OffTheRecordProfileIOData::InitializeInternal(
163    ProfileParams* profile_params,
164    content::ProtocolHandlerMap* protocol_handlers) const {
165  ChromeURLRequestContext* main_context = main_request_context();
166
167  IOThread* const io_thread = profile_params->io_thread;
168  IOThread::Globals* const io_thread_globals = io_thread->globals();
169
170  ApplyProfileParamsToContext(main_context);
171
172  main_context->set_transport_security_state(transport_security_state());
173
174  main_context->set_net_log(io_thread->net_log());
175
176  main_context->set_network_delegate(network_delegate());
177
178  main_context->set_host_resolver(
179      io_thread_globals->host_resolver.get());
180  main_context->set_http_auth_handler_factory(
181      io_thread_globals->http_auth_handler_factory.get());
182  main_context->set_fraudulent_certificate_reporter(
183      fraudulent_certificate_reporter());
184  main_context->set_proxy_service(proxy_service());
185
186  main_context->set_throttler_manager(
187      io_thread_globals->throttler_manager.get());
188
189  // For incognito, we use the default non-persistent HttpServerPropertiesImpl.
190  set_http_server_properties(
191      scoped_ptr<net::HttpServerProperties>(
192          new net::HttpServerPropertiesImpl()));
193  main_context->set_http_server_properties(http_server_properties());
194
195  // For incognito, we use a non-persistent server bound cert store.
196  net::ServerBoundCertService* server_bound_cert_service =
197      new net::ServerBoundCertService(
198          new net::DefaultServerBoundCertStore(NULL),
199          base::WorkerPool::GetTaskRunner(true));
200  set_server_bound_cert_service(server_bound_cert_service);
201  main_context->set_server_bound_cert_service(server_bound_cert_service);
202
203  main_context->set_cookie_store(new net::CookieMonster(
204      NULL, profile_params->cookie_monster_delegate.get()));
205
206  net::HttpCache::BackendFactory* main_backend =
207      net::HttpCache::DefaultBackend::InMemory(0);
208  net::HttpNetworkSession::Params network_session_params;
209  PopulateNetworkSessionParams(profile_params, &network_session_params);
210  net::HttpCache* cache = new net::HttpCache(
211      network_session_params, main_backend);
212
213  main_http_factory_.reset(cache);
214  main_context->set_http_transaction_factory(cache);
215#if !defined(DISABLE_FTP_SUPPORT)
216  ftp_factory_.reset(
217      new net::FtpNetworkLayer(main_context->host_resolver()));
218#endif  // !defined(DISABLE_FTP_SUPPORT)
219
220  scoped_ptr<net::URLRequestJobFactoryImpl> main_job_factory(
221      new net::URLRequestJobFactoryImpl());
222
223  InstallProtocolHandlers(main_job_factory.get(), protocol_handlers);
224  main_job_factory_ = SetUpJobFactoryDefaults(
225      main_job_factory.Pass(),
226      profile_params->protocol_handler_interceptor.Pass(),
227      network_delegate(),
228      ftp_factory_.get());
229  main_context->set_job_factory(main_job_factory_.get());
230
231#if defined(ENABLE_EXTENSIONS)
232  InitializeExtensionsRequestContext(profile_params);
233#endif
234}
235
236void OffTheRecordProfileIOData::
237    InitializeExtensionsRequestContext(ProfileParams* profile_params) const {
238  ChromeURLRequestContext* extensions_context = extensions_request_context();
239
240  IOThread* const io_thread = profile_params->io_thread;
241  IOThread::Globals* const io_thread_globals = io_thread->globals();
242
243  ApplyProfileParamsToContext(extensions_context);
244
245  extensions_context->set_transport_security_state(transport_security_state());
246
247  extensions_context->set_net_log(io_thread->net_log());
248
249  extensions_context->set_throttler_manager(
250      io_thread_globals->throttler_manager.get());
251
252  // All we care about for extensions is the cookie store. For incognito, we
253  // use a non-persistent cookie store.
254  net::CookieMonster* extensions_cookie_store =
255      new net::CookieMonster(NULL, NULL);
256  // Enable cookies for devtools and extension URLs.
257  const char* schemes[] = {chrome::kChromeDevToolsScheme,
258                           extensions::kExtensionScheme};
259  extensions_cookie_store->SetCookieableSchemes(schemes, 2);
260  extensions_context->set_cookie_store(extensions_cookie_store);
261
262  scoped_ptr<net::URLRequestJobFactoryImpl> extensions_job_factory(
263      new net::URLRequestJobFactoryImpl());
264  // TODO(shalev): The extensions_job_factory has a NULL NetworkDelegate.
265  // Without a network_delegate, this protocol handler will never
266  // handle file: requests, but as a side effect it makes
267  // job_factory::IsHandledProtocol return true, which prevents attempts to
268  // handle the protocol externally. We pass NULL in to
269  // SetUpJobFactoryDefaults() to get this effect.
270  extensions_job_factory_ = SetUpJobFactoryDefaults(
271      extensions_job_factory.Pass(),
272      scoped_ptr<ProtocolHandlerRegistry::JobInterceptorFactory>(),
273      NULL,
274      ftp_factory_.get());
275  extensions_context->set_job_factory(extensions_job_factory_.get());
276}
277
278ChromeURLRequestContext*
279OffTheRecordProfileIOData::InitializeAppRequestContext(
280    ChromeURLRequestContext* main_context,
281    const StoragePartitionDescriptor& partition_descriptor,
282    scoped_ptr<ProtocolHandlerRegistry::JobInterceptorFactory>
283        protocol_handler_interceptor,
284    content::ProtocolHandlerMap* protocol_handlers) const {
285  AppRequestContext* context = new AppRequestContext(load_time_stats());
286
287  // Copy most state from the main context.
288  context->CopyFrom(main_context);
289
290  // Use a separate in-memory cookie store for the app.
291  // TODO(creis): We should have a cookie delegate for notifying the cookie
292  // extensions API, but we need to update it to understand isolated apps first.
293  context->SetCookieStore(new net::CookieMonster(NULL, NULL));
294
295  // Use a separate in-memory cache for the app.
296  net::HttpCache::BackendFactory* app_backend =
297      net::HttpCache::DefaultBackend::InMemory(0);
298  net::HttpNetworkSession* main_network_session =
299      main_http_factory_->GetSession();
300  scoped_ptr<net::HttpTransactionFactory> app_http_cache(
301      new net::HttpCache(main_network_session, app_backend));
302
303  context->SetHttpTransactionFactory(app_http_cache.Pass());
304
305  scoped_ptr<net::URLRequestJobFactoryImpl> job_factory(
306      new net::URLRequestJobFactoryImpl());
307  InstallProtocolHandlers(job_factory.get(), protocol_handlers);
308  scoped_ptr<net::URLRequestJobFactory> top_job_factory;
309  top_job_factory = SetUpJobFactoryDefaults(job_factory.Pass(),
310                                            protocol_handler_interceptor.Pass(),
311                                            network_delegate(),
312                                            ftp_factory_.get());
313  context->SetJobFactory(top_job_factory.Pass());
314  return context;
315}
316
317ChromeURLRequestContext*
318OffTheRecordProfileIOData::InitializeMediaRequestContext(
319    ChromeURLRequestContext* original_context,
320    const StoragePartitionDescriptor& partition_descriptor) const {
321  NOTREACHED();
322  return NULL;
323}
324
325ChromeURLRequestContext*
326OffTheRecordProfileIOData::AcquireMediaRequestContext() const {
327  NOTREACHED();
328  return NULL;
329}
330
331ChromeURLRequestContext*
332OffTheRecordProfileIOData::AcquireIsolatedAppRequestContext(
333    ChromeURLRequestContext* main_context,
334    const StoragePartitionDescriptor& partition_descriptor,
335    scoped_ptr<ProtocolHandlerRegistry::JobInterceptorFactory>
336        protocol_handler_interceptor,
337    content::ProtocolHandlerMap* protocol_handlers) const {
338  // We create per-app contexts on demand, unlike the others above.
339  ChromeURLRequestContext* app_request_context =
340      InitializeAppRequestContext(main_context, partition_descriptor,
341                                  protocol_handler_interceptor.Pass(),
342                                  protocol_handlers);
343  DCHECK(app_request_context);
344  return app_request_context;
345}
346
347ChromeURLRequestContext*
348OffTheRecordProfileIOData::AcquireIsolatedMediaRequestContext(
349    ChromeURLRequestContext* app_context,
350    const StoragePartitionDescriptor& partition_descriptor) const {
351  NOTREACHED();
352  return NULL;
353}
354
355chrome_browser_net::LoadTimeStats* OffTheRecordProfileIOData::GetLoadTimeStats(
356    IOThread::Globals* io_thread_globals) const {
357  return NULL;
358}
359