From 45134197a411fd9e02986c9e11d7b6d876891f23 Mon Sep 17 00:00:00 2001 From: "darin@chromium.org" Date: Mon, 8 Feb 2010 21:10:55 +0000 Subject: Show an app modal dialog when the cookie policy is ASK. This hooks up the dialog for cookies and localstorage. It also includes support for remembering the decision, and in the case of cookies, support is added for forcing a cookie to be a stored as a session cookie. BUG=34625,34572 Review URL: http://codereview.chromium.org/583004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@38393 0039d316-1c4b-4281-b951-d872f2087c98 --- chrome/browser/net/chrome_cookie_policy.cc | 159 ++++++++++++++++++++++------- chrome/browser/net/chrome_cookie_policy.h | 29 +++++- 2 files changed, 150 insertions(+), 38 deletions(-) (limited to 'chrome/browser/net') diff --git a/chrome/browser/net/chrome_cookie_policy.cc b/chrome/browser/net/chrome_cookie_policy.cc index 3e924d1..a72d916 100644 --- a/chrome/browser/net/chrome_cookie_policy.cc +++ b/chrome/browser/net/chrome_cookie_policy.cc @@ -5,8 +5,11 @@ #include "chrome/browser/net/chrome_cookie_policy.h" #include "base/string_util.h" +#include "chrome/browser/browser_list.h" #include "chrome/browser/chrome_thread.h" +#include "chrome/browser/cookie_prompt_modal_dialog_delegate.h" #include "chrome/browser/host_content_settings_map.h" +#include "chrome/browser/message_box_handler.h" #include "googleurl/src/gurl.h" #include "net/base/net_errors.h" #include "net/base/static_cookie_policy.h" @@ -16,6 +19,40 @@ // sign of trouble anyways. static const size_t kMaxCompletionsPerHost = 10000; +// ---------------------------------------------------------------------------- + +class ChromeCookiePolicy::PromptDelegate + : public CookiePromptModalDialogDelegate { + public: + PromptDelegate(ChromeCookiePolicy* cookie_policy, const std::string& host) + : cookie_policy_(cookie_policy), + host_(host) { + } + + // CookiesPromptViewDelegate methods: + virtual void AllowSiteData(bool remember, bool session_expire); + virtual void BlockSiteData(bool remember); + + private: + scoped_refptr cookie_policy_; + std::string host_; +}; + +void ChromeCookiePolicy::PromptDelegate::AllowSiteData(bool remember, + bool session_expire) { + int policy = net::OK; + if (session_expire) + policy = net::OK_FOR_SESSION_ONLY; + cookie_policy_->DidPromptForSetCookie(host_, policy, remember); +} + +void ChromeCookiePolicy::PromptDelegate::BlockSiteData(bool remember) { + cookie_policy_->DidPromptForSetCookie(host_, net::ERR_ACCESS_DENIED, + remember); +} + +// ---------------------------------------------------------------------------- + ChromeCookiePolicy::ChromeCookiePolicy(HostContentSettingsMap* map) : host_content_settings_map_(map) { } @@ -27,6 +64,8 @@ ChromeCookiePolicy::~ChromeCookiePolicy() { int ChromeCookiePolicy::CanGetCookies(const GURL& url, const GURL& first_party, net::CompletionCallback* callback) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + if (host_content_settings_map_->BlockThirdPartyCookies()) { net::StaticCookiePolicy policy( net::StaticCookiePolicy::BLOCK_THIRD_PARTY_COOKIES); @@ -37,36 +76,33 @@ int ChromeCookiePolicy::CanGetCookies(const GURL& url, 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; + int policy = CheckPolicy(host); + if (policy != net::ERR_IO_PENDING) + return policy; 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) { + if (it == host_completions_map_.end()) { + policy = net::OK; + } else if (it->second.size() >= kMaxCompletionsPerHost) { LOG(ERROR) << "Would exceed kMaxCompletionsPerHost"; - return net::ERR_ACCESS_DENIED; + policy = net::ERR_ACCESS_DENIED; + } else { + it->second.push_back(Completion::ForGetCookies(callback)); + policy = net::ERR_IO_PENDING; } - - it->second.push_back(Completion::ForGetCookies(callback)); - - return net::ERR_IO_PENDING; + return policy; } int ChromeCookiePolicy::CanSetCookie(const GURL& url, const GURL& first_party, const std::string& cookie_line, net::CompletionCallback* callback) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + if (host_content_settings_map_->BlockThirdPartyCookies()) { net::StaticCookiePolicy policy( net::StaticCookiePolicy::BLOCK_THIRD_PARTY_COOKIES); @@ -77,12 +113,9 @@ int ChromeCookiePolicy::CanSetCookie(const GURL& url, 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; + int policy = CheckPolicy(host); + if (policy != net::ERR_IO_PENDING) + return policy; DCHECK(callback); @@ -92,13 +125,56 @@ int ChromeCookiePolicy::CanSetCookie(const GURL& url, if (completions.size() >= kMaxCompletionsPerHost) { LOG(ERROR) << "Would exceed kMaxCompletionsPerHost"; + policy = net::ERR_ACCESS_DENIED; + } else { + completions.push_back(Completion::ForSetCookie(callback)); + policy = net::ERR_IO_PENDING; + } + + PromptForSetCookie(host, cookie_line); + return policy; +} + +int ChromeCookiePolicy::CheckPolicy(const std::string& host) const { + 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; + return net::ERR_IO_PENDING; // Need to prompt. +} + +void ChromeCookiePolicy::ShowNextPrompt() { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + + if (prompt_queue_.empty()) + return; + PromptData data = prompt_queue_.front(); + + // The policy may have changed (due to the "remember" option). + int policy = CheckPolicy(data.host); + if (policy != net::ERR_IO_PENDING) { + DidPromptForSetCookie(data.host, policy, false); + return; } - completions.push_back(Completion::ForSetCookie(callback)); + // Show the prompt on top of the current tab. + Browser* browser = BrowserList::GetLastActive(); + if (!browser || !browser->GetSelectedTabContents()) { + DidPromptForSetCookie(data.host, net::ERR_ACCESS_DENIED, false); + return; + } - PromptForSetCookie(host, cookie_line); - return net::ERR_IO_PENDING; +#if defined(OS_WIN) + RunCookiePrompt(browser->GetSelectedTabContents(), + data.host, + data.cookie_line, + new PromptDelegate(this, data.host)); +#else + // TODO(darin): Enable prompting for other ports. + DidPromptForSetCookie(data.host, net::ERR_ACCESS_DENIED, false); +#endif } void ChromeCookiePolicy::PromptForSetCookie(const std::string &host, @@ -111,27 +187,38 @@ void ChromeCookiePolicy::PromptForSetCookie(const std::string &host, return; } - // TODO(darin): Prompt user! -#if 0 - MessageBox(NULL, - UTF8ToWide(cookie_line).c_str(), - UTF8ToWide(host).c_str(), - MB_OK); -#endif + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); - DidPromptForSetCookie(host, net::OK); + bool show_now = prompt_queue_.empty(); + prompt_queue_.push(PromptData(host, cookie_line)); + if (show_now) + ShowNextPrompt(); } void ChromeCookiePolicy::DidPromptForSetCookie(const std::string &host, - int result) { + int policy, bool remember) { if (!ChromeThread::CurrentlyOn(ChromeThread::IO)) { + // Process the remember flag immediately. + if (remember) { + ContentSetting content_setting = CONTENT_SETTING_BLOCK; + if (policy == net::OK || policy == net::OK_FOR_SESSION_ONLY) + content_setting = CONTENT_SETTING_ALLOW; + host_content_settings_map_->SetContentSetting( + host, CONTENT_SETTINGS_TYPE_COOKIES, content_setting); + } + ChromeThread::PostTask( ChromeThread::IO, FROM_HERE, NewRunnableMethod(this, &ChromeCookiePolicy::DidPromptForSetCookie, - host, result)); + host, policy, remember)); + + prompt_queue_.pop(); + ShowNextPrompt(); return; } + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + // 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); @@ -158,5 +245,5 @@ void ChromeCookiePolicy::DidPromptForSetCookie(const std::string &host, host_completions_map_.erase(it); for (size_t j = 0; j < callbacks.size(); ++j) - callbacks[j]->Run(result); + callbacks[j]->Run(policy); } diff --git a/chrome/browser/net/chrome_cookie_policy.h b/chrome/browser/net/chrome_cookie_policy.h index 0d536f8..6b4d675 100644 --- a/chrome/browser/net/chrome_cookie_policy.h +++ b/chrome/browser/net/chrome_cookie_policy.h @@ -6,6 +6,8 @@ #define CHROME_BROWSER_NET_CHROME_COOKIE_POLICY_H_ #include +#include +#include #include #include "base/ref_counted.h" @@ -35,6 +37,9 @@ class ChromeCookiePolicy net::CompletionCallback* callback); private: + class PromptDelegate; + friend class PromptDelegate; + class Completion { public: static Completion ForSetCookie(net::CompletionCallback* callback) { @@ -57,17 +62,37 @@ class ChromeCookiePolicy bool is_set_cookie_request_; net::CompletionCallback* callback_; }; - typedef std::vector Completions; typedef std::map HostCompletionsMap; + struct PromptData { + std::string host; + std::string cookie_line; + + PromptData(const std::string& host, const std::string& cookie_line) + : host(host), + cookie_line(cookie_line) { + } + }; + typedef std::queue PromptQueue; + + int CheckPolicy(const std::string& host) const; + void ShowNextPrompt(); void PromptForSetCookie(const std::string& host, const std::string& cookie_line); - void DidPromptForSetCookie(const std::string& host, int result); + void DidPromptForSetCookie(const std::string& host, int result, + bool remember); // A map from hostname to callbacks awaiting a cookie policy response. + // This map is only accessed on the IO thread. HostCompletionsMap host_completions_map_; + // A queue of pending prompts. We queue these up here so that before showing + // the next prompt we can reconsult the HostContentSettingsMap in case + // settings have changed since the prompt request was placed in the queue. + // This queue is only accessed on the UI thread. + PromptQueue prompt_queue_; + scoped_refptr host_content_settings_map_; }; -- cgit v1.1