summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/base/cookie_monster.cc116
-rw-r--r--net/base/cookie_monster.h71
-rw-r--r--net/base/cookie_monster_perftest.cc1
-rw-r--r--net/base/cookie_monster_store_test.cc59
-rw-r--r--net/base/cookie_monster_store_test.h50
-rw-r--r--net/base/cookie_monster_unittest.cc88
6 files changed, 312 insertions, 73 deletions
diff --git a/net/base/cookie_monster.cc b/net/base/cookie_monster.cc
index 6afe739..3ee2d40 100644
--- a/net/base/cookie_monster.cc
+++ b/net/base/cookie_monster.cc
@@ -49,6 +49,7 @@
#include "base/basictypes.h"
#include "base/bind.h"
+#include "base/callback.h"
#include "base/format_macros.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
@@ -67,6 +68,26 @@ using base::Time;
using base::TimeDelta;
using base::TimeTicks;
+// In steady state, most cookie requests can be satisfied by the in memory
+// cookie monster store. However, if a request comes in during the initial
+// cookie load, it must be delayed until that load completes. That is done by
+// queueing it on CookieMonster::queue_ and running it when notification of
+// cookie load completion is received via CookieMonster::OnLoaded. This callback
+// is passed to the persistent store from CookieMonster::InitStore(), which is
+// called on the first operation invoked on the CookieMonster.
+//
+// On the browser critical paths (e.g. for loading initial web pages in a
+// session restore) it may take too long to wait for the full load. If a cookie
+// request is for a specific URL, DoCookieTaskForURL is called, which triggers a
+// priority load if the key is not loaded yet by calling PersistentCookieStore
+// :: LoadCookiesForKey. The request is queued in CookieMonster::tasks_queued
+// and executed upon receiving notification of key load completion via
+// CookieMonster::OnKeyLoaded(). If multiple requests for the same eTLD+1 are
+// received before key load completion, only the first request calls
+// PersistentCookieStore::LoadCookiesForKey, all subsequent requests are queued
+// in CookieMonster::tasks_queued and executed upon receiving notification of
+// key load completion triggered by the first request for the same eTLD+1.
+
static const int kMinutesInTenYears = 10 * 365 * 24 * 60;
namespace net {
@@ -993,7 +1014,7 @@ void CookieMonster::SetCookieWithDetailsAsync(
expiration_time, secure, http_only,
callback);
- DoCookieTask(task);
+ DoCookieTaskForURL(task, url);
}
void CookieMonster::GetAllCookiesAsync(const GetCookieListCallback& callback) {
@@ -1011,7 +1032,7 @@ void CookieMonster::GetAllCookiesForURLWithOptionsAsync(
scoped_refptr<GetAllCookiesForURLWithOptionsTask> task =
new GetAllCookiesForURLWithOptionsTask(this, url, options, callback);
- DoCookieTask(task);
+ DoCookieTaskForURL(task, url);
}
void CookieMonster::GetAllCookiesForURLAsync(
@@ -1021,7 +1042,7 @@ void CookieMonster::GetAllCookiesForURLAsync(
scoped_refptr<GetAllCookiesForURLWithOptionsTask> task =
new GetAllCookiesForURLWithOptionsTask(this, url, options, callback);
- DoCookieTask(task);
+ DoCookieTaskForURL(task, url);
}
void CookieMonster::DeleteAllAsync(const DeleteCallback& callback) {
@@ -1046,7 +1067,7 @@ void CookieMonster::DeleteAllForHostAsync(
scoped_refptr<DeleteAllForHostTask> task =
new DeleteAllForHostTask(this, url, callback);
- DoCookieTask(task);
+ DoCookieTaskForURL(task, url);
}
void CookieMonster::DeleteCanonicalCookieAsync(
@@ -1066,7 +1087,7 @@ void CookieMonster::SetCookieWithOptionsAsync(
scoped_refptr<SetCookieWithOptionsTask> task =
new SetCookieWithOptionsTask(this, url, cookie_line, options, callback);
- DoCookieTask(task);
+ DoCookieTaskForURL(task, url);
}
void CookieMonster::GetCookiesWithOptionsAsync(
@@ -1076,7 +1097,7 @@ void CookieMonster::GetCookiesWithOptionsAsync(
scoped_refptr<GetCookiesWithOptionsTask> task =
new GetCookiesWithOptionsTask(this, url, options, callback);
- DoCookieTask(task);
+ DoCookieTaskForURL(task, url);
}
void CookieMonster::GetCookiesWithInfoAsync(
@@ -1086,7 +1107,7 @@ void CookieMonster::GetCookiesWithInfoAsync(
scoped_refptr<GetCookiesWithInfoTask> task =
new GetCookiesWithInfoTask(this, url, options, callback);
- DoCookieTask(task);
+ DoCookieTaskForURL(task, url);
}
void CookieMonster::DeleteCookieAsync(const GURL& url,
@@ -1095,15 +1116,14 @@ void CookieMonster::DeleteCookieAsync(const GURL& url,
scoped_refptr<DeleteCookieTask> task =
new DeleteCookieTask(this, url, cookie_name, callback);
- DoCookieTask(task);
+ DoCookieTaskForURL(task, url);
}
void CookieMonster::DoCookieTask(
const scoped_refptr<CookieMonsterTask>& task_item) {
- InitIfNecessary();
-
{
base::AutoLock autolock(lock_);
+ InitIfNecessary();
if (!loaded_) {
queue_.push(task_item);
return;
@@ -1113,6 +1133,34 @@ void CookieMonster::DoCookieTask(
task_item->Run();
}
+void CookieMonster::DoCookieTaskForURL(
+ const scoped_refptr<CookieMonsterTask>& task_item,
+ const GURL& url) {
+ {
+ base::AutoLock autolock(lock_);
+ InitIfNecessary();
+ // If cookies for the requested domain key (eTLD+1) have been loaded from DB
+ // then run the task, otherwise load from DB.
+ if (!loaded_) {
+ // Checks if the domain key has been loaded.
+ std::string key(GetEffectiveDomain(url.scheme(), url.host()));
+ if (keys_loaded_.find(key) == keys_loaded_.end()) {
+ std::map<std::string, std::deque<scoped_refptr<CookieMonsterTask> > >
+ ::iterator it = tasks_queued_.find(key);
+ if (it == tasks_queued_.end()) {
+ store_->LoadCookiesForKey(key,
+ base::Bind(&CookieMonster::OnKeyLoaded, this, key));
+ it = tasks_queued_.insert(std::make_pair(key,
+ std::deque<scoped_refptr<CookieMonsterTask> >())).first;
+ }
+ it->second.push_back(task_item);
+ return;
+ }
+ }
+ }
+ task_item->Run();
+}
+
bool CookieMonster::SetCookieWithDetails(
const GURL& url, const std::string& name, const std::string& value,
const std::string& domain, const std::string& path,
@@ -1470,6 +1518,30 @@ void CookieMonster::OnLoaded(TimeTicks beginning_time,
InvokeQueue();
}
+void CookieMonster::OnKeyLoaded(const std::string& key,
+ const std::vector<CanonicalCookie*>& cookies) {
+ // This function does its own separate locking.
+ StoreLoadedCookies(cookies);
+
+ std::deque<scoped_refptr<CookieMonsterTask> > tasks_queued;
+ {
+ base::AutoLock autolock(lock_);
+ keys_loaded_.insert(key);
+ std::map<std::string, std::deque<scoped_refptr<CookieMonsterTask> > >
+ ::iterator it = tasks_queued_.find(key);
+ if (it == tasks_queued_.end())
+ return;
+ it->second.swap(tasks_queued);
+ tasks_queued_.erase(it);
+ }
+
+ while (!tasks_queued.empty()) {
+ scoped_refptr<CookieMonsterTask> task = tasks_queued.front();
+ task->Run();
+ tasks_queued.pop_front();
+ }
+}
+
void CookieMonster::StoreLoadedCookies(
const std::vector<CanonicalCookie*>& cookies) {
// Initialize the store and sync in any saved persistent cookies. We don't
@@ -1477,24 +1549,16 @@ void CookieMonster::StoreLoadedCookies(
// and sync'd.
base::AutoLock autolock(lock_);
- // Avoid ever letting cookies with duplicate creation times into the store;
- // that way we don't have to worry about what sections of code are safe
- // to call while it's in that state.
- std::set<int64> creation_times;
-
- // Presumably later than any access time in the store.
- Time earliest_access_time;
-
for (std::vector<CanonicalCookie*>::const_iterator it = cookies.begin();
it != cookies.end(); ++it) {
int64 cookie_creation_time = (*it)->CreationDate().ToInternalValue();
- if (creation_times.insert(cookie_creation_time).second) {
+ if (creation_times_.insert(cookie_creation_time).second) {
InternalInsertCookie(GetKey((*it)->Domain()), *it, false);
const Time cookie_access_time((*it)->LastAccessDate());
- if (earliest_access_time.is_null() ||
- cookie_access_time < earliest_access_time)
- earliest_access_time = cookie_access_time;
+ if (earliest_access_time_.is_null() ||
+ cookie_access_time < earliest_access_time_)
+ earliest_access_time_ = cookie_access_time;
} else {
LOG(ERROR) << base::StringPrintf("Found cookies with duplicate creation "
"times in backing store: "
@@ -1507,12 +1571,14 @@ void CookieMonster::StoreLoadedCookies(
delete (*it);
}
}
- earliest_access_time_= earliest_access_time;
// After importing cookies from the PersistentCookieStore, verify that
// none of our other constraints are violated.
- //
// In particular, the backing store might have given us duplicate cookies.
+
+ // This method could be called multiple times due to priority loading, thus
+ // cookies loaded in previous runs will be validated again, but this is OK
+ // since they are expected to be much fewer than total DB.
EnsureCookiesMapIsValid();
}
@@ -1523,6 +1589,8 @@ void CookieMonster::InvokeQueue() {
base::AutoLock autolock(lock_);
if (queue_.empty()) {
loaded_ = true;
+ creation_times_.clear();
+ keys_loaded_.clear();
break;
}
request_task = queue_.front();
diff --git a/net/base/cookie_monster.h b/net/base/cookie_monster.h
index 44fbc6d..9dea152 100644
--- a/net/base/cookie_monster.h
+++ b/net/base/cookie_monster.h
@@ -8,13 +8,16 @@
#define NET_BASE_COOKIE_MONSTER_H_
#pragma once
+#include <deque>
#include <map>
#include <queue>
+#include <set>
#include <string>
#include <utility>
#include <vector>
#include "base/basictypes.h"
+#include "base/callback.h"
#include "base/gtest_prod_util.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
@@ -29,7 +32,7 @@ class GURL;
namespace base {
class Histogram;
class TimeTicks;
-}
+} // namespace base
namespace net {
@@ -43,11 +46,18 @@ class CookieList;
// This class IS thread-safe. Normally, it is only used on the I/O thread, but
// is also accessed directly through Automation for UI testing.
//
-// Several methods exist in asynchronous forms. Calls may be deferred if all
-// affected cookies are not yet loaded from the backing store. Otherwise, the
-// callback may be invoked immediately (prior to return of the asynchronous
+// All cookie tasks are handled asynchronously. Tasks may be deferred if
+// all affected cookies are not yet loaded from the backing store. Otherwise,
+// the callback may be invoked immediately (prior to return of the asynchronous
// function).
//
+// A cookie task is either pending loading of the entire cookie store, or
+// loading of cookies for a specfic domain key(eTLD+1). In the former case, the
+// cookie task will be queued in queue_ while PersistentCookieStore chain loads
+// the cookie store on DB thread. In the latter case, the cookie task will be
+// queued in tasks_queued_ while PermanentCookieStore loads cookies for the
+// specified domain key(eTLD+1) on DB thread.
+//
// Callbacks are guaranteed to be invoked on the calling thread.
//
// TODO(deanm) Implement CookieMonster, the cookie database.
@@ -450,9 +460,19 @@ class NET_EXPORT CookieMonster : public CookieStore {
// Stores cookies loaded from the backing store and invokes any deferred
// calls. |beginning_time| should be the moment PersistentCookieStore::Load
// was invoked and is used for reporting histogram_time_load_.
+ // See PersistentCookieStore::Load for details on the contents of cookies.
void OnLoaded(base::TimeTicks beginning_time,
const std::vector<CanonicalCookie*>& cookies);
+ // Stores cookies loaded from the backing store and invokes the deferred
+ // task(s) pending loading of cookies associated with the domain key
+ // (eTLD+1). Called when all cookies for the domain key(eTLD+1) have been
+ // loaded from DB. See PersistentCookieStore::Load for details on the contents
+ // of cookies.
+ void OnKeyLoaded(
+ const std::string& key,
+ const std::vector<CanonicalCookie*>& cookies);
+
// Stores the loaded cookies.
void StoreLoadedCookies(const std::vector<CanonicalCookie*>& cookies);
@@ -568,10 +588,15 @@ class NET_EXPORT CookieMonster : public CookieStore {
// ugly and increment when we've seen the same time twice.
base::Time CurrentTime();
- // Run the cookie request task if cookie loaded, otherwise added the task
- // to task queue.
+ // Runs the task if, or defers the task until, the full cookie database is
+ // loaded.
void DoCookieTask(const scoped_refptr<CookieMonsterTask>& task_item);
+ // Runs the task if, or defers the task until, the cookies for the given URL
+ // are loaded.
+ void DoCookieTaskForURL(const scoped_refptr<CookieMonsterTask>& task_item,
+ const GURL& url);
+
// Histogram variables; see CookieMonster::InitializeHistograms() in
// cookie_monster.cc for details.
base::Histogram* histogram_expiration_duration_minutes_;
@@ -597,8 +622,17 @@ class NET_EXPORT CookieMonster : public CookieStore {
// calls may be immediately processed.
bool loaded_;
- // Queues calls to CookieMonster until loading from the backend store is
- // completed.
+ // List of domain keys that have been loaded from the DB.
+ std::set<std::string> keys_loaded_;
+
+ // Map of domain keys to their associated task queues. These tasks are blocked
+ // until all cookies for the associated domain key eTLD+1 are loaded from the
+ // backend store.
+ std::map<std::string, std::deque<scoped_refptr<CookieMonsterTask> > >
+ tasks_queued_;
+
+ // Queues tasks that are blocked until all cookies are loaded from the backend
+ // store.
std::queue<scoped_refptr<CookieMonsterTask> > queue_;
// Indicates whether this cookie monster uses the new effective domain
@@ -620,10 +654,16 @@ class NET_EXPORT CookieMonster : public CookieStore {
// This value is used to determine whether global garbage collection might
// find cookies to purge.
// Note: The default Time() constructor will create a value that compares
- // earlier than any other time value, which is is wanted. Thus this
+ // earlier than any other time value, which is wanted. Thus this
// value is not initialized.
base::Time earliest_access_time_;
+ // During loading, holds the set of all loaded cookie creation times. Used to
+ // avoid ever letting cookies with duplicate creation times into the store;
+ // that way we don't have to worry about what sections of code are safe
+ // to call while it's in that state.
+ std::set<int64> creation_times_;
+
std::vector<std::string> cookieable_schemes_;
scoped_refptr<Delegate> delegate_;
@@ -919,8 +959,17 @@ class CookieMonster::PersistentCookieStore
CookieMonster::CanonicalCookie*>&)> LoadedCallback;
// Initializes the store and retrieves the existing cookies. This will be
- // called only once at startup.
- virtual bool Load(const LoadedCallback& loaded_callback) = 0;
+ // called only once at startup. The callback will return all the cookies
+ // that are not yet returned to CookieMonster by previous priority loads.
+ virtual void Load(const LoadedCallback& loaded_callback) = 0;
+
+ // Does a priority load of all cookies for the domain key (eTLD+1). The
+ // callback will return all the cookies that are not yet returned by previous
+ // loads, which includes cookies for the requested domain key if they are not
+ // already returned, plus all cookies that are chain-loaded and not yet
+ // returned to CookieMonster.
+ virtual void LoadCookiesForKey(const std::string& key,
+ const LoadedCallback& loaded_callback) = 0;
virtual void AddCookie(const CanonicalCookie& cc) = 0;
virtual void UpdateCookieAccessTime(const CanonicalCookie& cc) = 0;
diff --git a/net/base/cookie_monster_perftest.cc b/net/base/cookie_monster_perftest.cc
index 98a2b5b..a425138 100644
--- a/net/base/cookie_monster_perftest.cc
+++ b/net/base/cookie_monster_perftest.cc
@@ -63,6 +63,7 @@ class BaseCallback {
// Therefore, callbacks will actually always complete synchronously. If the
// tests get more advanced we need to add other means of signaling
// completion.
+ MessageLoop::current()->RunAllPending();
EXPECT_TRUE(has_run_);
has_run_ = false;
}
diff --git a/net/base/cookie_monster_store_test.cc b/net/base/cookie_monster_store_test.cc
index f8257c3..dc1b495 100644
--- a/net/base/cookie_monster_store_test.cc
+++ b/net/base/cookie_monster_store_test.cc
@@ -4,6 +4,7 @@
#include "net/base/cookie_monster_store_test.h"
+#include "base/bind.h"
#include "base/message_loop.h"
#include "base/stringprintf.h"
#include "base/time.h"
@@ -11,9 +12,17 @@
#include "testing/gtest/include/gtest/gtest.h"
namespace net {
+LoadedCallbackTask::LoadedCallbackTask(LoadedCallback loaded_callback,
+ std::vector<CookieMonster::CanonicalCookie*> cookies)
+ : loaded_callback_(loaded_callback),
+ cookies_(cookies) {
+}
+
+LoadedCallbackTask::~LoadedCallbackTask() {}
MockPersistentCookieStore::MockPersistentCookieStore()
- : load_return_value_(true) {
+ : load_return_value_(true),
+ loaded_(false) {
}
MockPersistentCookieStore::~MockPersistentCookieStore() {}
@@ -25,14 +34,27 @@ void MockPersistentCookieStore::SetLoadExpectation(
load_result_ = result;
}
-bool MockPersistentCookieStore::Load(const LoadedCallback& loaded_callback) {
- bool ok = load_return_value_;
+void MockPersistentCookieStore::Load(const LoadedCallback& loaded_callback) {
std::vector<CookieMonster::CanonicalCookie*> out_cookies;
- if (ok) {
+ if (load_return_value_) {
out_cookies = load_result_;
+ loaded_ = true;
+ }
+ MessageLoop::current()->PostTask(FROM_HERE,
+ base::Bind(&LoadedCallbackTask::Run,
+ new LoadedCallbackTask(loaded_callback, out_cookies)));
+}
+
+void MockPersistentCookieStore::LoadCookiesForKey(const std::string& key,
+ const LoadedCallback& loaded_callback) {
+ if (!loaded_) {
+ Load(loaded_callback);
+ } else {
+ MessageLoop::current()->PostTask(FROM_HERE,
+ base::Bind(&LoadedCallbackTask::Run,
+ new LoadedCallbackTask(loaded_callback,
+ std::vector<CookieMonster::CanonicalCookie*>())));
}
- loaded_callback.Run(out_cookies);
- return ok;
}
void MockPersistentCookieStore::AddCookie(
@@ -113,19 +135,36 @@ CookieMonster::CanonicalCookie BuildCanonicalCookie(
!cookie_expires.is_null());
}
-MockSimplePersistentCookieStore::MockSimplePersistentCookieStore() {}
+MockSimplePersistentCookieStore::MockSimplePersistentCookieStore()
+ : loaded_(false) {}
MockSimplePersistentCookieStore::~MockSimplePersistentCookieStore() {}
-bool MockSimplePersistentCookieStore::Load(
+void MockSimplePersistentCookieStore::Load(
const LoadedCallback& loaded_callback) {
std::vector<CookieMonster::CanonicalCookie*> out_cookies;
+
for (CanonicalCookieMap::const_iterator it = cookies_.begin();
it != cookies_.end(); it++)
out_cookies.push_back(
new CookieMonster::CanonicalCookie(it->second));
- loaded_callback.Run(out_cookies);
- return true;
+
+ MessageLoop::current()->PostTask(FROM_HERE,
+ base::Bind(&LoadedCallbackTask::Run,
+ new LoadedCallbackTask(loaded_callback, out_cookies)));
+ loaded_ = true;
+}
+
+void MockSimplePersistentCookieStore::LoadCookiesForKey(const std::string& key,
+ const LoadedCallback& loaded_callback) {
+ if (!loaded_) {
+ Load(loaded_callback);
+ } else {
+ MessageLoop::current()->PostTask(FROM_HERE,
+ base::Bind(&LoadedCallbackTask::Run,
+ new LoadedCallbackTask(loaded_callback,
+ std::vector<CookieMonster::CanonicalCookie*>())));
+ }
}
void MockSimplePersistentCookieStore::AddCookie(
diff --git a/net/base/cookie_monster_store_test.h b/net/base/cookie_monster_store_test.h
index 4bae6f9..658e9e8 100644
--- a/net/base/cookie_monster_store_test.h
+++ b/net/base/cookie_monster_store_test.h
@@ -23,6 +23,29 @@ class Time;
namespace net {
+// Wrapper class for posting a loaded callback. Since the Callback class is not
+// reference counted, we cannot post a callback to the message loop directly,
+// instead we post a LoadedCallbackTask.
+class LoadedCallbackTask
+ : public base::RefCountedThreadSafe<LoadedCallbackTask> {
+ public:
+ typedef CookieMonster::PersistentCookieStore::LoadedCallback LoadedCallback;
+
+ LoadedCallbackTask(LoadedCallback loaded_callback,
+ std::vector<CookieMonster::CanonicalCookie*> cookies);
+ ~LoadedCallbackTask();
+
+ void Run() {
+ loaded_callback_.Run(cookies_);
+ }
+
+ private:
+ LoadedCallback loaded_callback_;
+ std::vector<CookieMonster::CanonicalCookie*> cookies_;
+
+ DISALLOW_COPY_AND_ASSIGN(LoadedCallbackTask);
+}; // Wrapper class LoadedCallbackTask
+
// Describes a call to one of the 3 functions of PersistentCookieStore.
struct CookieStoreCommand {
enum Type {
@@ -59,7 +82,10 @@ class MockPersistentCookieStore
return commands_;
}
- virtual bool Load(const LoadedCallback& loaded_callback) OVERRIDE;
+ virtual void Load(const LoadedCallback& loaded_callback) OVERRIDE;
+
+ virtual void LoadCookiesForKey(const std::string& key,
+ const LoadedCallback& loaded_callback) OVERRIDE;
virtual void AddCookie(const CookieMonster::CanonicalCookie& cookie) OVERRIDE;
@@ -80,6 +106,9 @@ class MockPersistentCookieStore
// Deferred result to use when Load() is called.
bool load_return_value_;
std::vector<CookieMonster::CanonicalCookie*> load_result_;
+ // Indicates if the store has been fully loaded to avoid returning duplicate
+ // cookies.
+ bool loaded_;
DISALLOW_COPY_AND_ASSIGN(MockPersistentCookieStore);
};
@@ -130,26 +159,33 @@ class MockSimplePersistentCookieStore
MockSimplePersistentCookieStore();
virtual ~MockSimplePersistentCookieStore();
- virtual bool Load(const LoadedCallback& loaded_callback);
+ virtual void Load(const LoadedCallback& loaded_callback) OVERRIDE;
+
+ virtual void LoadCookiesForKey(const std::string& key,
+ const LoadedCallback& loaded_callback) OVERRIDE;
virtual void AddCookie(
- const CookieMonster::CanonicalCookie& cookie);
+ const CookieMonster::CanonicalCookie& cookie) OVERRIDE;
virtual void UpdateCookieAccessTime(
- const CookieMonster::CanonicalCookie& cookie);
+ const CookieMonster::CanonicalCookie& cookie) OVERRIDE;
virtual void DeleteCookie(
- const CookieMonster::CanonicalCookie& cookie);
+ const CookieMonster::CanonicalCookie& cookie) OVERRIDE;
- virtual void Flush(Task* completion_task);
+ virtual void Flush(Task* completion_task) OVERRIDE;
- virtual void SetClearLocalStateOnExit(bool clear_local_state);
+ virtual void SetClearLocalStateOnExit(bool clear_local_state) OVERRIDE;
private:
typedef std::map<int64, CookieMonster::CanonicalCookie>
CanonicalCookieMap;
CanonicalCookieMap cookies_;
+
+ // Indicates if the store has been fully loaded to avoid return duplicate
+ // cookies in subsequent load requests
+ bool loaded_;
};
// Helper function for creating a CookieMonster backed by a
diff --git a/net/base/cookie_monster_unittest.cc b/net/base/cookie_monster_unittest.cc
index fac72f8..7b53397 100644
--- a/net/base/cookie_monster_unittest.cc
+++ b/net/base/cookie_monster_unittest.cc
@@ -37,7 +37,9 @@ namespace {
class NewMockPersistentCookieStore
: public CookieMonster::PersistentCookieStore {
public:
- MOCK_METHOD1(Load, bool(const LoadedCallback& loaded_callback));
+ MOCK_METHOD1(Load, void(const LoadedCallback& loaded_callback));
+ MOCK_METHOD2(LoadCookiesForKey, void(const std::string& key,
+ const LoadedCallback& loaded_callback));
MOCK_METHOD1(AddCookie, void(const CookieMonster::CanonicalCookie& cc));
MOCK_METHOD1(UpdateCookieAccessTime,
void(const CookieMonster::CanonicalCookie& cc));
@@ -1008,12 +1010,16 @@ ACTION_P3(GetAllCookiesForUrlAction, cookie_monster, url, callback) {
cookie_monster->GetAllCookiesForURLAsync(url, callback->AsCallback());
}
+ACTION_P(PushCallbackAction, callback_vector) {
+ callback_vector->push(arg1);
+}
} // namespace
// This test suite verifies the task deferral behaviour of the CookieMonster.
// Specifically, for each asynchronous method, verify that:
// 1. invoking it on an uninitialized cookie store causes the store to begin
-// loading its backing data.
+// chain-loading its backing data or loading data for a specific domain key
+// (eTLD+1).
// 2. The initial invocation does not complete until the loading completes.
// 3. Invocations after the loading has completed complete immediately.
class DeferredCookieTaskTest : public CookieMonsterTest {
@@ -1039,9 +1045,16 @@ class DeferredCookieTaskTest : public CookieMonsterTest {
testing::Mock::VerifyAndClear(persistent_store_.get());
}
- // Invokes the PersistentCookieStore::Load completion callback and waits
+ // Invokes the PersistentCookieStore::LoadCookiesForKey completion callbacks
+ // and PersistentCookieStore::Load completion callback and waits
// until the message loop is quit.
void CompleteLoadingAndWait() {
+ while (!loaded_for_key_callbacks_.empty()) {
+ loaded_for_key_callbacks_.front().Run(loaded_cookies_);
+ loaded_cookies_.clear();
+ loaded_for_key_callbacks_.pop();
+ }
+
loaded_callback_.Run(loaded_cookies_);
RunFor(kTimeout);
}
@@ -1055,13 +1068,34 @@ class DeferredCookieTaskTest : public CookieMonsterTest {
Begin();
}
+ void BeginWithForDomainKey(std::string key,
+ testing::Action<void(void)> action) {
+ EXPECT_CALL(*this, Begin()).WillOnce(action);
+ ExpectLoadCall();
+ ExpectLoadForKeyCall(key, false);
+ Begin();
+ }
+
// Declares an expectation that PersistentCookieStore::Load will be called,
// saving the provided callback and sending a quit to the message loop.
void ExpectLoadCall() {
EXPECT_CALL(*persistent_store_, Load(testing::_)).WillOnce(testing::DoAll(
testing::SaveArg<0>(&loaded_callback_),
- QuitCurrentMessageLoop(),
- testing::Return(true)));
+ QuitCurrentMessageLoop()));
+ }
+
+ // Declares an expectation that PersistentCookieStore::LoadCookiesForKey
+ // will be called, saving the provided callback and sending a quit to the
+ // message loop.
+ void ExpectLoadForKeyCall(std::string key, bool quit_queue) {
+ if (quit_queue)
+ EXPECT_CALL(*persistent_store_, LoadCookiesForKey(key, testing::_)).
+ WillOnce(testing::DoAll(
+ PushCallbackAction(&loaded_for_key_callbacks_),
+ QuitCurrentMessageLoop()));
+ else
+ EXPECT_CALL(*persistent_store_, LoadCookiesForKey(key, testing::_)).
+ WillOnce(PushCallbackAction(&loaded_for_key_callbacks_));
}
// Invokes the initial action.
@@ -1073,11 +1107,17 @@ class DeferredCookieTaskTest : public CookieMonsterTest {
private:
// Declares that mock expectations in this test suite are strictly ordered.
testing::InSequence in_sequence_;
- // Holds cookies to be returned from PersistentCookieStore::Load.
+ // Holds cookies to be returned from PersistentCookieStore::Load or
+ // PersistentCookieStore::LoadCookiesForKey.
std::vector<CookieMonster::CanonicalCookie*> loaded_cookies_;
// Stores the callback passed from the CookieMonster to the
- // PersistentCookieStore
+ // PersistentCookieStore::Load
CookieMonster::PersistentCookieStore::LoadedCallback loaded_callback_;
+ // Stores the callback passed from the CookieMonster to the
+ // PersistentCookieStore::LoadCookiesForKey
+ std::queue<CookieMonster::PersistentCookieStore::LoadedCallback>
+ loaded_for_key_callbacks_;
+
// Stores the CookieMonster under test.
scoped_refptr<CookieMonster> cookie_monster_;
// Stores the mock PersistentCookieStore.
@@ -1091,7 +1131,7 @@ TEST_F(DeferredCookieTaskTest, DeferredGetCookies) {
MockGetCookiesCallback get_cookies_callback;
- BeginWith(GetCookiesAction(
+ BeginWithForDomainKey("google.izzle", GetCookiesAction(
&cookie_monster(), url_google_, &get_cookies_callback));
WaitForLoadCall();
@@ -1111,7 +1151,7 @@ TEST_F(DeferredCookieTaskTest, DeferredGetCookiesWithInfo) {
MockGetCookieInfoCallback get_cookie_info_callback;
- BeginWith(GetCookiesWithInfoAction(
+ BeginWithForDomainKey("google.izzle", GetCookiesWithInfoAction(
&cookie_monster(), url_google_, &get_cookie_info_callback));
WaitForLoadCall();
@@ -1128,7 +1168,7 @@ TEST_F(DeferredCookieTaskTest, DeferredGetCookiesWithInfo) {
TEST_F(DeferredCookieTaskTest, DeferredSetCookie) {
MockSetCookiesCallback set_cookies_callback;
- BeginWith(SetCookieAction(
+ BeginWithForDomainKey("google.izzle", SetCookieAction(
&cookie_monster(), url_google_, "A=B", &set_cookies_callback));
WaitForLoadCall();
@@ -1145,7 +1185,7 @@ TEST_F(DeferredCookieTaskTest, DeferredSetCookie) {
TEST_F(DeferredCookieTaskTest, DeferredDeleteCookie) {
MockClosure delete_cookie_callback;
- BeginWith(DeleteCookieAction(
+ BeginWithForDomainKey("google.izzle", DeleteCookieAction(
&cookie_monster(), url_google_, "A", &delete_cookie_callback));
WaitForLoadCall();
@@ -1162,7 +1202,7 @@ TEST_F(DeferredCookieTaskTest, DeferredDeleteCookie) {
TEST_F(DeferredCookieTaskTest, DeferredSetCookieWithDetails) {
MockSetCookiesCallback set_cookies_callback;
- BeginWith(SetCookieWithDetailsAction(
+ BeginWithForDomainKey("google.izzle", SetCookieWithDetailsAction(
&cookie_monster(), url_google_foo_, "A", "B", std::string(), "/foo",
base::Time(), false, false, &set_cookies_callback));
@@ -1205,7 +1245,7 @@ TEST_F(DeferredCookieTaskTest, DeferredGetAllForUrlCookies) {
MockGetCookieListCallback get_cookie_list_callback;
- BeginWith(GetAllCookiesForUrlAction(
+ BeginWithForDomainKey("google.izzle", GetAllCookiesForUrlAction(
&cookie_monster(), url_google_, &get_cookie_list_callback));
WaitForLoadCall();
@@ -1227,7 +1267,7 @@ TEST_F(DeferredCookieTaskTest, DeferredGetAllForUrlWithOptionsCookies) {
MockGetCookieListCallback get_cookie_list_callback;
- BeginWith(GetAllCookiesForUrlWithOptionsAction(
+ BeginWithForDomainKey("google.izzle", GetAllCookiesForUrlWithOptionsAction(
&cookie_monster(), url_google_, &get_cookie_list_callback));
WaitForLoadCall();
@@ -1278,7 +1318,7 @@ TEST_F(DeferredCookieTaskTest, DeferredDeleteAllCreatedBetweenCookies) {
TEST_F(DeferredCookieTaskTest, DeferredDeleteAllForHostCookies) {
MockDeleteCallback delete_callback;
- BeginWith(DeleteAllForHostAction(
+ BeginWithForDomainKey("google.izzle", DeleteAllForHostAction(
&cookie_monster(), url_google_, &delete_callback));
WaitForLoadCall();
@@ -1334,17 +1374,17 @@ TEST_F(DeferredCookieTaskTest, DeferredTaskOrder) {
DeleteCookieAction(
&cookie_monster(), url_google_, "A", &delete_cookie_callback)));
ExpectLoadCall();
+ ExpectLoadForKeyCall("google.izzle", false);
Begin();
WaitForLoadCall();
EXPECT_CALL(get_cookies_callback, Invoke("X=1")).WillOnce(
GetCookiesWithInfoAction(
&cookie_monster(), url_google_, &get_cookie_info_callback));
-
- EXPECT_CALL(set_cookies_callback, Invoke(true));
- EXPECT_CALL(delete_cookie_callback, Invoke());
EXPECT_CALL(get_cookie_info_callback, Invoke("X=1", testing::_)).WillOnce(
QuitCurrentMessageLoop());
+ EXPECT_CALL(set_cookies_callback, Invoke(true));
+ EXPECT_CALL(delete_cookie_callback, Invoke());
CompleteLoadingAndWait();
}
@@ -2970,10 +3010,16 @@ class FlushablePersistentStore : public CookieMonster::PersistentCookieStore {
public:
FlushablePersistentStore() : flush_count_(0) {}
- bool Load(const LoadedCallback& loaded_callback) {
+ void Load(const LoadedCallback& loaded_callback) {
std::vector<CookieMonster::CanonicalCookie*> out_cookies;
- loaded_callback.Run(out_cookies);
- return false;
+ MessageLoop::current()->PostTask(FROM_HERE,
+ base::Bind(&net::LoadedCallbackTask::Run,
+ new net::LoadedCallbackTask(loaded_callback, out_cookies)));
+ }
+
+ void LoadCookiesForKey(const std::string& key,
+ const LoadedCallback& loaded_callback) {
+ Load(loaded_callback);
}
void AddCookie(const CookieMonster::CanonicalCookie&) {}