blob: 5551642305c64c7e7ae487c4b0216f64bfc5136a [file] [log] [blame]
// Copyright (c) 2012 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/browsing_data/browsing_data_cookie_helper.h"
#include "utility"
#include "base/bind.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/stl_util.h"
#include "chrome/browser/profiles/profile.h"
#include "content/public/browser/browser_thread.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
#include "net/cookies/canonical_cookie.h"
#include "net/cookies/cookie_util.h"
#include "net/cookies/parsed_cookie.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"
#include "url/gurl.h"
using content::BrowserThread;
namespace {
const char kGlobalCookieListURL[] = "chrome://cookielist";
}
BrowsingDataCookieHelper::BrowsingDataCookieHelper(
net::URLRequestContextGetter* request_context_getter)
: is_fetching_(false),
request_context_getter_(request_context_getter) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
}
BrowsingDataCookieHelper::~BrowsingDataCookieHelper() {
}
void BrowsingDataCookieHelper::StartFetching(
const base::Callback<void(const net::CookieList& cookies)>& callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(!is_fetching_);
DCHECK(!callback.is_null());
DCHECK(completion_callback_.is_null());
is_fetching_ = true;
completion_callback_ = callback;
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&BrowsingDataCookieHelper::FetchCookiesOnIOThread, this));
}
void BrowsingDataCookieHelper::DeleteCookie(
const net::CanonicalCookie& cookie) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&BrowsingDataCookieHelper::DeleteCookieOnIOThread,
this, cookie));
}
void BrowsingDataCookieHelper::FetchCookiesOnIOThread() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
scoped_refptr<net::CookieMonster> cookie_monster =
request_context_getter_->GetURLRequestContext()->
cookie_store()->GetCookieMonster();
if (cookie_monster.get()) {
cookie_monster->GetAllCookiesAsync(
base::Bind(&BrowsingDataCookieHelper::OnFetchComplete, this));
} else {
OnFetchComplete(net::CookieList());
}
}
void BrowsingDataCookieHelper::OnFetchComplete(const net::CookieList& cookies) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&BrowsingDataCookieHelper::NotifyInUIThread, this, cookies));
}
void BrowsingDataCookieHelper::NotifyInUIThread(
const net::CookieList& cookies) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(is_fetching_);
is_fetching_ = false;
completion_callback_.Run(cookies);
completion_callback_.Reset();
}
void BrowsingDataCookieHelper::DeleteCookieOnIOThread(
const net::CanonicalCookie& cookie) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
scoped_refptr<net::CookieMonster> cookie_monster =
request_context_getter_->GetURLRequestContext()->
cookie_store()->GetCookieMonster();
if (cookie_monster.get()) {
cookie_monster->DeleteCanonicalCookieAsync(
cookie, net::CookieMonster::DeleteCookieCallback());
}
}
CannedBrowsingDataCookieHelper::CannedBrowsingDataCookieHelper(
net::URLRequestContextGetter* request_context_getter)
: BrowsingDataCookieHelper(request_context_getter) {
}
CannedBrowsingDataCookieHelper::~CannedBrowsingDataCookieHelper() {
Reset();
}
CannedBrowsingDataCookieHelper* CannedBrowsingDataCookieHelper::Clone() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
CannedBrowsingDataCookieHelper* clone =
new CannedBrowsingDataCookieHelper(request_context_getter());
for (OriginCookieListMap::iterator it = origin_cookie_list_map_.begin();
it != origin_cookie_list_map_.end();
++it) {
net::CookieList* cookies = clone->GetCookiesFor(it->first);
cookies->insert(cookies->begin(), it->second->begin(), it->second->end());
}
return clone;
}
void CannedBrowsingDataCookieHelper::AddReadCookies(
const GURL& frame_url,
const GURL& url,
const net::CookieList& cookie_list) {
typedef net::CookieList::const_iterator cookie_iterator;
for (cookie_iterator add_cookie = cookie_list.begin();
add_cookie != cookie_list.end(); ++add_cookie) {
AddCookie(frame_url, *add_cookie);
}
}
void CannedBrowsingDataCookieHelper::AddChangedCookie(
const GURL& frame_url,
const GURL& url,
const std::string& cookie_line,
const net::CookieOptions& options) {
scoped_ptr<net::CanonicalCookie> cookie(net::CanonicalCookie::Create(
url, cookie_line, base::Time::Now(), options));
if (cookie.get())
AddCookie(frame_url, *cookie);
}
void CannedBrowsingDataCookieHelper::Reset() {
STLDeleteContainerPairSecondPointers(origin_cookie_list_map_.begin(),
origin_cookie_list_map_.end());
origin_cookie_list_map_.clear();
}
bool CannedBrowsingDataCookieHelper::empty() const {
for (OriginCookieListMap::const_iterator it =
origin_cookie_list_map_.begin();
it != origin_cookie_list_map_.end();
++it) {
if (!it->second->empty())
return false;
}
return true;
}
size_t CannedBrowsingDataCookieHelper::GetCookieCount() const {
size_t count = 0;
for (OriginCookieListMap::const_iterator it = origin_cookie_list_map_.begin();
it != origin_cookie_list_map_.end();
++it) {
count += it->second->size();
}
return count;
}
void CannedBrowsingDataCookieHelper::StartFetching(
const net::CookieMonster::GetCookieListCallback& callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
net::CookieList cookie_list;
for (OriginCookieListMap::iterator it = origin_cookie_list_map_.begin();
it != origin_cookie_list_map_.end();
++it) {
cookie_list.insert(cookie_list.begin(),
it->second->begin(),
it->second->end());
}
callback.Run(cookie_list);
}
bool CannedBrowsingDataCookieHelper::DeleteMatchingCookie(
const net::CanonicalCookie& add_cookie,
net::CookieList* cookie_list) {
typedef net::CookieList::iterator cookie_iterator;
for (cookie_iterator cookie = cookie_list->begin();
cookie != cookie_list->end(); ++cookie) {
if (cookie->Name() == add_cookie.Name() &&
cookie->Domain() == add_cookie.Domain()&&
cookie->Path() == add_cookie.Path()) {
cookie_list->erase(cookie);
return true;
}
}
return false;
}
net::CookieList* CannedBrowsingDataCookieHelper::GetCookiesFor(
const GURL& first_party_origin) {
OriginCookieListMap::iterator it =
origin_cookie_list_map_.find(first_party_origin);
if (it == origin_cookie_list_map_.end()) {
net::CookieList* cookies = new net::CookieList();
origin_cookie_list_map_.insert(
std::pair<GURL, net::CookieList*>(first_party_origin, cookies));
return cookies;
}
return it->second;
}
void CannedBrowsingDataCookieHelper::AddCookie(
const GURL& frame_url,
const net::CanonicalCookie& cookie) {
// Storing cookies in separate cookie lists per frame origin makes the
// GetCookieCount method count a cookie multiple times if it is stored in
// multiple lists.
// E.g. let "example.com" be redirected to "www.example.com". A cookie set
// with the cookie string "A=B; Domain=.example.com" would be sent to both
// hosts. This means it would be stored in the separate cookie lists for both
// hosts ("example.com", "www.example.com"). The method GetCookieCount would
// count this cookie twice. To prevent this, we us a single global cookie
// list as a work-around to store all added cookies. Per frame URL cookie
// lists are currently not used. In the future they will be used for
// collecting cookies per origin in redirect chains.
// TODO(markusheintz): A) Change the GetCookiesCount method to prevent
// counting cookies multiple times if they are stored in multiple cookie
// lists. B) Replace the GetCookieFor method call below with:
// "GetCookiesFor(frame_url.GetOrigin());"
net::CookieList* cookie_list =
GetCookiesFor(GURL(kGlobalCookieListURL));
DeleteMatchingCookie(cookie, cookie_list);
cookie_list->push_back(cookie);
}