chrome_url_request_context.cc revision 72a454cd3513ac24fbdd0e0cb9ad70b86a99b801
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/net/chrome_url_request_context.h"
6
7#include "base/command_line.h"
8#include "base/message_loop.h"
9#include "base/message_loop_proxy.h"
10#include "base/string_number_conversions.h"
11#include "base/string_util.h"
12#include "chrome/browser/browser_process.h"
13#include "chrome/browser/browser_thread.h"
14#include "chrome/browser/dom_ui/chrome_url_data_manager_backend.h"
15#include "chrome/browser/extensions/extension_service.h"
16#include "chrome/browser/extensions/user_script_master.h"
17#include "chrome/browser/io_thread.h"
18#include "chrome/browser/net/chrome_cookie_notification_details.h"
19#include "chrome/browser/net/chrome_net_log.h"
20#include "chrome/browser/net/chrome_dns_cert_provenance_checker_factory.h"
21#include "chrome/browser/net/sqlite_persistent_cookie_store.h"
22#include "chrome/browser/net/predictor_api.h"
23#include "chrome/browser/net/pref_proxy_config_service.h"
24#include "chrome/browser/profiles/profile.h"
25#include "chrome/browser/profiles/profile_io_data.h"
26#include "chrome/common/chrome_constants.h"
27#include "chrome/common/chrome_switches.h"
28#include "chrome/common/extensions/extension.h"
29#include "chrome/common/notification_service.h"
30#include "chrome/common/pref_names.h"
31#include "chrome/common/url_constants.h"
32#include "net/base/static_cookie_policy.h"
33#include "net/ftp/ftp_network_layer.h"
34#include "net/http/http_cache.h"
35#include "net/http/http_network_layer.h"
36#include "net/http/http_util.h"
37#include "net/proxy/proxy_config_service_fixed.h"
38#include "net/proxy/proxy_script_fetcher_impl.h"
39#include "net/proxy/proxy_service.h"
40#include "net/url_request/url_request.h"
41#include "webkit/glue/webkit_glue.h"
42
43#if defined(USE_NSS)
44#include "net/ocsp/nss_ocsp.h"
45#endif
46
47#if defined(OS_CHROMEOS)
48#include "chrome/browser/chromeos/cros/cros_library.h"
49#include "chrome/browser/chromeos/cros/libcros_service_library.h"
50#include "chrome/browser/chromeos/proxy_config_service.h"
51#endif  // defined(OS_CHROMEOS)
52
53namespace {
54
55// ----------------------------------------------------------------------------
56// Helper methods to check current thread
57// ----------------------------------------------------------------------------
58
59void CheckCurrentlyOnIOThread() {
60  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
61}
62
63void CheckCurrentlyOnMainThread() {
64  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
65}
66
67// ----------------------------------------------------------------------------
68// Helper methods to initialize proxy
69// ----------------------------------------------------------------------------
70
71net::ProxyConfigService* CreateProxyConfigService(Profile* profile) {
72  // The linux gconf-based proxy settings getter relies on being initialized
73  // from the UI thread.
74  CheckCurrentlyOnMainThread();
75
76  // Create a baseline service that provides proxy configuration in case nothing
77  // is configured through prefs (Note: prefs include command line and
78  // configuration policy).
79  net::ProxyConfigService* base_service = NULL;
80
81  // TODO(port): the IO and FILE message loops are only used by Linux.  Can
82  // that code be moved to chrome/browser instead of being in net, so that it
83  // can use BrowserThread instead of raw MessageLoop pointers? See bug 25354.
84#if defined(OS_CHROMEOS)
85  base_service = new chromeos::ProxyConfigService(
86      profile->GetChromeOSProxyConfigServiceImpl());
87#else
88  base_service = net::ProxyService::CreateSystemProxyConfigService(
89      g_browser_process->io_thread()->message_loop(),
90      g_browser_process->file_thread()->message_loop());
91#endif  // defined(OS_CHROMEOS)
92
93  return new PrefProxyConfigService(profile->GetProxyConfigTracker(),
94                                    base_service);
95}
96
97// Create a proxy service according to the options on command line.
98net::ProxyService* CreateProxyService(
99    net::NetLog* net_log,
100    net::URLRequestContext* context,
101    net::ProxyConfigService* proxy_config_service,
102    const CommandLine& command_line) {
103  CheckCurrentlyOnIOThread();
104
105  bool use_v8 = !command_line.HasSwitch(switches::kWinHttpProxyResolver);
106  if (use_v8 && command_line.HasSwitch(switches::kSingleProcess)) {
107    // See the note about V8 multithreading in net/proxy/proxy_resolver_v8.h
108    // to understand why we have this limitation.
109    LOG(ERROR) << "Cannot use V8 Proxy resolver in single process mode.";
110    use_v8 = false;  // Fallback to non-v8 implementation.
111  }
112
113  size_t num_pac_threads = 0u;  // Use default number of threads.
114
115  // Check the command line for an override on the number of proxy resolver
116  // threads to use.
117  if (command_line.HasSwitch(switches::kNumPacThreads)) {
118    std::string s = command_line.GetSwitchValueASCII(switches::kNumPacThreads);
119
120    // Parse the switch (it should be a positive integer formatted as decimal).
121    int n;
122    if (base::StringToInt(s, &n) && n > 0) {
123      num_pac_threads = static_cast<size_t>(n);
124    } else {
125      LOG(ERROR) << "Invalid switch for number of PAC threads: " << s;
126    }
127  }
128
129  net::ProxyService* proxy_service;
130  if (use_v8) {
131    proxy_service = net::ProxyService::CreateUsingV8ProxyResolver(
132        proxy_config_service,
133        num_pac_threads,
134        new net::ProxyScriptFetcherImpl(context),
135        context->host_resolver(),
136        net_log);
137  } else {
138    proxy_service = net::ProxyService::CreateUsingSystemProxyResolver(
139        proxy_config_service,
140        num_pac_threads,
141        net_log);
142  }
143
144#if defined(OS_CHROMEOS)
145  if (chromeos::CrosLibrary::Get()->EnsureLoaded()) {
146    chromeos::CrosLibrary::Get()->GetLibCrosServiceLibrary()->
147        RegisterNetworkProxyHandler(proxy_service);
148  }
149#endif  // defined(OS_CHROMEOS)
150
151  return proxy_service;
152}
153
154// ----------------------------------------------------------------------------
155// CookieMonster::Delegate implementation
156// ----------------------------------------------------------------------------
157class ChromeCookieMonsterDelegate : public net::CookieMonster::Delegate {
158 public:
159  explicit ChromeCookieMonsterDelegate(Profile* profile) {
160    CheckCurrentlyOnMainThread();
161    profile_getter_ = new ProfileGetter(profile);
162  }
163
164  // net::CookieMonster::Delegate implementation.
165  virtual void OnCookieChanged(
166      const net::CookieMonster::CanonicalCookie& cookie,
167      bool removed) {
168    BrowserThread::PostTask(
169        BrowserThread::UI, FROM_HERE,
170        NewRunnableMethod(this,
171            &ChromeCookieMonsterDelegate::OnCookieChangedAsyncHelper,
172            cookie,
173            removed));
174  }
175
176 private:
177  // This class allows us to safely access the Profile pointer. The Delegate
178  // itself cannot observe the PROFILE_DESTROYED notification, since it cannot
179  // guarantee to be deleted on the UI thread and therefore unregister from
180  // the notifications. All methods of ProfileGetter must be invoked on the UI
181  // thread.
182  class ProfileGetter
183      : public base::RefCountedThreadSafe<ProfileGetter,
184                                          BrowserThread::DeleteOnUIThread>,
185        public NotificationObserver {
186   public:
187    explicit ProfileGetter(Profile* profile) : profile_(profile) {
188      CheckCurrentlyOnMainThread();
189      registrar_.Add(this,
190                     NotificationType::PROFILE_DESTROYED,
191                     Source<Profile>(profile_));
192    }
193
194    // NotificationObserver implementation.
195    void Observe(NotificationType type,
196                 const NotificationSource& source,
197                 const NotificationDetails& details) {
198      CheckCurrentlyOnMainThread();
199      if (NotificationType::PROFILE_DESTROYED == type) {
200        Profile* profile = Source<Profile>(source).ptr();
201        if (profile_ == profile)
202          profile_ = NULL;
203      }
204    }
205
206    Profile* get() {
207      CheckCurrentlyOnMainThread();
208      return profile_;
209    }
210
211   private:
212    friend class ::BrowserThread;
213    friend class DeleteTask<ProfileGetter>;
214
215    virtual ~ProfileGetter() {}
216
217    NotificationRegistrar registrar_;
218
219    Profile* profile_;
220  };
221
222  virtual ~ChromeCookieMonsterDelegate() {}
223
224  void OnCookieChangedAsyncHelper(
225      const net::CookieMonster::CanonicalCookie& cookie,
226      bool removed) {
227    if (profile_getter_->get()) {
228      ChromeCookieDetails cookie_details(&cookie, removed);
229      NotificationService::current()->Notify(
230          NotificationType::COOKIE_CHANGED,
231          Source<Profile>(profile_getter_->get()),
232          Details<ChromeCookieDetails>(&cookie_details));
233    }
234  }
235
236  scoped_refptr<ProfileGetter> profile_getter_;
237};
238
239// ----------------------------------------------------------------------------
240// Helper factories
241// ----------------------------------------------------------------------------
242
243// Factory that creates the main ChromeURLRequestContext.
244class FactoryForOriginal : public ChromeURLRequestContextFactory {
245 public:
246  FactoryForOriginal(Profile* profile,
247                     const ProfileIOData* profile_io_data)
248      : ChromeURLRequestContextFactory(profile),
249        profile_io_data_(profile_io_data),
250        // We need to initialize the ProxyConfigService from the UI thread
251        // because on linux it relies on initializing things through gconf,
252        // and needs to be on the main thread.
253        proxy_config_service_(CreateProxyConfigService(profile)) {
254  }
255
256  virtual scoped_refptr<ChromeURLRequestContext> Create();
257
258 private:
259  const scoped_refptr<const ProfileIOData> profile_io_data_;
260  scoped_ptr<net::ProxyConfigService> proxy_config_service_;
261};
262
263scoped_refptr<ChromeURLRequestContext> FactoryForOriginal::Create() {
264  scoped_refptr<ChromeURLRequestContext> context =
265      profile_io_data_->GetMainRequestContext();
266  ApplyProfileParametersToContext(context);
267
268  IOThread::Globals* io_thread_globals = io_thread()->globals();
269  const ProfileIOData::LazyParams& params = profile_io_data_->lazy_params();
270
271  context->set_dns_cert_checker(
272      CreateDnsCertProvenanceChecker(io_thread_globals->dnsrr_resolver.get(),
273                                     context));
274
275  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
276
277  context->set_proxy_service(
278      CreateProxyService(io_thread()->net_log(),
279                         io_thread_globals->proxy_script_fetcher_context.get(),
280                         proxy_config_service_.release(),
281                         command_line));
282
283  net::HttpCache::DefaultBackend* backend = new net::HttpCache::DefaultBackend(
284      net::DISK_CACHE, params.cache_path, params.cache_max_size,
285      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE));
286  net::HttpCache* cache = new net::HttpCache(
287      context->host_resolver(),
288      context->cert_verifier(),
289      context->dnsrr_resolver(),
290      context->dns_cert_checker(),
291      context->proxy_service(),
292      context->ssl_config_service(),
293      context->http_auth_handler_factory(),
294      &io_thread_globals->network_delegate,
295      io_thread()->net_log(),
296      backend);
297
298  bool record_mode = chrome::kRecordModeEnabled &&
299                     command_line.HasSwitch(switches::kRecordMode);
300  bool playback_mode = command_line.HasSwitch(switches::kPlaybackMode);
301
302  if (record_mode || playback_mode) {
303    // Don't use existing cookies and use an in-memory store.
304    context->set_cookie_store(new net::CookieMonster(NULL,
305        cookie_monster_delegate_));
306    cache->set_mode(
307        record_mode ? net::HttpCache::RECORD : net::HttpCache::PLAYBACK);
308  }
309  context->set_http_transaction_factory(cache);
310
311  context->set_ftp_transaction_factory(
312      new net::FtpNetworkLayer(context->host_resolver()));
313
314  // setup cookie store
315  if (!context->cookie_store()) {
316    DCHECK(!params.cookie_path.empty());
317
318    scoped_refptr<SQLitePersistentCookieStore> cookie_db =
319        new SQLitePersistentCookieStore(params.cookie_path);
320    cookie_db->SetClearLocalStateOnExit(clear_local_state_on_exit_);
321    context->set_cookie_store(new net::CookieMonster(cookie_db.get(),
322        cookie_monster_delegate_));
323  }
324
325  context->set_cookie_policy(
326      new ChromeCookiePolicy(host_content_settings_map_));
327
328  appcache_service_->set_request_context(context);
329  return context;
330}
331
332// Factory that creates the ChromeURLRequestContext for extensions.
333class FactoryForExtensions : public ChromeURLRequestContextFactory {
334 public:
335  FactoryForExtensions(Profile* profile, const ProfileIOData* profile_io_data,
336                       bool incognito)
337      : ChromeURLRequestContextFactory(profile),
338        profile_io_data_(profile_io_data),
339        incognito_(incognito) {
340    DCHECK(incognito || profile_io_data);
341  }
342
343  virtual scoped_refptr<ChromeURLRequestContext> Create();
344
345 private:
346  const scoped_refptr<const ProfileIOData> profile_io_data_;
347  const bool incognito_;
348};
349
350scoped_refptr<ChromeURLRequestContext> FactoryForExtensions::Create() {
351  scoped_refptr<ChromeURLRequestContext> context = NULL;
352  if (incognito_)
353    context = new ChromeURLRequestContext;
354  else
355    context = profile_io_data_->GetExtensionsRequestContext();
356  ApplyProfileParametersToContext(context);
357
358  IOThread::Globals* io_thread_globals = io_thread()->globals();
359
360  // All we care about for extensions is the cookie store. For incognito, we
361  // use a non-persistent cookie store.
362  scoped_refptr<SQLitePersistentCookieStore> cookie_db = NULL;
363  if (!incognito_) {
364    const FilePath& cookie_store_path =
365        profile_io_data_->lazy_params().extensions_cookie_path;
366    DCHECK(!cookie_store_path.empty());
367    cookie_db = new SQLitePersistentCookieStore(cookie_store_path);
368  }
369
370  net::CookieMonster* cookie_monster =
371      new net::CookieMonster(cookie_db.get(), NULL);
372
373  // Enable cookies for devtools and extension URLs.
374  const char* schemes[] = {chrome::kChromeDevToolsScheme,
375                           chrome::kExtensionScheme};
376  cookie_monster->SetCookieableSchemes(schemes, 2);
377  context->set_cookie_store(cookie_monster);
378  context->set_network_delegate(&io_thread_globals->network_delegate);
379  // TODO(cbentzel): How should extensions handle HTTP Authentication?
380  context->set_http_auth_handler_factory(
381      io_thread_globals->http_auth_handler_factory.get());
382
383  return context;
384}
385
386// Factory that creates the ChromeURLRequestContext for incognito profile.
387class FactoryForOffTheRecord : public ChromeURLRequestContextFactory {
388 public:
389  explicit FactoryForOffTheRecord(Profile* profile)
390      : ChromeURLRequestContextFactory(profile),
391        proxy_config_service_(CreateProxyConfigService(profile)),
392        original_context_getter_(
393            static_cast<ChromeURLRequestContextGetter*>(
394                profile->GetOriginalProfile()->GetRequestContext())) {
395  }
396
397  virtual scoped_refptr<ChromeURLRequestContext> Create();
398
399 private:
400  scoped_ptr<net::ProxyConfigService> proxy_config_service_;
401  scoped_refptr<ChromeURLRequestContextGetter> original_context_getter_;
402};
403
404scoped_refptr<ChromeURLRequestContext> FactoryForOffTheRecord::Create() {
405  scoped_refptr<ChromeURLRequestContext> context = new ChromeURLRequestContext;
406  ApplyProfileParametersToContext(context);
407
408  IOThread::Globals* io_thread_globals = io_thread()->globals();
409  context->set_host_resolver(io_thread_globals->host_resolver.get());
410  context->set_cert_verifier(io_thread_globals->cert_verifier.get());
411  context->set_http_auth_handler_factory(
412      io_thread_globals->http_auth_handler_factory.get());
413  context->set_network_delegate(&io_thread_globals->network_delegate);
414
415  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
416  context->set_proxy_service(
417      CreateProxyService(io_thread()->net_log(),
418                         io_thread_globals->proxy_script_fetcher_context.get(),
419                         proxy_config_service_.release(),
420                         command_line));
421
422  net::HttpCache::BackendFactory* backend =
423      net::HttpCache::DefaultBackend::InMemory(0);
424
425  net::HttpCache* cache =
426      new net::HttpCache(io_thread_globals->host_resolver.get(),
427                         io_thread_globals->cert_verifier.get(),
428                         context->dnsrr_resolver(),
429                         NULL /* dns_cert_checker */,
430                         context->proxy_service(),
431                         context->ssl_config_service(),
432                         io_thread_globals->http_auth_handler_factory.get(),
433                         &io_thread_globals->network_delegate,
434                         io_thread()->net_log(),
435                         backend);
436  context->set_cookie_store(new net::CookieMonster(NULL,
437      cookie_monster_delegate_));
438  context->set_cookie_policy(
439      new ChromeCookiePolicy(host_content_settings_map_));
440  context->set_http_transaction_factory(cache);
441
442  context->set_ftp_transaction_factory(
443      new net::FtpNetworkLayer(context->host_resolver()));
444
445  appcache_service_->set_request_context(context);
446
447  context->set_net_log(io_thread()->net_log());
448  return context;
449}
450
451// Factory that creates the ChromeURLRequestContext for media.
452class FactoryForMedia : public ChromeURLRequestContextFactory {
453 public:
454  FactoryForMedia(Profile* profile,
455                  const ProfileIOData* profile_io_data)
456      : ChromeURLRequestContextFactory(profile),
457        main_context_getter_(
458            static_cast<ChromeURLRequestContextGetter*>(
459                profile->GetRequestContext())),
460        profile_io_data_(profile_io_data) {
461  }
462
463  virtual scoped_refptr<ChromeURLRequestContext> Create();
464
465 private:
466  scoped_refptr<ChromeURLRequestContextGetter> main_context_getter_;
467  const scoped_refptr<const ProfileIOData> profile_io_data_;
468};
469
470scoped_refptr<ChromeURLRequestContext> FactoryForMedia::Create() {
471  scoped_refptr<ChromeURLRequestContext> context =
472      profile_io_data_->GetMediaRequestContext();
473  ApplyProfileParametersToContext(context);
474
475  ChromeURLRequestContext* main_context = main_context_getter_->GetIOContext();
476
477  const ProfileIOData::LazyParams& params = profile_io_data_->lazy_params();
478
479  // TODO(willchan): Make a global ProxyService available in IOThread::Globals.
480  context->set_proxy_service(main_context->proxy_service());
481  context->set_network_delegate(main_context->network_delegate());
482
483  // Also share the cookie store of the common profile.
484  context->set_cookie_store(main_context->cookie_store());
485  context->set_cookie_policy(
486      static_cast<ChromeCookiePolicy*>(main_context->cookie_policy()));
487
488  // Create a media cache with default size.
489  // TODO(hclam): make the maximum size of media cache configurable.
490  net::HttpCache::DefaultBackend* backend = new net::HttpCache::DefaultBackend(
491      net::MEDIA_CACHE, params.media_cache_path, params.media_cache_max_size,
492      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE));
493
494  net::HttpCache* main_cache =
495      main_context->http_transaction_factory()->GetCache();
496  net::HttpNetworkSession* network_session = main_cache->GetSession();
497  net::HttpCache* cache = new net::HttpCache(network_session, backend);
498  context->set_http_transaction_factory(cache);
499  context->set_net_log(io_thread()->net_log());
500
501  return context;
502}
503
504}  // namespace
505
506// ----------------------------------------------------------------------------
507// ChromeURLRequestContextGetter
508// ----------------------------------------------------------------------------
509
510ChromeURLRequestContextGetter::ChromeURLRequestContextGetter(
511    Profile* profile,
512    ChromeURLRequestContextFactory* factory)
513    : io_thread_(g_browser_process->io_thread()),
514      factory_(factory),
515      url_request_context_(NULL) {
516  DCHECK(factory);
517
518  // If a base profile was specified, listen for changes to the preferences.
519  if (profile)
520    RegisterPrefsObserver(profile);
521}
522
523ChromeURLRequestContextGetter::~ChromeURLRequestContextGetter() {
524  CheckCurrentlyOnIOThread();
525
526  DCHECK(registrar_.IsEmpty()) << "Probably didn't call CleanupOnUIThread";
527
528  // Either we already transformed the factory into a net::URLRequestContext, or
529  // we still have a pending factory.
530  DCHECK((factory_.get() && !url_request_context_.get()) ||
531         (!factory_.get() && url_request_context_.get()));
532
533  if (url_request_context_)
534    io_thread_->UnregisterURLRequestContextGetter(this);
535
536  // The scoped_refptr / scoped_ptr destructors take care of releasing
537  // |factory_| and |url_request_context_| now.
538}
539
540// Lazily create a ChromeURLRequestContext using our factory.
541net::URLRequestContext* ChromeURLRequestContextGetter::GetURLRequestContext() {
542  CheckCurrentlyOnIOThread();
543
544  if (!url_request_context_) {
545    DCHECK(factory_.get());
546    url_request_context_ = factory_->Create();
547    if (is_main()) {
548      url_request_context_->set_is_main(true);
549#if defined(USE_NSS)
550      // TODO(ukai): find a better way to set the net::URLRequestContext for
551      // OCSP.
552      net::SetURLRequestContextForOCSP(url_request_context_);
553#endif
554    }
555
556    factory_.reset();
557    io_thread_->RegisterURLRequestContextGetter(this);
558  }
559
560  return url_request_context_;
561}
562
563void ChromeURLRequestContextGetter::ReleaseURLRequestContext() {
564  DCHECK(url_request_context_);
565  url_request_context_ = NULL;
566}
567
568net::CookieStore* ChromeURLRequestContextGetter::GetCookieStore() {
569  // If we are running on the IO thread this is real easy.
570  if (BrowserThread::CurrentlyOn(BrowserThread::IO))
571    return GetURLRequestContext()->cookie_store();
572
573  // If we aren't running on the IO thread, we cannot call
574  // GetURLRequestContext(). Instead we will post a task to the IO loop
575  // and wait for it to complete.
576
577  base::WaitableEvent completion(false, false);
578  net::CookieStore* result = NULL;
579
580  BrowserThread::PostTask(
581      BrowserThread::IO, FROM_HERE,
582      NewRunnableMethod(this,
583          &ChromeURLRequestContextGetter::GetCookieStoreAsyncHelper,
584          &completion,
585          &result));
586
587  completion.Wait();
588  DCHECK(result);
589  return result;
590}
591
592scoped_refptr<base::MessageLoopProxy>
593ChromeURLRequestContextGetter::GetIOMessageLoopProxy() const {
594  return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
595}
596
597// static
598ChromeURLRequestContextGetter* ChromeURLRequestContextGetter::CreateOriginal(
599    Profile* profile,
600    const ProfileIOData* profile_io_data) {
601  DCHECK(!profile->IsOffTheRecord());
602  return new ChromeURLRequestContextGetter(
603      profile,
604      new FactoryForOriginal(profile, profile_io_data));
605}
606
607// static
608ChromeURLRequestContextGetter*
609ChromeURLRequestContextGetter::CreateOriginalForMedia(
610    Profile* profile, const ProfileIOData* profile_io_data) {
611  DCHECK(!profile->IsOffTheRecord());
612  return new ChromeURLRequestContextGetter(
613      profile,
614      new FactoryForMedia(profile, profile_io_data));
615}
616
617// static
618ChromeURLRequestContextGetter*
619ChromeURLRequestContextGetter::CreateOriginalForExtensions(
620    Profile* profile, const ProfileIOData* profile_io_data) {
621  DCHECK(!profile->IsOffTheRecord());
622  return new ChromeURLRequestContextGetter(
623      profile,
624      new FactoryForExtensions(profile, profile_io_data, false));
625}
626
627// static
628ChromeURLRequestContextGetter*
629ChromeURLRequestContextGetter::CreateOffTheRecord(Profile* profile) {
630  DCHECK(profile->IsOffTheRecord());
631  return new ChromeURLRequestContextGetter(
632      profile, new FactoryForOffTheRecord(profile));
633}
634
635// static
636ChromeURLRequestContextGetter*
637ChromeURLRequestContextGetter::CreateOffTheRecordForExtensions(
638    Profile* profile) {
639  DCHECK(profile->IsOffTheRecord());
640  return new ChromeURLRequestContextGetter(
641      profile, new FactoryForExtensions(profile, NULL, true));
642}
643
644void ChromeURLRequestContextGetter::CleanupOnUIThread() {
645  CheckCurrentlyOnMainThread();
646  // Unregister for pref notifications.
647  registrar_.RemoveAll();
648}
649
650// NotificationObserver implementation.
651void ChromeURLRequestContextGetter::Observe(
652    NotificationType type,
653    const NotificationSource& source,
654    const NotificationDetails& details) {
655  CheckCurrentlyOnMainThread();
656
657  if (NotificationType::PREF_CHANGED == type) {
658    std::string* pref_name_in = Details<std::string>(details).ptr();
659    PrefService* prefs = Source<PrefService>(source).ptr();
660    DCHECK(pref_name_in && prefs);
661    if (*pref_name_in == prefs::kAcceptLanguages) {
662      std::string accept_language =
663          prefs->GetString(prefs::kAcceptLanguages);
664      BrowserThread::PostTask(
665          BrowserThread::IO, FROM_HERE,
666          NewRunnableMethod(
667              this,
668              &ChromeURLRequestContextGetter::OnAcceptLanguageChange,
669              accept_language));
670    } else if (*pref_name_in == prefs::kDefaultCharset) {
671      std::string default_charset =
672          prefs->GetString(prefs::kDefaultCharset);
673      BrowserThread::PostTask(
674          BrowserThread::IO, FROM_HERE,
675          NewRunnableMethod(
676              this,
677              &ChromeURLRequestContextGetter::OnDefaultCharsetChange,
678              default_charset));
679    } else if (*pref_name_in == prefs::kClearSiteDataOnExit) {
680      bool clear_site_data =
681          prefs->GetBoolean(prefs::kClearSiteDataOnExit);
682      BrowserThread::PostTask(
683          BrowserThread::IO, FROM_HERE,
684          NewRunnableMethod(
685              this,
686              &ChromeURLRequestContextGetter::OnClearSiteDataOnExitChange,
687              clear_site_data));
688    }
689  } else {
690    NOTREACHED();
691  }
692}
693
694void ChromeURLRequestContextGetter::RegisterPrefsObserver(Profile* profile) {
695  CheckCurrentlyOnMainThread();
696
697  registrar_.Init(profile->GetPrefs());
698  registrar_.Add(prefs::kAcceptLanguages, this);
699  registrar_.Add(prefs::kDefaultCharset, this);
700  registrar_.Add(prefs::kClearSiteDataOnExit, this);
701}
702
703void ChromeURLRequestContextGetter::OnAcceptLanguageChange(
704    const std::string& accept_language) {
705  GetIOContext()->OnAcceptLanguageChange(accept_language);
706}
707
708void ChromeURLRequestContextGetter::OnDefaultCharsetChange(
709    const std::string& default_charset) {
710  GetIOContext()->OnDefaultCharsetChange(default_charset);
711}
712
713void ChromeURLRequestContextGetter::OnClearSiteDataOnExitChange(
714    bool clear_site_data) {
715  GetCookieStore()->GetCookieMonster()->
716      SetClearPersistentStoreOnExit(clear_site_data);
717}
718
719void ChromeURLRequestContextGetter::GetCookieStoreAsyncHelper(
720    base::WaitableEvent* completion,
721    net::CookieStore** result) {
722  // Note that CookieStore is refcounted, yet we do not add a reference.
723  *result = GetURLRequestContext()->cookie_store();
724  completion->Signal();
725}
726
727// ----------------------------------------------------------------------------
728// ChromeURLRequestContext
729// ----------------------------------------------------------------------------
730
731ChromeURLRequestContext::ChromeURLRequestContext()
732    : is_off_the_record_(false) {
733  CheckCurrentlyOnIOThread();
734}
735
736ChromeURLDataManagerBackend*
737    ChromeURLRequestContext::GetChromeURLDataManagerBackend() {
738  if (!chrome_url_data_manager_backend_.get())
739    chrome_url_data_manager_backend_.reset(new ChromeURLDataManagerBackend());
740  return chrome_url_data_manager_backend_.get();
741}
742
743ChromeURLRequestContext::~ChromeURLRequestContext() {
744  CheckCurrentlyOnIOThread();
745
746  if (appcache_service_.get() && appcache_service_->request_context() == this)
747    appcache_service_->set_request_context(NULL);
748
749  if (proxy_service_ &&
750      proxy_service_->GetProxyScriptFetcher() &&
751      proxy_service_->GetProxyScriptFetcher()->GetRequestContext() == this) {
752    // Remove the ProxyScriptFetcher's weak reference to this context.
753    proxy_service_->SetProxyScriptFetcher(NULL);
754  }
755
756#if defined(USE_NSS)
757  if (is_main()) {
758    net::URLRequestContext* ocsp_context = net::GetURLRequestContextForOCSP();
759    if (ocsp_context) {
760      DCHECK_EQ(this, ocsp_context);
761      // We are releasing the net::URLRequestContext used by OCSP handlers.
762      net::SetURLRequestContextForOCSP(NULL);
763    }
764  }
765#endif
766
767  NotificationService::current()->Notify(
768      NotificationType::URL_REQUEST_CONTEXT_RELEASED,
769      Source<net::URLRequestContext>(this),
770      NotificationService::NoDetails());
771
772  delete ftp_transaction_factory_;
773  delete http_transaction_factory_;
774
775  // cookie_policy_'s lifetime is auto-managed by chrome_cookie_policy_.  We
776  // null this out here to avoid a dangling reference to chrome_cookie_policy_
777  // when ~net::URLRequestContext runs.
778  cookie_policy_ = NULL;
779}
780
781const std::string& ChromeURLRequestContext::GetUserAgent(
782    const GURL& url) const {
783  return webkit_glue::GetUserAgent(url);
784}
785
786void ChromeURLRequestContext::OnAcceptLanguageChange(
787    const std::string& accept_language) {
788  CheckCurrentlyOnIOThread();
789  accept_language_ =
790      net::HttpUtil::GenerateAcceptLanguageHeader(accept_language);
791}
792
793void ChromeURLRequestContext::OnDefaultCharsetChange(
794    const std::string& default_charset) {
795  CheckCurrentlyOnIOThread();
796  referrer_charset_ = default_charset;
797  accept_charset_ =
798      net::HttpUtil::GenerateAcceptCharsetHeader(default_charset);
799}
800
801// ----------------------------------------------------------------------------
802// ChromeURLRequestContextFactory
803// ----------------------------------------------------------------------------
804
805// Extract values from |profile| and copy them into
806// ChromeURLRequestContextFactory. We will use them later when constructing the
807// ChromeURLRequestContext on the IO thread (see
808// ApplyProfileParametersToContext() which reverses this).
809ChromeURLRequestContextFactory::ChromeURLRequestContextFactory(Profile* profile)
810    : is_off_the_record_(profile->IsOffTheRecord()),
811      io_thread_(g_browser_process->io_thread()) {
812  CheckCurrentlyOnMainThread();
813  PrefService* prefs = profile->GetPrefs();
814
815  // Set up Accept-Language and Accept-Charset header values
816  accept_language_ = net::HttpUtil::GenerateAcceptLanguageHeader(
817      prefs->GetString(prefs::kAcceptLanguages));
818  std::string default_charset = prefs->GetString(prefs::kDefaultCharset);
819  accept_charset_ =
820      net::HttpUtil::GenerateAcceptCharsetHeader(default_charset);
821  clear_local_state_on_exit_ = prefs->GetBoolean(prefs::kClearSiteDataOnExit);
822
823  // At this point, we don't know the charset of the referring page
824  // where a url request originates from. This is used to get a suggested
825  // filename from Content-Disposition header made of raw 8bit characters.
826  // Down the road, it can be overriden if it becomes known (for instance,
827  // when download request is made through the context menu in a web page).
828  // At the moment, it'll remain 'undeterministic' when a user
829  // types a URL in the omnibar or click on a download link in a page.
830  // For the latter, we need a change on the webkit-side.
831  // We initialize it to the default charset here and a user will
832  // have an *arguably* better default charset for interpreting a raw 8bit
833  // C-D header field.  It means the native OS codepage fallback in
834  // net_util::GetSuggestedFilename is unlikely to be taken.
835  referrer_charset_ = default_charset;
836
837  host_content_settings_map_ = profile->GetHostContentSettingsMap();
838  host_zoom_map_ = profile->GetHostZoomMap();
839  transport_security_state_ = profile->GetTransportSecurityState();
840
841  if (profile->GetUserScriptMaster())
842    user_script_dir_path_ = profile->GetUserScriptMaster()->user_script_dir();
843
844  ssl_config_service_ = profile->GetSSLConfigService();
845  profile_dir_path_ = profile->GetPath();
846  cookie_monster_delegate_ = new ChromeCookieMonsterDelegate(profile);
847  appcache_service_ = profile->GetAppCacheService();
848  database_tracker_ = profile->GetDatabaseTracker();
849  blob_storage_context_ = profile->GetBlobStorageContext();
850  file_system_context_ = profile->GetFileSystemContext();
851  extension_info_map_ = profile->GetExtensionInfoMap();
852  extension_io_event_router_ = profile->GetExtensionIOEventRouter();
853  prerender_manager_ = profile->GetPrerenderManager();
854}
855
856ChromeURLRequestContextFactory::~ChromeURLRequestContextFactory() {
857  CheckCurrentlyOnIOThread();
858}
859
860void ChromeURLRequestContextFactory::ApplyProfileParametersToContext(
861    ChromeURLRequestContext* context) {
862  // Apply all the parameters. NOTE: keep this in sync with
863  // ChromeURLRequestContextFactory(Profile*).
864  context->set_is_off_the_record(is_off_the_record_);
865  context->set_accept_language(accept_language_);
866  context->set_accept_charset(accept_charset_);
867  context->set_referrer_charset(referrer_charset_);
868  context->set_user_script_dir_path(user_script_dir_path_);
869  context->set_host_content_settings_map(host_content_settings_map_);
870  context->set_host_zoom_map(host_zoom_map_);
871  context->set_transport_security_state(
872      transport_security_state_);
873  context->set_ssl_config_service(ssl_config_service_);
874  context->set_appcache_service(appcache_service_);
875  context->set_database_tracker(database_tracker_);
876  context->set_blob_storage_context(blob_storage_context_);
877  context->set_file_system_context(file_system_context_);
878  context->set_extension_info_map(extension_info_map_);
879  context->set_extension_io_event_router(extension_io_event_router_);
880  context->set_prerender_manager(prerender_manager_);
881}
882