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