diff options
author | darin@chromium.org <darin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-02-03 19:19:15 +0000 |
---|---|---|
committer | darin@chromium.org <darin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-02-03 19:19:15 +0000 |
commit | c7a90eab2f4a045fee103dbfa18710918b368476 (patch) | |
tree | e12ebddacb41a61bb804deff42a504b0361f5544 /chrome/browser | |
parent | 97cdd4667b961cf865047d0bc764764a7c199ce7 (diff) | |
download | chromium_src-c7a90eab2f4a045fee103dbfa18710918b368476.zip chromium_src-c7a90eab2f4a045fee103dbfa18710918b368476.tar.gz chromium_src-c7a90eab2f4a045fee103dbfa18710918b368476.tar.bz2 |
Modify CookiePolicy to work asynchronously
This change will enable us to prompt the user before setting a cookie. While we only need to prompt before setting, we actually need to make both CanSetCookie and CanGetCookies asynchronous. This is necessary in order to preserve FIFO ordering since the value returned by GetCookies depends on the changes made to the cookie DB by SetCookie.
This change also includes some simplification of CookieStore. Instead of N virtual functions, I distilled it down to only 4. The remaining functions are instead expressed in terms of those.
While studying all the places where we currently use CookiePolicy, I found that some of them were not appropriate. After discussing with Amit, I decided to remove the policy checks in URLRequestAutomationJob. See the comments in the code regarding this.
I changed the signature of CookieMonster::GetRawCookies to GetAllCookiesForURL to better match GetAllCookies. I also filed a bug about making it even closer in functionality. Related to this change webkit/glue/webcookie.h grows a constructor that takes a CanonicalCookie to help clean up some code.
On the Chrome side, ChromeURLRequestContext now has a ChromeCookiePolicy object. That object is thread-safe ref counted because it is passed between the UI and IO threads. It is responsible for implementing the queuing logic described above. It will also in the future trigger the Chrome UI code to actually show the set-cookie prompt.
Please review the state machinery changes in URLRequestHttpJob carefully.
R=eroman
BUG=34331
TEST=no tests yet for prompting.
Review URL: http://codereview.chromium.org/567015
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@37998 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r-- | chrome/browser/automation/automation_profile_impl.cc | 42 | ||||
-rw-r--r-- | chrome/browser/automation/url_request_automation_job.cc | 29 | ||||
-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 | ||||
-rw-r--r-- | chrome/browser/renderer_host/resource_message_filter.cc | 162 | ||||
-rw-r--r-- | chrome/browser/renderer_host/resource_message_filter.h | 4 |
8 files changed, 402 insertions, 137 deletions
diff --git a/chrome/browser/automation/automation_profile_impl.cc b/chrome/browser/automation/automation_profile_impl.cc index 3a1387d..d09b036 100644 --- a/chrome/browser/automation/automation_profile_impl.cc +++ b/chrome/browser/automation/automation_profile_impl.cc @@ -58,8 +58,12 @@ class AutomationCookieStore : public net::CookieStore { } // CookieStore implementation. - virtual bool SetCookie(const GURL& url, const std::string& cookie_line) { - bool cookie_set = original_cookie_store_->SetCookie(url, cookie_line); + virtual bool SetCookieWithOptions(const GURL& url, + const std::string& cookie_line, + const net::CookieOptions& options) { + bool cookie_set = + original_cookie_store_->SetCookieWithOptions(url, cookie_line, + options); if (cookie_set) { // TODO(eroman): Should NOT be accessing the profile from here, as this // is running on the IO thread. @@ -68,48 +72,14 @@ class AutomationCookieStore : public net::CookieStore { } return cookie_set; } - virtual bool SetCookieWithOptions(const GURL& url, - const std::string& cookie_line, - const net::CookieOptions& options) { - return original_cookie_store_->SetCookieWithOptions(url, cookie_line, - options); - } - virtual bool SetCookieWithCreationTime(const GURL& url, - const std::string& cookie_line, - const base::Time& creation_time) { - return original_cookie_store_->SetCookieWithCreationTime(url, cookie_line, - creation_time); - } - virtual bool SetCookieWithCreationTimeWithOptions( - const GURL& url, - const std::string& cookie_line, - const base::Time& creation_time, - const net::CookieOptions& options) { - return original_cookie_store_->SetCookieWithCreationTimeWithOptions(url, - cookie_line, creation_time, options); - } - virtual void SetCookies(const GURL& url, - const std::vector<std::string>& cookies) { - original_cookie_store_->SetCookies(url, cookies); - } - virtual void SetCookiesWithOptions(const GURL& url, - const std::vector<std::string>& cookies, - const net::CookieOptions& options) { - original_cookie_store_->SetCookiesWithOptions(url, cookies, options); - } - virtual std::string GetCookies(const GURL& url) { - return original_cookie_store_->GetCookies(url); - } virtual std::string GetCookiesWithOptions(const GURL& url, const net::CookieOptions& options) { return original_cookie_store_->GetCookiesWithOptions(url, options); } - virtual void DeleteCookie(const GURL& url, const std::string& cookie_name) { return original_cookie_store_->DeleteCookie(url, cookie_name); } - virtual net::CookieMonster* GetCookieMonster() { return original_cookie_store_->GetCookieMonster(); } diff --git a/chrome/browser/automation/url_request_automation_job.cc b/chrome/browser/automation/url_request_automation_job.cc index 319b976..77e927f 100644 --- a/chrome/browser/automation/url_request_automation_job.cc +++ b/chrome/browser/automation/url_request_automation_job.cc @@ -13,7 +13,6 @@ #include "chrome/browser/renderer_host/resource_dispatcher_host_request_info.h" #include "chrome/test/automation/automation_messages.h" #include "net/base/cookie_monster.h" -#include "net/base/cookie_policy.h" #include "net/base/io_buffer.h" #include "net/base/net_errors.h" #include "net/http/http_util.h" @@ -298,6 +297,9 @@ void URLRequestAutomationJob::OnRequestStarted(int tab, int id, URLRequestContext* ctx = request_->context(); std::vector<std::string> response_cookies; + // NOTE: We ignore Chrome's cookie policy to allow the automation to + // decide what cookies should be set. + if (!response.headers.empty()) { headers_ = new net::HttpResponseHeaders( net::HttpUtil::AssembleRawHeaders(response.headers.data(), @@ -312,30 +314,23 @@ void URLRequestAutomationJob::OnRequestStarted(int tab, int id, response_cookies.push_back(value); } - if (response_cookies.size()) { - if (ctx && ctx->cookie_store() && (!ctx->cookie_policy() || - ctx->cookie_policy()->CanSetCookie( - url_for_cookies, request_->first_party_for_cookies()))) { - net::CookieOptions options; - options.set_include_httponly(); - ctx->cookie_store()->SetCookiesWithOptions(url_for_cookies, - response_cookies, - options); - } + if (response_cookies.size() && ctx && ctx->cookie_store()) { + net::CookieOptions options; + options.set_include_httponly(); + ctx->cookie_store()->SetCookiesWithOptions(url_for_cookies, + response_cookies, + options); } } - if (!response.persistent_cookies.empty() && ctx && ctx->cookie_store() && - (!ctx->cookie_policy() || ctx->cookie_policy()->CanSetCookie( - url_for_cookies, request_->first_party_for_cookies()))) { + if (!response.persistent_cookies.empty() && ctx && ctx->cookie_store()) { StringTokenizer cookie_parser(response.persistent_cookies, ";"); net::CookieMonster::CookieList existing_cookies; net::CookieMonster* monster = ctx->cookie_store()->GetCookieMonster(); DCHECK(monster); - if (monster) { - existing_cookies = monster->GetRawCookies(url_for_cookies); - } + if (monster) + existing_cookies = monster->GetAllCookiesForURL(url_for_cookies); while (cookie_parser.GetNext()) { std::string cookie_string = cookie_parser.token(); 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_; diff --git a/chrome/browser/renderer_host/resource_message_filter.cc b/chrome/browser/renderer_host/resource_message_filter.cc index 1bcb7a7..2861718 100644 --- a/chrome/browser/renderer_host/resource_message_filter.cc +++ b/chrome/browser/renderer_host/resource_message_filter.cc @@ -152,6 +152,99 @@ Blacklist::Match* GetPrivacyBlacklistMatchForURL( return blacklist->FindMatch(url); } +class SetCookieCompletion : public net::CompletionCallback { + public: + SetCookieCompletion(const GURL& url, const std::string& cookie_line, + URLRequestContext* context) + : url_(url), + cookie_line_(cookie_line), + context_(context) { + } + + virtual void RunWithParams(const Tuple1<int>& params) { + int result = params.a; + if (result == net::OK) + context_->cookie_store()->SetCookie(url_, cookie_line_); + delete this; + } + + private: + GURL url_; + std::string cookie_line_; + scoped_refptr<URLRequestContext> context_; +}; + +class GetCookiesCompletion : public net::CompletionCallback { + public: + GetCookiesCompletion(const GURL& url, IPC::Message* reply_msg, + ResourceMessageFilter* filter, + URLRequestContext* context) + : url_(url), + reply_msg_(reply_msg), + filter_(filter), + context_(context) { + } + + virtual void RunWithParams(const Tuple1<int>& params) { + int result = params.a; + std::string cookies; + if (result == net::OK) + cookies = context_->cookie_store()->GetCookies(url_); + ViewHostMsg_GetCookies::WriteReplyParams(reply_msg_, cookies); + filter_->Send(reply_msg_); + delete this; + } + + private: + GURL url_; + IPC::Message* reply_msg_; + scoped_refptr<ResourceMessageFilter> filter_; + scoped_refptr<URLRequestContext> context_; +}; + +class GetRawCookiesCompletion : public net::CompletionCallback { + public: + GetRawCookiesCompletion(const GURL& url, IPC::Message* reply_msg, + ResourceMessageFilter* filter, + URLRequestContext* context) + : url_(url), + reply_msg_(reply_msg), + filter_(filter), + context_(context) { + } + + virtual void RunWithParams(const Tuple1<int>& params) { + // Ignore the policy result. We only waited on the policy result so that + // any pending 'set-cookie' requests could be flushed. The intent of + // querying the raw cookies is to reveal the contents of the cookie DB, so + // it important that we don't read the cookie db ahead of pending writes. + + net::CookieMonster* cookie_monster = + context_->cookie_store()->GetCookieMonster(); + net::CookieMonster::CookieList cookie_list = + cookie_monster->GetAllCookiesForURL(url_); + + std::vector<webkit_glue::WebCookie> cookies; + for (size_t i = 0; i < cookie_list.size(); ++i) { + // TODO(darin): url.host() is not necessarily the domain of the cookie. + // We need a different API on CookieMonster to provide the domain info. + // See http://crbug.com/34315. + cookies.push_back( + webkit_glue::WebCookie(cookie_list[i].first, cookie_list[i].second)); + } + + ViewHostMsg_GetRawCookies::WriteReplyParams(reply_msg_, cookies); + filter_->Send(reply_msg_); + delete this; + } + + private: + GURL url_; + IPC::Message* reply_msg_; + scoped_refptr<ResourceMessageFilter> filter_; + scoped_refptr<URLRequestContext> context_; +}; + } // namespace ResourceMessageFilter::ResourceMessageFilter( @@ -302,8 +395,8 @@ bool ResourceMessageFilter::OnMessageReceived(const IPC::Message& msg) { IPC_MESSAGE_HANDLER(ViewHostMsg_CreateWindow, OnMsgCreateWindow) IPC_MESSAGE_HANDLER(ViewHostMsg_CreateWidget, OnMsgCreateWidget) IPC_MESSAGE_HANDLER(ViewHostMsg_SetCookie, OnSetCookie) - IPC_MESSAGE_HANDLER(ViewHostMsg_GetCookies, OnGetCookies) - IPC_MESSAGE_HANDLER(ViewHostMsg_GetRawCookies, OnGetRawCookies) + IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetCookies, OnGetCookies) + IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetRawCookies, OnGetRawCookies) IPC_MESSAGE_HANDLER(ViewHostMsg_DeleteCookie, OnDeleteCookie) IPC_MESSAGE_HANDLER(ViewHostMsg_GetCookiesEnabled, OnGetCookiesEnabled) #if defined(OS_WIN) // This hack is Windows-specific. @@ -483,58 +576,55 @@ void ResourceMessageFilter::OnSetCookie(const GURL& url, const std::string& cookie) { ChromeURLRequestContext* context = GetRequestContextForURL(url); - DCHECK(context->cookie_policy()); - if (!context->cookie_policy()->CanSetCookie(url, first_party_for_cookies)) - return; scoped_ptr<Blacklist::Match> match( GetPrivacyBlacklistMatchForURL(url, context)); if (match.get() && (match->attributes() & Blacklist::kBlockCookies)) return; - context->cookie_store()->SetCookie(url, cookie); + + SetCookieCompletion* callback = new SetCookieCompletion(url, cookie, context); + + DCHECK(context->cookie_policy()); + int policy = context->cookie_policy()->CanSetCookie( + url, first_party_for_cookies, cookie, callback); + if (policy == net::ERR_IO_PENDING) + return; + callback->Run(policy); } void ResourceMessageFilter::OnGetCookies(const GURL& url, const GURL& first_party_for_cookies, - std::string* cookies) { + IPC::Message* reply_msg) { URLRequestContext* context = GetRequestContextForURL(url); + + GetCookiesCompletion* callback = + new GetCookiesCompletion(url, reply_msg, this, context); + DCHECK(context->cookie_policy()); - if (context->cookie_policy()->CanGetCookies(url, first_party_for_cookies)) - *cookies = context->cookie_store()->GetCookies(url); + int policy = context->cookie_policy()->CanGetCookies( + url, first_party_for_cookies, callback); + if (policy == net::ERR_IO_PENDING) + return; + callback->Run(policy); } void ResourceMessageFilter::OnGetRawCookies( const GURL& url, const GURL& first_party_for_cookies, - std::vector<webkit_glue::WebCookie>* raw_cookies) { - raw_cookies->clear(); - + IPC::Message* reply_msg) { URLRequestContext* context = GetRequestContextForURL(url); - net::CookieMonster* cookie_monster = context->cookie_store()-> - GetCookieMonster(); - if (!cookie_monster) { - NOTREACHED(); - return; - } - if (!context->cookie_policy()->CanGetCookies(url, first_party_for_cookies)) - return; + GetRawCookiesCompletion* callback = + new GetRawCookiesCompletion(url, reply_msg, this, context); - typedef net::CookieMonster::CookieList CookieList; - CookieList cookieList = cookie_monster->GetRawCookies(url); - for (CookieList::iterator it = cookieList.begin(); - it != cookieList.end(); ++it) { - net::CookieMonster::CanonicalCookie& cookie = it->second; - raw_cookies->push_back( - webkit_glue::WebCookie( - cookie.Name(), - cookie.Value(), - it->first, - cookie.Path(), - cookie.ExpiryDate().ToDoubleT() * 1000, - cookie.IsHttpOnly(), - cookie.IsSecure(), - !cookie.IsPersistent())); - } + // We check policy here to avoid sending back cookies that would not normally + // be applied to outbound requests for the given URL. Since this cookie info + // is visible in the developer tools, it is helpful to make it match reality. + DCHECK(context->cookie_policy()); + int policy = context->cookie_policy()->CanGetCookies( + url, first_party_for_cookies, callback); + if (policy == net::ERR_IO_PENDING) + return; + callback->Run(policy); } void ResourceMessageFilter::OnDeleteCookie(const GURL& url, diff --git a/chrome/browser/renderer_host/resource_message_filter.h b/chrome/browser/renderer_host/resource_message_filter.h index 3931c83..e813ae1 100644 --- a/chrome/browser/renderer_host/resource_message_filter.h +++ b/chrome/browser/renderer_host/resource_message_filter.h @@ -133,10 +133,10 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter, const std::string& cookie); void OnGetCookies(const GURL& url, const GURL& first_party_for_cookies, - std::string* cookies); + IPC::Message* reply_msg); void OnGetRawCookies(const GURL& url, const GURL& first_party_for_cookies, - std::vector<webkit_glue::WebCookie>* raw_cookies); + IPC::Message* reply_msg); void OnDeleteCookie(const GURL& url, const std::string& cookieName); void OnGetCookiesEnabled(const GURL& url, |