diff options
author | eroman@chromium.org <eroman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-23 06:33:31 +0000 |
---|---|---|
committer | eroman@chromium.org <eroman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-23 06:33:31 +0000 |
commit | be180c8044f145310f9eb13fd2cab5fd20e88220 (patch) | |
tree | 707ac9f3f95f5191664dbdac2ff3f34ab08ad8e7 /chrome/browser/net/chrome_url_request_context.cc | |
parent | 4cb1d3be9986c105608991f3dde12c6346335060 (diff) | |
download | chromium_src-be180c8044f145310f9eb13fd2cab5fd20e88220.zip chromium_src-be180c8044f145310f9eb13fd2cab5fd20e88220.tar.gz chromium_src-be180c8044f145310f9eb13fd2cab5fd20e88220.tar.bz2 |
Move initialization of ChromeURLRequestContexts to the IO thread.
Before, these URLRequestContexts were lazily created from the UI thread. Unfortunately that model made it easy for consumers on the UI thread to poke at stuff which was being used from the IO thread, and introduce races.
So instead of providing a URLRequestContext*, the Profile now vends a URLRequestContextGetter*.
The consequence of this is:
* Consumers on the UI thread can no longer get access to a URLRequestContext.
* Consumers on the IO thread need to call URLRequestContextGetter::GetURLRequestContext() to get at the context. This uses the same style lazy-creation of URLRequestContexts, albeit from the IO thread.
OK, so now the smelly part:
There were a couple of consumers of URLRequestContext on the UI thread that can't easily be moved to the IO thread -- these are the consumers of the cookie store. Before they could happily mess with the cookie store from the UI thread, and this was fine since CookieStore is threadsafe. However under the new model, they have no way to get at the URLRequestContext from the UI thread, hence can't get a pointer to the cookie store.
To support that use-cases, I bastardized the API some by adding a URLRequestContextGetter::GetCookieStore() method that lets UI thread consumers get a pointer to the cookie store, since we know this particular cross-thread usage is safe.
BUG=http://crbug.com/22294
Review URL: http://codereview.chromium.org/258008
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@29880 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/net/chrome_url_request_context.cc')
-rw-r--r-- | chrome/browser/net/chrome_url_request_context.cc | 596 |
1 files changed, 469 insertions, 127 deletions
diff --git a/chrome/browser/net/chrome_url_request_context.cc b/chrome/browser/net/chrome_url_request_context.cc index 368e95e..33b6f61 100644 --- a/chrome/browser/net/chrome_url_request_context.cc +++ b/chrome/browser/net/chrome_url_request_context.cc @@ -24,10 +24,31 @@ #include "net/http/http_cache.h" #include "net/http/http_network_layer.h" #include "net/http/http_util.h" +#include "net/proxy/proxy_config_service_fixed.h" #include "net/proxy/proxy_service.h" #include "net/url_request/url_request.h" #include "webkit/glue/webkit_glue.h" +#if defined(OS_LINUX) +#include "net/ocsp/nss_ocsp.h" +#endif + +// TODO(eroman): Fix the definition ordering to match-up with the declaration +// ordering (this was done to help keep the diffs simple during +// refactor). + +// TODO(eroman): The ChromeURLRequestContext's Blacklist* is shared with the +// Profile... This is a problem since the Profile dies before +// the IO thread, so we may end up accessing a deleted variable. + +static void CheckCurrentlyOnIOThread() { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); +} + +static void CheckCurrentlyOnMainThread() { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); +} + net::ProxyConfig* CreateProxyConfig(const CommandLine& command_line) { // Scan for all "enable" type proxy switches. static const char* proxy_switches[] = { @@ -86,10 +107,33 @@ net::ProxyConfig* CreateProxyConfig(const CommandLine& command_line) { return proxy_config; } +static net::ProxyConfigService* CreateProxyConfigService( + const CommandLine& command_line) { + // The linux gconf-based proxy settings getter relies on being initialized + // from the UI thread. + CheckCurrentlyOnMainThread(); + + scoped_ptr<net::ProxyConfig> proxy_config_from_cmd_line( + CreateProxyConfig(command_line)); + + if (!proxy_config_from_cmd_line.get()) { + // Use system settings. + return net::ProxyService::CreateSystemProxyConfigService( + g_browser_process->io_thread()->message_loop(), + g_browser_process->file_thread()->message_loop()); + } + + // Otherwise use the fixed settings from the command line. + return new net::ProxyConfigServiceFixed(*proxy_config_from_cmd_line.get()); +} + // Create a proxy service according to the options on command line. -static net::ProxyService* CreateProxyService(URLRequestContext* context, - const CommandLine& command_line) { - scoped_ptr<net::ProxyConfig> proxy_config(CreateProxyConfig(command_line)); +static net::ProxyService* CreateProxyService( + URLRequestContext* context, + net::ProxyConfigService* proxy_config_service, + const CommandLine& command_line, + MessageLoop* io_loop) { + CheckCurrentlyOnIOThread(); bool use_v8 = !command_line.HasSwitch(switches::kWinHttpProxyResolver); if (use_v8 && command_line.HasSwitch(switches::kSingleProcess)) { @@ -100,38 +144,87 @@ static net::ProxyService* CreateProxyService(URLRequestContext* context, } return net::ProxyService::Create( - proxy_config.get(), + proxy_config_service, use_v8, context, - g_browser_process->io_thread()->message_loop(), - g_browser_process->file_thread()->message_loop()); + io_loop); } +// Lazily create a ChromeURLRequestContext using our factory. +URLRequestContext* ChromeURLRequestContextGetter::GetURLRequestContext() { + CheckCurrentlyOnIOThread(); + + if (!url_request_context_) { + DCHECK(factory_.get()); + url_request_context_ = factory_->Create(); + factory_.reset(); + } + + return url_request_context_; +} + +// Factory that creates the main ChromeURLRequestContext. +class FactoryForOriginal : public ChromeURLRequestContextFactory { + public: + FactoryForOriginal(Profile* profile, + const FilePath& cookie_store_path, + const FilePath& disk_cache_path, + int cache_size) + : ChromeURLRequestContextFactory(profile), + cookie_store_path_(cookie_store_path), + disk_cache_path_(disk_cache_path), + cache_size_(cache_size), + // We need to initialize the ProxyConfigService from the UI thread + // because on linux it relies on initializing things through gconf, + // and needs to be on the main thread. + proxy_config_service_( + CreateProxyConfigService( + *CommandLine::ForCurrentProcess())) { + } + + virtual ChromeURLRequestContext* Create(); + + private: + FilePath cookie_store_path_; + FilePath disk_cache_path_; + int cache_size_; + + scoped_ptr<net::ProxyConfigService> proxy_config_service_; +}; + // static -ChromeURLRequestContext* ChromeURLRequestContext::CreateOriginal( +ChromeURLRequestContextGetter* ChromeURLRequestContextGetter::CreateOriginal( Profile* profile, const FilePath& cookie_store_path, - const FilePath& disk_cache_path, int cache_size, - ChromeAppCacheService* appcache_service) { + const FilePath& disk_cache_path, int cache_size) { DCHECK(!profile->IsOffTheRecord()); - ChromeURLRequestContext* context = new ChromeURLRequestContext( - profile, appcache_service); + return new ChromeURLRequestContextGetter( + profile, + new FactoryForOriginal(profile, + cookie_store_path, + disk_cache_path, + cache_size)); +} - // The appcache service uses the profile's original context for UpdateJobs. - DCHECK(!appcache_service->request_context()); - appcache_service->set_request_context(context); +ChromeURLRequestContext* FactoryForOriginal::Create() { + ChromeURLRequestContext* context = new ChromeURLRequestContext; + ApplyProfileParametersToContext(context); // Global host resolver for the context. - context->host_resolver_ = chrome_browser_net::GetGlobalHostResolver(); + context->set_host_resolver(chrome_browser_net::GetGlobalHostResolver()); const CommandLine& command_line = *CommandLine::ForCurrentProcess(); - context->proxy_service_ = CreateProxyService(context, command_line); + context->set_proxy_service( + CreateProxyService(context, + proxy_config_service_.release(), + command_line, + MessageLoop::current() /*io_loop*/)); net::HttpCache* cache = - new net::HttpCache(context->host_resolver_, - context->proxy_service_, - context->ssl_config_service_, - disk_cache_path, cache_size); + new net::HttpCache(context->host_resolver(), + context->proxy_service(), + context->ssl_config_service(), + disk_cache_path_, cache_size_); if (command_line.HasSwitch(switches::kDisableByteRangeSupport)) cache->set_enable_range_support(false); @@ -142,80 +235,130 @@ ChromeURLRequestContext* ChromeURLRequestContext::CreateOriginal( if (record_mode || playback_mode) { // Don't use existing cookies and use an in-memory store. - context->cookie_store_ = new net::CookieMonster(); + context->set_cookie_store(new net::CookieMonster()); cache->set_mode( record_mode ? net::HttpCache::RECORD : net::HttpCache::PLAYBACK); } - context->http_transaction_factory_ = cache; + context->set_http_transaction_factory(cache); // The kWininetFtp switch is Windows specific because we have two FTP // implementations on Windows. #if defined(OS_WIN) if (!command_line.HasSwitch(switches::kWininetFtp)) - context->ftp_transaction_factory_ = - new net::FtpNetworkLayer(context->host_resolver_); + context->set_ftp_transaction_factory( + new net::FtpNetworkLayer(context->host_resolver())); #else - context->ftp_transaction_factory_ = - new net::FtpNetworkLayer(context->host_resolver_); + context->set_ftp_transaction_factory( + new net::FtpNetworkLayer(context->host_resolver())); #endif // setup cookie store - if (!context->cookie_store_) { - DCHECK(!cookie_store_path.empty()); + if (!context->cookie_store()) { + DCHECK(!cookie_store_path_.empty()); scoped_refptr<SQLitePersistentCookieStore> cookie_db = new SQLitePersistentCookieStore( - cookie_store_path, - g_browser_process->db_thread()->message_loop()); - context->cookie_store_ = new net::CookieMonster(cookie_db.get()); + cookie_store_path_, + db_loop_); + context->set_cookie_store(new net::CookieMonster(cookie_db.get())); } + // Create a new AppCacheService (issues fetches through the + // main URLRequestContext that we just created). + context->set_appcache_service( + new ChromeAppCacheService(profile_dir_path_, false)); + context->appcache_service()->set_request_context(context); + +#if defined(OS_LINUX) + // TODO(ukai): find a better way to set the URLRequestContext for OCSP. + net::SetURLRequestContextForOCSP(context); +#endif + return context; } // static -ChromeURLRequestContext* ChromeURLRequestContext::CreateOriginalForMedia( - Profile* profile, const FilePath& disk_cache_path, int cache_size, - ChromeAppCacheService* appcache_service) { +ChromeURLRequestContextGetter* +ChromeURLRequestContextGetter::CreateOriginalForMedia( + Profile* profile, const FilePath& disk_cache_path, int cache_size) { DCHECK(!profile->IsOffTheRecord()); return CreateRequestContextForMedia(profile, disk_cache_path, cache_size, - false, appcache_service); + false); } +// Factory that creates the ChromeURLRequestContext for extensions. +class FactoryForExtensions : public ChromeURLRequestContextFactory { + public: + FactoryForExtensions(Profile* profile, const FilePath& cookie_store_path) + : ChromeURLRequestContextFactory(profile), + cookie_store_path_(cookie_store_path) { + } + + virtual ChromeURLRequestContext* Create(); + + private: + FilePath cookie_store_path_; +}; + // static -ChromeURLRequestContext* ChromeURLRequestContext::CreateOriginalForExtensions( +ChromeURLRequestContextGetter* +ChromeURLRequestContextGetter::CreateOriginalForExtensions( Profile* profile, const FilePath& cookie_store_path) { DCHECK(!profile->IsOffTheRecord()); - ChromeURLRequestContext* context = new ChromeURLRequestContext( - profile, NULL); + return new ChromeURLRequestContextGetter( + profile, + new FactoryForExtensions(profile, cookie_store_path)); +} + +ChromeURLRequestContext* FactoryForExtensions::Create() { + ChromeURLRequestContext* context = new ChromeURLRequestContext; + ApplyProfileParametersToContext(context); // All we care about for extensions is the cookie store. - DCHECK(!cookie_store_path.empty()); + DCHECK(!cookie_store_path_.empty()); scoped_refptr<SQLitePersistentCookieStore> cookie_db = - new SQLitePersistentCookieStore( - cookie_store_path, - g_browser_process->db_thread()->message_loop()); + new SQLitePersistentCookieStore(cookie_store_path_, db_loop_); net::CookieMonster* cookie_monster = new net::CookieMonster(cookie_db.get()); // Enable cookies for extension URLs only. const char* schemes[] = {chrome::kExtensionScheme}; cookie_monster->SetCookieableSchemes(schemes, 1); - context->cookie_store_ = cookie_monster; + context->set_cookie_store(cookie_monster); return context; } +// Factory that creates the ChromeURLRequestContext for incognito profile. +class FactoryForOffTheRecord : public ChromeURLRequestContextFactory { + public: + FactoryForOffTheRecord(Profile* profile) + : ChromeURLRequestContextFactory(profile), + original_context_getter_( + static_cast<ChromeURLRequestContextGetter*>( + profile->GetOriginalProfile()->GetRequestContext())) { + } + + virtual ChromeURLRequestContext* Create(); + + private: + scoped_refptr<ChromeURLRequestContextGetter> original_context_getter_; +}; + // static -ChromeURLRequestContext* ChromeURLRequestContext::CreateOffTheRecord( - Profile* profile, ChromeAppCacheService* appcache_service) { +ChromeURLRequestContextGetter* ChromeURLRequestContextGetter::CreateOffTheRecord( + Profile* profile) { DCHECK(profile->IsOffTheRecord()); - ChromeURLRequestContext* context = new ChromeURLRequestContext( - profile, appcache_service); + return new ChromeURLRequestContextGetter( + profile, new FactoryForOffTheRecord(profile)); +} + +ChromeURLRequestContext* FactoryForOffTheRecord::Create() { + ChromeURLRequestContext* context = new ChromeURLRequestContext; + ApplyProfileParametersToContext(context); - // The appcache service uses the profile's original context for UpdateJobs. - DCHECK(!appcache_service->request_context()); - appcache_service->set_request_context(context); + ChromeURLRequestContext* original_context = + original_context_getter_->GetIOContext(); // Share the same proxy service and host resolver as the original profile. // TODO(eroman): although ProxyService is reference counted, this sharing @@ -223,16 +366,14 @@ ChromeURLRequestContext* ChromeURLRequestContext::CreateOffTheRecord( // ProxyService holds a (non referencing) pointer to the URLRequestContext // it uses to download PAC scripts, which in this case is the original // profile... - context->host_resolver_ = - profile->GetOriginalProfile()->GetRequestContext()->host_resolver(); - context->proxy_service_ = - profile->GetOriginalProfile()->GetRequestContext()->proxy_service(); + context->set_host_resolver(original_context->host_resolver()); + context->set_proxy_service(original_context->proxy_service()); net::HttpCache* cache = - new net::HttpCache(context->host_resolver_, context->proxy_service_, - context->ssl_config_service_, 0); - context->cookie_store_ = new net::CookieMonster; - context->http_transaction_factory_ = cache; + new net::HttpCache(context->host_resolver(), context->proxy_service(), + context->ssl_config_service(), 0); + context->set_cookie_store(new net::CookieMonster); + context->set_http_transaction_factory(cache); if (CommandLine::ForCurrentProcess()->HasSwitch( switches::kDisableByteRangeSupport)) @@ -242,69 +383,129 @@ ChromeURLRequestContext* ChromeURLRequestContext::CreateOffTheRecord( // implementations on Windows. #if defined(OS_WIN) if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kWininetFtp)) - context->ftp_transaction_factory_ = - new net::FtpNetworkLayer(context->host_resolver_); + context->set_ftp_transaction_factory( + new net::FtpNetworkLayer(context->host_resolver())); #else - context->ftp_transaction_factory_ = - new net::FtpNetworkLayer(context->host_resolver_); + context->set_ftp_transaction_factory( + new net::FtpNetworkLayer(context->host_resolver())); #endif + // Create a separate AppCacheService for OTR mode. + context->set_appcache_service( + new ChromeAppCacheService(profile_dir_path_, true)); + context->appcache_service()->set_request_context(context); + return context; } +// Factory that creates the ChromeURLRequestContext for extensions in incognito +// mode. +class FactoryForOffTheRecordExtensions + : public ChromeURLRequestContextFactory { + public: + FactoryForOffTheRecordExtensions(Profile* profile) + : ChromeURLRequestContextFactory(profile) {} + + virtual ChromeURLRequestContext* Create(); +}; + // static -ChromeURLRequestContext* -ChromeURLRequestContext::CreateOffTheRecordForExtensions(Profile* profile) { +ChromeURLRequestContextGetter* +ChromeURLRequestContextGetter::CreateOffTheRecordForExtensions(Profile* profile) { DCHECK(profile->IsOffTheRecord()); - ChromeURLRequestContext* context = - new ChromeURLRequestContext(profile, NULL); + return new ChromeURLRequestContextGetter( + profile, + new FactoryForOffTheRecordExtensions(profile)); +} + +ChromeURLRequestContext* FactoryForOffTheRecordExtensions::Create() { + ChromeURLRequestContext* context = new ChromeURLRequestContext; + ApplyProfileParametersToContext(context); + net::CookieMonster* cookie_monster = new net::CookieMonster; // Enable cookies for extension URLs only. const char* schemes[] = {chrome::kExtensionScheme}; cookie_monster->SetCookieableSchemes(schemes, 1); - context->cookie_store_ = cookie_monster; + context->set_cookie_store(cookie_monster); return context; } +// Factory that creates the ChromeURLRequestContext for media. +class FactoryForMedia : public ChromeURLRequestContextFactory { + public: + FactoryForMedia(Profile* profile, + const FilePath& disk_cache_path, + int cache_size, + bool off_the_record) + : ChromeURLRequestContextFactory(profile), + main_context_getter_( + static_cast<ChromeURLRequestContextGetter*>( + profile->GetRequestContext())) { + is_media_ = true; + is_off_the_record_ = off_the_record; + } + + virtual ChromeURLRequestContext* Create(); + + private: + scoped_refptr<ChromeURLRequestContextGetter> main_context_getter_; + + FilePath disk_cache_path_; + int cache_size_; +}; + // static -ChromeURLRequestContext* ChromeURLRequestContext::CreateRequestContextForMedia( +ChromeURLRequestContextGetter* +ChromeURLRequestContextGetter::CreateRequestContextForMedia( Profile* profile, const FilePath& disk_cache_path, int cache_size, - bool off_the_record, ChromeAppCacheService* appcache_service) { - URLRequestContext* original_context = - profile->GetOriginalProfile()->GetRequestContext(); - ChromeURLRequestContext* context = - new ChromeURLRequestContext(profile, appcache_service); - context->is_media_ = true; + bool off_the_record) { + return new ChromeURLRequestContextGetter( + profile, + new FactoryForMedia(profile, + disk_cache_path, + cache_size, + off_the_record)); +} + +ChromeURLRequestContext* FactoryForMedia::Create() { + ChromeURLRequestContext* context = new ChromeURLRequestContext; + ApplyProfileParametersToContext(context); + + ChromeURLRequestContext* main_context = + main_context_getter_->GetIOContext(); // Share the same proxy service of the common profile. - context->proxy_service_ = original_context->proxy_service(); + context->set_proxy_service(main_context->proxy_service()); // Also share the cookie store of the common profile. - context->cookie_store_ = original_context->cookie_store(); + context->set_cookie_store(main_context->cookie_store()); // Create a media cache with default size. // TODO(hclam): make the maximum size of media cache configurable. - net::HttpCache* original_cache = - original_context->http_transaction_factory()->GetCache(); + net::HttpCache* main_cache = + main_context->http_transaction_factory()->GetCache(); net::HttpCache* cache; - if (original_cache) { - // Try to reuse HttpNetworkSession in the original context, assuming that + if (main_cache) { + // Try to reuse HttpNetworkSession in the main context, assuming that // HttpTransactionFactory (network_layer()) of HttpCache is implemented // by HttpNetworkLayer so we can reuse HttpNetworkSession within it. This // assumption will be invalid if the original HttpCache is constructed with // HttpCache(HttpTransactionFactory*, disk_cache::Backend*) constructor. - net::HttpNetworkLayer* original_network_layer = - static_cast<net::HttpNetworkLayer*>(original_cache->network_layer()); - cache = new net::HttpCache(original_network_layer->GetSession(), - disk_cache_path, cache_size); + net::HttpNetworkLayer* main_network_layer = + static_cast<net::HttpNetworkLayer*>(main_cache->network_layer()); + cache = new net::HttpCache(main_network_layer->GetSession(), + disk_cache_path_, cache_size_); + // TODO(eroman): Since this is poaching the session from the main + // context, it should hold a reference to that context preventing the + // session from getting deleted. } else { // If original HttpCache doesn't exist, simply construct one with a whole // new set of network stack. - cache = new net::HttpCache(original_context->host_resolver(), - original_context->proxy_service(), - original_context->ssl_config_service(), - disk_cache_path, cache_size); + cache = new net::HttpCache(main_context->host_resolver(), + main_context->proxy_service(), + main_context->ssl_config_service(), + disk_cache_path_, cache_size_); } if (CommandLine::ForCurrentProcess()->HasSwitch( @@ -312,21 +513,42 @@ ChromeURLRequestContext* ChromeURLRequestContext::CreateRequestContextForMedia( cache->set_enable_range_support(false); cache->set_type(net::MEDIA_CACHE); - context->http_transaction_factory_ = cache; + context->set_http_transaction_factory(cache); + + // Use the same appcache service as the profile's main context. + context->set_appcache_service(main_context->appcache_service()); + return context; } -ChromeURLRequestContext::ChromeURLRequestContext( - Profile* profile, ChromeAppCacheService* appcache_service) - : appcache_service_(appcache_service), - prefs_(profile->GetPrefs()), - is_media_(false), +ChromeURLRequestContextGetter::ChromeURLRequestContextGetter( + Profile* profile, + ChromeURLRequestContextFactory* factory) + : prefs_(NULL), + factory_(factory), + url_request_context_(NULL) { + DCHECK(factory); + + // If a base profile was specified, listen for changes to the preferences. + if (profile) + RegisterPrefsObserver(profile); +} + +// Extract values from |profile| and copy them into +// ChromeURLRequestContextFactory. We will use them later when constructing the +// ChromeURLRequestContext on the IO thread (see +// ApplyProfileParametersToContext() which reverses this). +ChromeURLRequestContextFactory::ChromeURLRequestContextFactory(Profile* profile) + : is_media_(false), is_off_the_record_(profile->IsOffTheRecord()) { + CheckCurrentlyOnMainThread(); + PrefService* prefs = profile->GetPrefs(); + // Set up Accept-Language and Accept-Charset header values accept_language_ = net::HttpUtil::GenerateAcceptLanguageHeader( - WideToASCII(prefs_->GetString(prefs::kAcceptLanguages))); + WideToASCII(prefs->GetString(prefs::kAcceptLanguages))); std::string default_charset = - WideToASCII(prefs_->GetString(prefs::kDefaultCharset)); + WideToASCII(prefs->GetString(prefs::kDefaultCharset)); accept_charset_ = net::HttpUtil::GenerateAcceptCharsetHeader(default_charset); @@ -344,11 +566,13 @@ ChromeURLRequestContext::ChromeURLRequestContext( // net_util::GetSuggestedFilename is unlikely to be taken. referrer_charset_ = default_charset; - cookie_policy_.set_type(net::CookiePolicy::FromInt( - prefs_->GetInteger(prefs::kCookieBehavior))); + cookie_policy_type_ = net::CookiePolicy::FromInt( + prefs->GetInteger(prefs::kCookieBehavior)); + // TODO(eroman): this doesn't look safe; sharing between IO and UI threads! blacklist_ = profile->GetBlacklist(); + // TODO(eroman): this doesn't look safe; sharing between IO and UI threads! strict_transport_security_state_ = profile->GetStrictTransportSecurityState(); if (profile->GetExtensionsService()) { @@ -363,15 +587,51 @@ ChromeURLRequestContext::ChromeURLRequestContext( if (profile->GetUserScriptMaster()) user_script_dir_path_ = profile->GetUserScriptMaster()->user_script_dir(); + // TODO(eroman): this doesn't look safe; sharing between IO and UI threads! + ssl_config_service_ = profile->GetSSLConfigService(); + + profile_dir_path_ = profile->GetPath(); + + // Get references to the database and file threads. + db_loop_ = g_browser_process->db_thread()->message_loop(); +} + +ChromeURLRequestContextFactory::~ChromeURLRequestContextFactory() { + CheckCurrentlyOnIOThread(); +} + +void ChromeURLRequestContextFactory::ApplyProfileParametersToContext( + ChromeURLRequestContext* context) { + // Apply all the parameters. NOTE: keep this in sync with + // ChromeURLRequestContextFactory(Profile*). + context->set_is_media(is_media_); + context->set_is_off_the_record(is_off_the_record_); + context->set_accept_language(accept_language_); + context->set_accept_charset(accept_charset_); + context->set_referrer_charset(referrer_charset_); + context->set_cookie_policy_type(cookie_policy_type_); + context->set_extension_paths(extension_paths_); + context->set_user_script_dir_path(user_script_dir_path_); + context->set_blacklist(blacklist_); + context->set_strict_transport_security_state( + strict_transport_security_state_); + context->set_ssl_config_service(ssl_config_service_); +} + +void ChromeURLRequestContextGetter::RegisterPrefsObserver(Profile* profile) { + CheckCurrentlyOnMainThread(); + + prefs_ = profile->GetPrefs(); + prefs_->AddPrefObserver(prefs::kAcceptLanguages, this); prefs_->AddPrefObserver(prefs::kCookieBehavior, this); prefs_->AddPrefObserver(prefs::kDefaultCharset, this); - - ssl_config_service_ = profile->GetSSLConfigService(); } ChromeURLRequestContext::ChromeURLRequestContext( ChromeURLRequestContext* other) { + CheckCurrentlyOnIOThread(); + // Set URLRequestContext members host_resolver_ = other->host_resolver_; proxy_service_ = other->proxy_service_; @@ -389,16 +649,17 @@ ChromeURLRequestContext::ChromeURLRequestContext( appcache_service_ = other->appcache_service_; extension_paths_ = other->extension_paths_; user_script_dir_path_ = other->user_script_dir_path_; - prefs_ = other->prefs_; blacklist_ = other->blacklist_; is_media_ = other->is_media_; is_off_the_record_ = other->is_off_the_record_; } // NotificationObserver implementation. -void ChromeURLRequestContext::Observe(NotificationType type, - const NotificationSource& source, - const NotificationDetails& details) { +void ChromeURLRequestContextGetter::Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + CheckCurrentlyOnMainThread(); + if (NotificationType::PREF_CHANGED == type) { std::wstring* pref_name_in = Details<std::wstring>(details).ptr(); PrefService* prefs = Source<PrefService>(source).ptr(); @@ -407,39 +668,91 @@ void ChromeURLRequestContext::Observe(NotificationType type, std::string accept_language = WideToASCII(prefs->GetString(prefs::kAcceptLanguages)); g_browser_process->io_thread()->message_loop()->PostTask(FROM_HERE, - NewRunnableMethod(this, - &ChromeURLRequestContext::OnAcceptLanguageChange, - accept_language)); + NewRunnableMethod( + this, + &ChromeURLRequestContextGetter::OnAcceptLanguageChange, + accept_language)); } else if (*pref_name_in == prefs::kCookieBehavior) { net::CookiePolicy::Type policy_type = net::CookiePolicy::FromInt( prefs_->GetInteger(prefs::kCookieBehavior)); g_browser_process->io_thread()->message_loop()->PostTask(FROM_HERE, - NewRunnableMethod(this, - &ChromeURLRequestContext::OnCookiePolicyChange, - policy_type)); + NewRunnableMethod( + this, + &ChromeURLRequestContextGetter::OnCookiePolicyChange, + policy_type)); } else if (*pref_name_in == prefs::kDefaultCharset) { std::string default_charset = WideToASCII(prefs->GetString(prefs::kDefaultCharset)); g_browser_process->io_thread()->message_loop()->PostTask(FROM_HERE, - NewRunnableMethod(this, - &ChromeURLRequestContext::OnDefaultCharsetChange, - default_charset)); + NewRunnableMethod( + this, + &ChromeURLRequestContextGetter::OnDefaultCharsetChange, + default_charset)); } } else { NOTREACHED(); } } -void ChromeURLRequestContext::CleanupOnUIThread() { - // Unregister for pref notifications. - prefs_->RemovePrefObserver(prefs::kAcceptLanguages, this); - prefs_->RemovePrefObserver(prefs::kCookieBehavior, this); - prefs_->RemovePrefObserver(prefs::kDefaultCharset, this); - prefs_ = NULL; +void ChromeURLRequestContextGetter::OnAcceptLanguageChange( + const std::string& accept_language) { + GetIOContext()->OnAcceptLanguageChange(accept_language); +} + +void ChromeURLRequestContextGetter::OnCookiePolicyChange( + net::CookiePolicy::Type type) { + GetIOContext()->OnCookiePolicyChange(type); +} +void ChromeURLRequestContextGetter::OnDefaultCharsetChange( + const std::string& default_charset) { + GetIOContext()->OnDefaultCharsetChange(default_charset); +} + +void ChromeURLRequestContextGetter::OnNewExtensions(const std::string& id, + const FilePath& path) { + GetIOContext()->OnNewExtensions(id, path); +} + +void ChromeURLRequestContextGetter::OnUnloadedExtension( + const std::string& id) { + GetIOContext()->OnUnloadedExtension(id); +} + +void ChromeURLRequestContextGetter::CleanupOnUIThread() { + CheckCurrentlyOnMainThread(); + + if (prefs_) { + // Unregister for pref notifications. + prefs_->RemovePrefObserver(prefs::kAcceptLanguages, this); + prefs_->RemovePrefObserver(prefs::kCookieBehavior, this); + prefs_->RemovePrefObserver(prefs::kDefaultCharset, this); + prefs_ = NULL; + } + + // TODO(eroman): Doesn't look like this member is even used... + // can probably be deleted. registrar_.RemoveAll(); } +ChromeURLRequestContextGetter::~ChromeURLRequestContextGetter() { + CheckCurrentlyOnIOThread(); + + DCHECK(!prefs_) << "Probably didn't call CleanupOnUIThread"; + + // Either we already transformed the factory into a URLRequestContext, or + // we still have a pending factory. + DCHECK((factory_.get() && !url_request_context_.get()) || + (!factory_.get() && url_request_context_.get())); + + // The scoped_refptr / scoped_ptr destructors take care of releasing + // |factory_| and |url_request_context_| now. +} + +ChromeURLRequestContext::ChromeURLRequestContext() { + CheckCurrentlyOnIOThread(); +} + FilePath ChromeURLRequestContext::GetPathForExtension(const std::string& id) { ExtensionPaths::iterator iter = extension_paths_.find(id); if (iter != extension_paths_.end()) { @@ -496,23 +809,20 @@ bool ChromeURLRequestContext::AllowSendingCookies(const URLRequest* request) void ChromeURLRequestContext::OnAcceptLanguageChange( const std::string& accept_language) { - DCHECK(MessageLoop::current() == - ChromeThread::GetMessageLoop(ChromeThread::IO)); + CheckCurrentlyOnIOThread(); accept_language_ = net::HttpUtil::GenerateAcceptLanguageHeader(accept_language); } void ChromeURLRequestContext::OnCookiePolicyChange( net::CookiePolicy::Type type) { - DCHECK(MessageLoop::current() == - ChromeThread::GetMessageLoop(ChromeThread::IO)); + CheckCurrentlyOnIOThread(); cookie_policy_.set_type(type); } void ChromeURLRequestContext::OnDefaultCharsetChange( const std::string& default_charset) { - DCHECK(MessageLoop::current() == - ChromeThread::GetMessageLoop(ChromeThread::IO)); + CheckCurrentlyOnIOThread(); referrer_charset_ = default_charset; accept_charset_ = net::HttpUtil::GenerateAcceptCharsetHeader(default_charset); @@ -525,6 +835,7 @@ void ChromeURLRequestContext::OnNewExtensions(const std::string& id, } void ChromeURLRequestContext::OnUnloadedExtension(const std::string& id) { + CheckCurrentlyOnIOThread(); if (is_off_the_record_) return; ExtensionPaths::iterator iter = extension_paths_.find(id); @@ -533,8 +844,7 @@ void ChromeURLRequestContext::OnUnloadedExtension(const std::string& id) { } ChromeURLRequestContext::~ChromeURLRequestContext() { - DCHECK(NULL == prefs_); - + CheckCurrentlyOnIOThread(); if (appcache_service_.get() && appcache_service_->request_context() == this) appcache_service_->set_request_context(NULL); @@ -546,3 +856,35 @@ ChromeURLRequestContext::~ChromeURLRequestContext() { delete ftp_transaction_factory_; delete http_transaction_factory_; } + +net::CookieStore* ChromeURLRequestContextGetter::GetCookieStore() { + // If we are running on the IO thread this is real easy. + if (ChromeThread::CurrentlyOn(ChromeThread::IO)) + return GetURLRequestContext()->cookie_store(); + + // If we aren't running on the IO thread, we cannot call + // GetURLRequestContext(). Instead we will post a task to the IO loop + // and wait for it to complete. + + base::WaitableEvent completion(false, false); + net::CookieStore* result = NULL; + + g_browser_process->io_thread()->message_loop()->PostTask( + FROM_HERE, + NewRunnableMethod(this, + &ChromeURLRequestContextGetter::GetCookieStoreAsyncHelper, + &completion, + &result)); + + completion.Wait(); + DCHECK(result); + return result; +} + +void ChromeURLRequestContextGetter::GetCookieStoreAsyncHelper( + base::WaitableEvent* completion, + net::CookieStore** result) { + // Note that CookieStore is refcounted, yet we do not add a reference. + *result = GetURLRequestContext()->cookie_store(); + completion->Signal(); +} |