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