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