chrome_url_request_context.cc revision dc0f95d653279beabeb9817299e2902918ba123e
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/message_loop.h" 8#include "base/message_loop_proxy.h" 9#include "chrome/browser/browser_process.h" 10#include "chrome/browser/io_thread.h" 11#include "chrome/browser/net/chrome_cookie_policy.h" 12#include "chrome/browser/profiles/profile.h" 13#include "chrome/browser/profiles/profile_io_data.h" 14#include "chrome/browser/ui/webui/chrome_url_data_manager_backend.h" 15#include "chrome/common/notification_service.h" 16#include "chrome/common/pref_names.h" 17#include "content/browser/browser_thread.h" 18#include "net/base/cookie_store.h" 19#include "net/ftp/ftp_transaction_factory.h" 20#include "net/http/http_transaction_factory.h" 21#include "net/http/http_util.h" 22#include "webkit/glue/webkit_glue.h" 23 24#if defined(USE_NSS) 25#include "net/ocsp/nss_ocsp.h" 26#endif 27 28#if defined(OS_CHROMEOS) 29#include "chrome/browser/chromeos/cros/cros_library.h" 30#include "chrome/browser/chromeos/cros/libcros_service_library.h" 31#include "chrome/browser/chromeos/proxy_config_service.h" 32#endif // defined(OS_CHROMEOS) 33 34class ChromeURLRequestContextFactory { 35 public: 36 ChromeURLRequestContextFactory() {} 37 virtual ~ChromeURLRequestContextFactory() {} 38 39 // Called to create a new instance (will only be called once). 40 virtual scoped_refptr<ChromeURLRequestContext> Create() = 0; 41 42 protected: 43 DISALLOW_COPY_AND_ASSIGN(ChromeURLRequestContextFactory); 44}; 45 46namespace { 47 48// ---------------------------------------------------------------------------- 49// Helper factories 50// ---------------------------------------------------------------------------- 51 52// Factory that creates the main ChromeURLRequestContext. 53class FactoryForMain : public ChromeURLRequestContextFactory { 54 public: 55 explicit FactoryForMain(const ProfileIOData* profile_io_data) 56 : profile_io_data_(profile_io_data) {} 57 58 virtual scoped_refptr<ChromeURLRequestContext> Create() { 59 return profile_io_data_->GetMainRequestContext(); 60 } 61 62 private: 63 const scoped_refptr<const ProfileIOData> profile_io_data_; 64}; 65 66// Factory that creates the ChromeURLRequestContext for extensions. 67class FactoryForExtensions : public ChromeURLRequestContextFactory { 68 public: 69 explicit FactoryForExtensions(const ProfileIOData* profile_io_data) 70 : profile_io_data_(profile_io_data) {} 71 72 virtual scoped_refptr<ChromeURLRequestContext> Create() { 73 return profile_io_data_->GetExtensionsRequestContext(); 74 } 75 76 private: 77 const scoped_refptr<const ProfileIOData> profile_io_data_; 78}; 79 80// Factory that creates the ChromeURLRequestContext for media. 81class FactoryForMedia : public ChromeURLRequestContextFactory { 82 public: 83 explicit FactoryForMedia(const ProfileIOData* profile_io_data) 84 : profile_io_data_(profile_io_data) { 85 } 86 87 virtual scoped_refptr<ChromeURLRequestContext> Create() { 88 return profile_io_data_->GetMediaRequestContext(); 89 } 90 91 private: 92 const scoped_refptr<const ProfileIOData> profile_io_data_; 93}; 94 95} // namespace 96 97// ---------------------------------------------------------------------------- 98// ChromeURLRequestContextGetter 99// ---------------------------------------------------------------------------- 100 101ChromeURLRequestContextGetter::ChromeURLRequestContextGetter( 102 Profile* profile, 103 ChromeURLRequestContextFactory* factory) 104 : io_thread_(g_browser_process->io_thread()), 105 factory_(factory), 106 url_request_context_(NULL) { 107 DCHECK(factory); 108 DCHECK(profile); 109 RegisterPrefsObserver(profile); 110} 111 112ChromeURLRequestContextGetter::~ChromeURLRequestContextGetter() { 113 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 114 115 DCHECK(registrar_.IsEmpty()) << "Probably didn't call CleanupOnUIThread"; 116 117 // Either we already transformed the factory into a net::URLRequestContext, or 118 // we still have a pending factory. 119 DCHECK((factory_.get() && !url_request_context_.get()) || 120 (!factory_.get() && url_request_context_.get())); 121 122 if (url_request_context_) 123 io_thread_->UnregisterURLRequestContextGetter(this); 124 125 // The scoped_refptr / scoped_ptr destructors take care of releasing 126 // |factory_| and |url_request_context_| now. 127} 128 129// Lazily create a ChromeURLRequestContext using our factory. 130net::URLRequestContext* ChromeURLRequestContextGetter::GetURLRequestContext() { 131 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 132 133 if (!url_request_context_) { 134 DCHECK(factory_.get()); 135 url_request_context_ = factory_->Create(); 136 if (is_main()) { 137 url_request_context_->set_is_main(true); 138#if defined(USE_NSS) 139 // TODO(ukai): find a better way to set the net::URLRequestContext for 140 // OCSP. 141 net::SetURLRequestContextForOCSP(url_request_context_); 142#endif 143 } 144 145 factory_.reset(); 146 io_thread_->RegisterURLRequestContextGetter(this); 147 } 148 149 return url_request_context_; 150} 151 152void ChromeURLRequestContextGetter::ReleaseURLRequestContext() { 153 DCHECK(url_request_context_); 154 url_request_context_ = NULL; 155} 156 157net::CookieStore* ChromeURLRequestContextGetter::GetCookieStore() { 158 // If we are running on the IO thread this is real easy. 159 if (BrowserThread::CurrentlyOn(BrowserThread::IO)) 160 return GetURLRequestContext()->cookie_store(); 161 162 // If we aren't running on the IO thread, we cannot call 163 // GetURLRequestContext(). Instead we will post a task to the IO loop 164 // and wait for it to complete. 165 166 base::WaitableEvent completion(false, false); 167 net::CookieStore* result = NULL; 168 169 BrowserThread::PostTask( 170 BrowserThread::IO, FROM_HERE, 171 NewRunnableMethod(this, 172 &ChromeURLRequestContextGetter::GetCookieStoreAsyncHelper, 173 &completion, 174 &result)); 175 176 completion.Wait(); 177 DCHECK(result); 178 return result; 179} 180 181scoped_refptr<base::MessageLoopProxy> 182ChromeURLRequestContextGetter::GetIOMessageLoopProxy() const { 183 return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO); 184} 185 186// static 187ChromeURLRequestContextGetter* ChromeURLRequestContextGetter::CreateOriginal( 188 Profile* profile, 189 const ProfileIOData* profile_io_data) { 190 DCHECK(!profile->IsOffTheRecord()); 191 return new ChromeURLRequestContextGetter( 192 profile, 193 new FactoryForMain(profile_io_data)); 194} 195 196// static 197ChromeURLRequestContextGetter* 198ChromeURLRequestContextGetter::CreateOriginalForMedia( 199 Profile* profile, const ProfileIOData* profile_io_data) { 200 DCHECK(!profile->IsOffTheRecord()); 201 return new ChromeURLRequestContextGetter( 202 profile, 203 new FactoryForMedia(profile_io_data)); 204} 205 206// static 207ChromeURLRequestContextGetter* 208ChromeURLRequestContextGetter::CreateOriginalForExtensions( 209 Profile* profile, const ProfileIOData* profile_io_data) { 210 DCHECK(!profile->IsOffTheRecord()); 211 return new ChromeURLRequestContextGetter( 212 profile, 213 new FactoryForExtensions(profile_io_data)); 214} 215 216// static 217ChromeURLRequestContextGetter* 218ChromeURLRequestContextGetter::CreateOffTheRecord( 219 Profile* profile, const ProfileIOData* profile_io_data) { 220 DCHECK(profile->IsOffTheRecord()); 221 return new ChromeURLRequestContextGetter( 222 profile, new FactoryForMain(profile_io_data)); 223} 224 225// static 226ChromeURLRequestContextGetter* 227ChromeURLRequestContextGetter::CreateOffTheRecordForExtensions( 228 Profile* profile, const ProfileIOData* profile_io_data) { 229 DCHECK(profile->IsOffTheRecord()); 230 return new ChromeURLRequestContextGetter( 231 profile, new FactoryForExtensions(profile_io_data)); 232} 233 234void ChromeURLRequestContextGetter::CleanupOnUIThread() { 235 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 236 // Unregister for pref notifications. 237 DCHECK(!registrar_.IsEmpty()) << "Called more than once!"; 238 registrar_.RemoveAll(); 239} 240 241// NotificationObserver implementation. 242void ChromeURLRequestContextGetter::Observe( 243 NotificationType type, 244 const NotificationSource& source, 245 const NotificationDetails& details) { 246 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 247 248 if (NotificationType::PREF_CHANGED == type) { 249 std::string* pref_name_in = Details<std::string>(details).ptr(); 250 PrefService* prefs = Source<PrefService>(source).ptr(); 251 DCHECK(pref_name_in && prefs); 252 if (*pref_name_in == prefs::kAcceptLanguages) { 253 std::string accept_language = 254 prefs->GetString(prefs::kAcceptLanguages); 255 BrowserThread::PostTask( 256 BrowserThread::IO, FROM_HERE, 257 NewRunnableMethod( 258 this, 259 &ChromeURLRequestContextGetter::OnAcceptLanguageChange, 260 accept_language)); 261 } else if (*pref_name_in == prefs::kDefaultCharset) { 262 std::string default_charset = 263 prefs->GetString(prefs::kDefaultCharset); 264 BrowserThread::PostTask( 265 BrowserThread::IO, FROM_HERE, 266 NewRunnableMethod( 267 this, 268 &ChromeURLRequestContextGetter::OnDefaultCharsetChange, 269 default_charset)); 270 } else if (*pref_name_in == prefs::kClearSiteDataOnExit) { 271 bool clear_site_data = 272 prefs->GetBoolean(prefs::kClearSiteDataOnExit); 273 BrowserThread::PostTask( 274 BrowserThread::IO, FROM_HERE, 275 NewRunnableMethod( 276 this, 277 &ChromeURLRequestContextGetter::OnClearSiteDataOnExitChange, 278 clear_site_data)); 279 } 280 } else { 281 NOTREACHED(); 282 } 283} 284 285void ChromeURLRequestContextGetter::RegisterPrefsObserver(Profile* profile) { 286 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 287 288 registrar_.Init(profile->GetPrefs()); 289 registrar_.Add(prefs::kAcceptLanguages, this); 290 registrar_.Add(prefs::kDefaultCharset, this); 291 registrar_.Add(prefs::kClearSiteDataOnExit, this); 292} 293 294void ChromeURLRequestContextGetter::OnAcceptLanguageChange( 295 const std::string& accept_language) { 296 GetIOContext()->OnAcceptLanguageChange(accept_language); 297} 298 299void ChromeURLRequestContextGetter::OnDefaultCharsetChange( 300 const std::string& default_charset) { 301 GetIOContext()->OnDefaultCharsetChange(default_charset); 302} 303 304void ChromeURLRequestContextGetter::OnClearSiteDataOnExitChange( 305 bool clear_site_data) { 306 GetCookieStore()->GetCookieMonster()-> 307 SetClearPersistentStoreOnExit(clear_site_data); 308} 309 310void ChromeURLRequestContextGetter::GetCookieStoreAsyncHelper( 311 base::WaitableEvent* completion, 312 net::CookieStore** result) { 313 // Note that CookieStore is refcounted, yet we do not add a reference. 314 *result = GetURLRequestContext()->cookie_store(); 315 completion->Signal(); 316} 317 318// ---------------------------------------------------------------------------- 319// ChromeURLRequestContext 320// ---------------------------------------------------------------------------- 321 322ChromeURLRequestContext::ChromeURLRequestContext() 323 : is_off_the_record_(false) { 324 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 325} 326 327void ChromeURLRequestContext::set_chrome_cookie_policy( 328 ChromeCookiePolicy* cookie_policy) { 329 chrome_cookie_policy_ = cookie_policy; // Take a strong reference. 330 set_cookie_policy(cookie_policy); 331} 332 333ChromeURLDataManagerBackend* 334 ChromeURLRequestContext::GetChromeURLDataManagerBackend() { 335 if (!chrome_url_data_manager_backend_.get()) 336 chrome_url_data_manager_backend_.reset(new ChromeURLDataManagerBackend()); 337 return chrome_url_data_manager_backend_.get(); 338} 339 340ChromeURLRequestContext::~ChromeURLRequestContext() { 341 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 342 343 if (appcache_service_.get() && appcache_service_->request_context() == this) 344 appcache_service_->set_request_context(NULL); 345 346#if defined(USE_NSS) 347 if (is_main()) { 348 net::URLRequestContext* ocsp_context = net::GetURLRequestContextForOCSP(); 349 if (ocsp_context) { 350 DCHECK_EQ(this, ocsp_context); 351 // We are releasing the net::URLRequestContext used by OCSP handlers. 352 net::SetURLRequestContextForOCSP(NULL); 353 } 354 } 355#endif 356 357 NotificationService::current()->Notify( 358 NotificationType::URL_REQUEST_CONTEXT_RELEASED, 359 Source<net::URLRequestContext>(this), 360 NotificationService::NoDetails()); 361 362 // cookie_policy_'s lifetime is auto-managed by chrome_cookie_policy_. We 363 // null this out here to avoid a dangling reference to chrome_cookie_policy_ 364 // when ~net::URLRequestContext runs. 365 set_cookie_policy(NULL); 366} 367 368const std::string& ChromeURLRequestContext::GetUserAgent( 369 const GURL& url) const { 370 return webkit_glue::GetUserAgent(url); 371} 372 373void ChromeURLRequestContext::OnAcceptLanguageChange( 374 const std::string& accept_language) { 375 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 376 set_accept_language( 377 net::HttpUtil::GenerateAcceptLanguageHeader(accept_language)); 378} 379 380void ChromeURLRequestContext::OnDefaultCharsetChange( 381 const std::string& default_charset) { 382 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 383 set_referrer_charset(default_charset); 384 set_accept_charset( 385 net::HttpUtil::GenerateAcceptCharsetHeader(default_charset)); 386} 387