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