diff options
Diffstat (limited to 'chrome/browser/net')
-rw-r--r-- | chrome/browser/net/chrome_cookie_policy.cc | 162 | ||||
-rw-r--r-- | chrome/browser/net/chrome_cookie_policy.h | 74 | ||||
-rw-r--r-- | chrome/browser/net/chrome_url_request_context.cc | 53 | ||||
-rw-r--r-- | chrome/browser/net/chrome_url_request_context.h | 13 |
4 files changed, 256 insertions, 46 deletions
diff --git a/chrome/browser/net/chrome_cookie_policy.cc b/chrome/browser/net/chrome_cookie_policy.cc new file mode 100644 index 0000000..3e924d1 --- /dev/null +++ b/chrome/browser/net/chrome_cookie_policy.cc @@ -0,0 +1,162 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/net/chrome_cookie_policy.h" + +#include "base/string_util.h" +#include "chrome/browser/chrome_thread.h" +#include "chrome/browser/host_content_settings_map.h" +#include "googleurl/src/gurl.h" +#include "net/base/net_errors.h" +#include "net/base/static_cookie_policy.h" + +// If we queue up more than this number of completions, then switch from ASK to +// BLOCK. More than this number of requests at once seems like it could be a +// sign of trouble anyways. +static const size_t kMaxCompletionsPerHost = 10000; + +ChromeCookiePolicy::ChromeCookiePolicy(HostContentSettingsMap* map) + : host_content_settings_map_(map) { +} + +ChromeCookiePolicy::~ChromeCookiePolicy() { + DCHECK(host_completions_map_.empty()); +} + +int ChromeCookiePolicy::CanGetCookies(const GURL& url, + const GURL& first_party, + net::CompletionCallback* callback) { + if (host_content_settings_map_->BlockThirdPartyCookies()) { + net::StaticCookiePolicy policy( + net::StaticCookiePolicy::BLOCK_THIRD_PARTY_COOKIES); + int rv = policy.CanGetCookies(url, first_party, NULL); + if (rv != net::OK) + return rv; + } + + const std::string& host = url.host(); + + ContentSetting setting = host_content_settings_map_->GetContentSetting( + host, CONTENT_SETTINGS_TYPE_COOKIES); + if (setting == CONTENT_SETTING_BLOCK) + return net::ERR_ACCESS_DENIED; + if (setting == CONTENT_SETTING_ALLOW) + return net::OK; + + DCHECK(callback); + + // If we are currently prompting the user for a 'set-cookie' matching this + // host, then we need to defer reading cookies. + + HostCompletionsMap::iterator it = host_completions_map_.find(host); + if (it == host_completions_map_.end()) + return net::OK; + + if (it->second.size() >= kMaxCompletionsPerHost) { + LOG(ERROR) << "Would exceed kMaxCompletionsPerHost"; + return net::ERR_ACCESS_DENIED; + } + + it->second.push_back(Completion::ForGetCookies(callback)); + + return net::ERR_IO_PENDING; +} + +int ChromeCookiePolicy::CanSetCookie(const GURL& url, + const GURL& first_party, + const std::string& cookie_line, + net::CompletionCallback* callback) { + if (host_content_settings_map_->BlockThirdPartyCookies()) { + net::StaticCookiePolicy policy( + net::StaticCookiePolicy::BLOCK_THIRD_PARTY_COOKIES); + int rv = policy.CanSetCookie(url, first_party, cookie_line, NULL); + if (rv != net::OK) + return rv; + } + + const std::string& host = url.host(); + + ContentSetting setting = host_content_settings_map_->GetContentSetting( + host, CONTENT_SETTINGS_TYPE_COOKIES); + if (setting == CONTENT_SETTING_BLOCK) + return net::ERR_ACCESS_DENIED; + if (setting == CONTENT_SETTING_ALLOW) + return net::OK; + + DCHECK(callback); + + // Else, ask the user... + + Completions& completions = host_completions_map_[host]; + + if (completions.size() >= kMaxCompletionsPerHost) { + LOG(ERROR) << "Would exceed kMaxCompletionsPerHost"; + return net::ERR_ACCESS_DENIED; + } + + completions.push_back(Completion::ForSetCookie(callback)); + + PromptForSetCookie(host, cookie_line); + return net::ERR_IO_PENDING; +} + +void ChromeCookiePolicy::PromptForSetCookie(const std::string &host, + const std::string& cookie_line) { + if (!ChromeThread::CurrentlyOn(ChromeThread::UI)) { + ChromeThread::PostTask( + ChromeThread::UI, FROM_HERE, + NewRunnableMethod(this, &ChromeCookiePolicy::PromptForSetCookie, host, + cookie_line)); + return; + } + + // TODO(darin): Prompt user! +#if 0 + MessageBox(NULL, + UTF8ToWide(cookie_line).c_str(), + UTF8ToWide(host).c_str(), + MB_OK); +#endif + + DidPromptForSetCookie(host, net::OK); +} + +void ChromeCookiePolicy::DidPromptForSetCookie(const std::string &host, + int result) { + if (!ChromeThread::CurrentlyOn(ChromeThread::IO)) { + ChromeThread::PostTask( + ChromeThread::IO, FROM_HERE, + NewRunnableMethod(this, &ChromeCookiePolicy::DidPromptForSetCookie, + host, result)); + return; + } + + // Notify all callbacks, starting with the first until we hit another that + // is for a 'set-cookie'. + HostCompletionsMap::iterator it = host_completions_map_.find(host); + CHECK(it != host_completions_map_.end()); + + Completions& completions = it->second; + CHECK(!completions.empty() && completions[0].is_set_cookie_request()); + + // Gather the list of callbacks to notify, and remove them from the + // completions list before handing control to the callbacks (in case + // they should call back into us to modify host_completions_map_). + + std::vector<net::CompletionCallback*> callbacks; + callbacks.push_back(completions[0].callback()); + size_t i = 1; + for (; i < completions.size(); ++i) { + if (completions[i].is_set_cookie_request()) + break; + callbacks.push_back(completions[i].callback()); + } + completions.erase(completions.begin(), completions.begin() + i); + + if (completions.empty()) + host_completions_map_.erase(it); + + for (size_t j = 0; j < callbacks.size(); ++j) + callbacks[j]->Run(result); +} diff --git a/chrome/browser/net/chrome_cookie_policy.h b/chrome/browser/net/chrome_cookie_policy.h new file mode 100644 index 0000000..0d536f8 --- /dev/null +++ b/chrome/browser/net/chrome_cookie_policy.h @@ -0,0 +1,74 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_NET_CHROME_COOKIE_POLICY_H_ +#define CHROME_BROWSER_NET_CHROME_COOKIE_POLICY_H_ + +#include <map> +#include <vector> + +#include "base/ref_counted.h" +#include "net/base/cookie_policy.h" + +class HostContentSettingsMap; + +// Implements CookiePolicy that may delay queries to ask the user to decide. +// +// We will only prompt the user before setting a cookie. We do not prompt the +// user before getting a cookie. However, if we are in the process of +// prompting the user, then any requests to get cookies will be deferred. +// This is done so that cookie requests remain FIFO. +// +class ChromeCookiePolicy + : public base::RefCountedThreadSafe<ChromeCookiePolicy>, + public net::CookiePolicy { + public: + explicit ChromeCookiePolicy(HostContentSettingsMap* map); + ~ChromeCookiePolicy(); + + // CookiePolicy methods: + virtual int CanGetCookies(const GURL& url, const GURL& first_party, + net::CompletionCallback* callback); + virtual int CanSetCookie(const GURL& url, const GURL& first_party, + const std::string& cookie_line, + net::CompletionCallback* callback); + + private: + class Completion { + public: + static Completion ForSetCookie(net::CompletionCallback* callback) { + return Completion(true, callback); + } + + static Completion ForGetCookies(net::CompletionCallback* callback) { + return Completion(false, callback); + } + + bool is_set_cookie_request() const { return is_set_cookie_request_; } + net::CompletionCallback* callback() const { return callback_; } + + private: + Completion(bool is_set_cookie_request, net::CompletionCallback* callback) + : is_set_cookie_request_(is_set_cookie_request), + callback_(callback) { + } + + bool is_set_cookie_request_; + net::CompletionCallback* callback_; + }; + + typedef std::vector<Completion> Completions; + typedef std::map<std::string, Completions> HostCompletionsMap; + + void PromptForSetCookie(const std::string& host, + const std::string& cookie_line); + void DidPromptForSetCookie(const std::string& host, int result); + + // A map from hostname to callbacks awaiting a cookie policy response. + HostCompletionsMap host_completions_map_; + + scoped_refptr<HostContentSettingsMap> host_content_settings_map_; +}; + +#endif // CHROME_BROWSER_NET_CHROME_COOKIE_POLICY_H_ diff --git a/chrome/browser/net/chrome_url_request_context.cc b/chrome/browser/net/chrome_url_request_context.cc index 6b97030..8013800 100644 --- a/chrome/browser/net/chrome_url_request_context.cc +++ b/chrome/browser/net/chrome_url_request_context.cc @@ -184,6 +184,9 @@ ChromeURLRequestContext* FactoryForOriginal::Create() { context->set_cookie_store(new net::CookieMonster(cookie_db.get())); } + context->set_cookie_policy( + new ChromeCookiePolicy(host_content_settings_map_)); + // Create a new AppCacheService (issues fetches through the // main URLRequestContext that we just created). context->set_appcache_service( @@ -262,6 +265,8 @@ ChromeURLRequestContext* FactoryForOffTheRecord::Create() { new net::HttpCache(context->host_resolver(), context->proxy_service(), context->ssl_config_service(), 0); context->set_cookie_store(new net::CookieMonster); + context->set_cookie_policy( + new ChromeCookiePolicy(host_content_settings_map_)); context->set_http_transaction_factory(cache); if (CommandLine::ForCurrentProcess()->HasSwitch( @@ -300,6 +305,7 @@ ChromeURLRequestContext* FactoryForOffTheRecordExtensions::Create() { const char* schemes[] = {chrome::kExtensionScheme}; cookie_monster->SetCookieableSchemes(schemes, 1); context->set_cookie_store(cookie_monster); + // No dynamic cookie policy for extensions. return context; } @@ -341,6 +347,8 @@ ChromeURLRequestContext* FactoryForMedia::Create() { context->set_proxy_service(main_context->proxy_service()); // Also share the cookie store of the common profile. context->set_cookie_store(main_context->cookie_store()); + context->set_cookie_policy( + static_cast<ChromeCookiePolicy*>(main_context->cookie_policy())); // Create a media cache with default size. // TODO(hclam): make the maximum size of media cache configurable. @@ -606,8 +614,6 @@ void ChromeURLRequestContextGetter::GetCookieStoreAsyncHelper( ChromeURLRequestContext::ChromeURLRequestContext() { CheckCurrentlyOnIOThread(); - cookie_policy_ = this; // We implement CookiePolicy - url_request_tracker()->SetGraveyardFilter( &ChromeURLRequestContext::ShouldTrackRequest); } @@ -640,6 +646,9 @@ ChromeURLRequestContext::~ChromeURLRequestContext() { delete ftp_transaction_factory_; delete http_transaction_factory_; + // cookie_policy_'s lifetime is auto-managed by chrome_cookie_policy_. We + // null this out here to avoid a dangling reference to chrome_cookie_policy_ + // when ~URLRequestContext runs. cookie_policy_ = NULL; } @@ -756,48 +765,10 @@ bool ChromeURLRequestContext::AreCookiesEnabled() const { return setting != CONTENT_SETTING_BLOCK; } -bool ChromeURLRequestContext::CanGetCookies(const GURL& url, - const GURL& first_party) { - if (host_content_settings_map_->BlockThirdPartyCookies()) { - net::StaticCookiePolicy policy( - net::StaticCookiePolicy::BLOCK_THIRD_PARTY_COOKIES); - if (!policy.CanGetCookies(url, first_party)) - return false; - } - - ContentSetting setting = host_content_settings_map_->GetContentSetting( - url.host(), CONTENT_SETTINGS_TYPE_COOKIES); - if (setting == CONTENT_SETTING_BLOCK) - return false; - - // TODO(darin): Implement CONTENT_SETTING_ASK - return true; -} - -bool ChromeURLRequestContext::CanSetCookie(const GURL& url, - const GURL& first_party) { - if (host_content_settings_map_->BlockThirdPartyCookies()) { - net::StaticCookiePolicy policy( - net::StaticCookiePolicy::BLOCK_THIRD_PARTY_COOKIES); - if (!policy.CanSetCookie(url, first_party)) - return false; - } - - ContentSetting setting = host_content_settings_map_->GetContentSetting( - url.host(), CONTENT_SETTINGS_TYPE_COOKIES); - if (setting == CONTENT_SETTING_BLOCK) - return false; - - // TODO(darin): Implement CONTENT_SETTING_ASK - return true; -} - ChromeURLRequestContext::ChromeURLRequestContext( ChromeURLRequestContext* other) { CheckCurrentlyOnIOThread(); - cookie_policy_ = this; // We implement CookiePolicy - // Set URLRequestContext members host_resolver_ = other->host_resolver_; proxy_service_ = other->proxy_service_; @@ -805,6 +776,7 @@ ChromeURLRequestContext::ChromeURLRequestContext( http_transaction_factory_ = other->http_transaction_factory_; ftp_transaction_factory_ = other->ftp_transaction_factory_; cookie_store_ = other->cookie_store_; + cookie_policy_ = other->cookie_policy_; transport_security_state_ = other->transport_security_state_; accept_language_ = other->accept_language_; accept_charset_ = other->accept_charset_; @@ -814,6 +786,7 @@ ChromeURLRequestContext::ChromeURLRequestContext( extension_info_ = other->extension_info_; user_script_dir_path_ = other->user_script_dir_path_; appcache_service_ = other->appcache_service_; + chrome_cookie_policy_ = other->chrome_cookie_policy_; host_content_settings_map_ = other->host_content_settings_map_; host_zoom_map_ = other->host_zoom_map_; privacy_blacklist_ = other->privacy_blacklist_; diff --git a/chrome/browser/net/chrome_url_request_context.h b/chrome/browser/net/chrome_url_request_context.h index 8d4186d..f52029e 100644 --- a/chrome/browser/net/chrome_url_request_context.h +++ b/chrome/browser/net/chrome_url_request_context.h @@ -11,6 +11,7 @@ #include "chrome/browser/host_content_settings_map.h" #include "chrome/browser/host_zoom_map.h" #include "chrome/browser/privacy_blacklist/blacklist.h" +#include "chrome/browser/net/chrome_cookie_policy.h" #include "chrome/browser/net/url_request_context_getter.h" #include "chrome/common/appcache/chrome_appcache_service.h" #include "chrome/common/extensions/extension.h" @@ -34,8 +35,7 @@ class IOThread; // // All methods of this class must be called from the IO thread, // including the constructor and destructor. -class ChromeURLRequestContext : public URLRequestContext, - public net::CookiePolicy { +class ChromeURLRequestContext : public URLRequestContext { public: // Maintains some extension-related state we need on the IO thread. // TODO(aa): It would be cool if the Extension objects in ExtensionsService @@ -121,10 +121,6 @@ class ChromeURLRequestContext : public URLRequestContext, // False only if cookies are globally blocked without exception. bool AreCookiesEnabled() const; - // CookiePolicy methods: - virtual bool CanGetCookies(const GURL& url, const GURL& first_party); - virtual bool CanSetCookie(const GURL& url, const GURL& first_party); - protected: // Copies the dependencies from |other| into |this|. If you use this // constructor, then you should hold a reference to |other|, as we @@ -167,6 +163,10 @@ class ChromeURLRequestContext : public URLRequestContext, void set_cookie_store(net::CookieStore* cookie_store) { cookie_store_ = cookie_store; } + void set_cookie_policy(ChromeCookiePolicy* cookie_policy) { + chrome_cookie_policy_ = cookie_policy; // Take a strong reference. + cookie_policy_ = cookie_policy; + } void set_proxy_service(net::ProxyService* service) { proxy_service_ = service; } @@ -206,6 +206,7 @@ class ChromeURLRequestContext : public URLRequestContext, FilePath user_script_dir_path_; scoped_refptr<ChromeAppCacheService> appcache_service_; + scoped_refptr<ChromeCookiePolicy> chrome_cookie_policy_; scoped_refptr<HostContentSettingsMap> host_content_settings_map_; scoped_refptr<HostZoomMap> host_zoom_map_; scoped_refptr<Blacklist> privacy_blacklist_; |