1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/browsing_data/browsing_data_cookie_helper.h"
8 #include "base/run_loop.h"
9 #include "chrome/test/base/testing_profile.h"
10 #include "content/public/test/test_browser_thread_bundle.h"
11 #include "net/cookies/canonical_cookie.h"
12 #include "net/cookies/parsed_cookie.h"
13 #include "net/url_request/url_request_context_getter.h"
14 #include "testing/gtest/include/gtest/gtest.h"
18 // Test expectations for a given cookie.
19 class CookieExpectation
{
21 CookieExpectation() : matched_(false) {}
23 bool MatchesCookie(const net::CanonicalCookie
& cookie
) const {
24 if (!source_
.empty() && source_
!= cookie
.Source())
26 if (!domain_
.empty() && domain_
!= cookie
.Domain())
28 if (!path_
.empty() && path_
!= cookie
.Path())
30 if (!name_
.empty() && name_
!= cookie
.Name())
32 if (!value_
.empty() && value_
!= cookie
.Value())
45 // Matches a CookieExpectation against a Cookie.
48 explicit CookieMatcher(const net::CanonicalCookie
& cookie
)
50 bool operator()(const CookieExpectation
& expectation
) {
51 return expectation
.MatchesCookie(cookie_
);
53 net::CanonicalCookie cookie_
;
56 // Unary predicate to determine whether an expectation has been matched.
57 bool ExpectationIsMatched(const CookieExpectation
& expectation
) {
58 return expectation
.matched_
;
61 class BrowsingDataCookieHelperTest
: public testing::Test
{
63 BrowsingDataCookieHelperTest()
64 : testing_profile_(new TestingProfile()) {
67 void SetUp() override
{ cookie_expectations_
.clear(); }
69 // Adds an expectation for a cookie that satisfies the given parameters.
70 void AddCookieExpectation(const char* source
,
75 CookieExpectation matcher
;
77 matcher
.source_
= source
;
79 matcher
.domain_
= domain
;
85 matcher
.value_
= value
;
86 cookie_expectations_
.push_back(matcher
);
89 // Checks the existing expectations, and then clears all existing
91 void CheckCookieExpectations() {
92 ASSERT_EQ(cookie_expectations_
.size(), cookie_list_
.size());
94 // For each cookie, look for a matching expectation.
95 for (net::CookieList::iterator it
= cookie_list_
.begin();
96 it
!= cookie_list_
.end();
98 CookieMatcher
matcher(*it
);
99 std::vector
<CookieExpectation
>::iterator match
= std::find_if(
100 cookie_expectations_
.begin(), cookie_expectations_
.end(), matcher
);
101 if (match
!= cookie_expectations_
.end())
102 match
->matched_
= true;
105 // Check that each expectation has been matched.
106 unsigned long match_count
= std::count_if(cookie_expectations_
.begin(),
107 cookie_expectations_
.end(),
108 ExpectationIsMatched
);
109 EXPECT_EQ(cookie_expectations_
.size(), match_count
);
111 cookie_expectations_
.clear();
114 void CreateCookiesForTest() {
115 scoped_refptr
<net::CookieMonster
> cookie_monster
=
116 testing_profile_
->GetCookieMonster();
117 cookie_monster
->SetCookieWithOptionsAsync(
118 GURL("http://www.google.com"), "A=1", net::CookieOptions(),
119 net::CookieMonster::SetCookiesCallback());
120 cookie_monster
->SetCookieWithOptionsAsync(
121 GURL("http://www.gmail.google.com"), "B=1", net::CookieOptions(),
122 net::CookieMonster::SetCookiesCallback());
125 void CreateCookiesForDomainCookieTest() {
126 scoped_refptr
<net::CookieMonster
> cookie_monster
=
127 testing_profile_
->GetCookieMonster();
128 cookie_monster
->SetCookieWithOptionsAsync(
129 GURL("http://www.google.com"), "A=1", net::CookieOptions(),
130 net::CookieMonster::SetCookiesCallback());
131 cookie_monster
->SetCookieWithOptionsAsync(
132 GURL("http://www.google.com"), "A=2; Domain=.www.google.com ",
133 net::CookieOptions(), net::CookieMonster::SetCookiesCallback());
136 void FetchCallback(const net::CookieList
& cookies
) {
137 cookie_list_
= cookies
;
139 AddCookieExpectation(NULL
, "www.google.com", NULL
, "A", NULL
);
140 AddCookieExpectation(NULL
, "www.gmail.google.com", NULL
, "B", NULL
);
141 CheckCookieExpectations();
144 void DomainCookieCallback(const net::CookieList
& cookies
) {
145 cookie_list_
= cookies
;
147 AddCookieExpectation(NULL
, "www.google.com", NULL
, "A", "1");
148 AddCookieExpectation(NULL
, ".www.google.com", NULL
, "A", "2");
149 CheckCookieExpectations();
152 void DeleteCallback(const net::CookieList
& cookies
) {
153 cookie_list_
= cookies
;
154 AddCookieExpectation(NULL
, "www.gmail.google.com", NULL
, "B", NULL
);
155 CheckCookieExpectations();
158 void CannedUniqueCallback(const net::CookieList
& cookies
) {
159 cookie_list_
= cookies
;
160 AddCookieExpectation(
161 "http://www.google.com/", "www.google.com", "/", "A", NULL
);
162 CheckCookieExpectations();
165 void CannedReplaceCookieCallback(const net::CookieList
& cookies
) {
166 cookie_list_
= cookies
;
167 AddCookieExpectation(
168 "http://www.google.com/", "www.google.com", "/", "A", "2");
169 AddCookieExpectation(
170 "http://www.google.com/", "www.google.com", "/example/0", "A", "4");
171 AddCookieExpectation(
172 "http://www.google.com/", ".google.com", "/", "A", "6");
173 AddCookieExpectation(
174 "http://www.google.com/", ".google.com", "/example/1", "A", "8");
175 AddCookieExpectation(
176 "http://www.google.com/", ".www.google.com", "/", "A", "10");
177 CheckCookieExpectations();
180 void CannedDomainCookieCallback(const net::CookieList
& cookies
) {
181 cookie_list_
= cookies
;
182 AddCookieExpectation(
183 "http://www.google.com/", "www.google.com", NULL
, "A", NULL
);
184 AddCookieExpectation(
185 "http://www.google.com/", ".www.google.com", NULL
, "A", NULL
);
186 CheckCookieExpectations();
189 void CannedDifferentFramesCallback(const net::CookieList
& cookie_list
) {
190 ASSERT_EQ(3U, cookie_list
.size());
193 void DeleteCookie(BrowsingDataCookieHelper
* helper
, const GURL origin
) {
194 for (net::CookieList::iterator it
= cookie_list_
.begin();
195 it
!= cookie_list_
.end();
197 if (it
->Source() == net::CanonicalCookie::GetCookieSourceFromURL(origin
))
198 helper
->DeleteCookie(*it
);
203 content::TestBrowserThreadBundle thread_bundle_
;
204 scoped_ptr
<TestingProfile
> testing_profile_
;
206 std::vector
<CookieExpectation
> cookie_expectations_
;
207 net::CookieList cookie_list_
;
210 TEST_F(BrowsingDataCookieHelperTest
, FetchData
) {
211 CreateCookiesForTest();
212 scoped_refptr
<BrowsingDataCookieHelper
> cookie_helper(
213 new BrowsingDataCookieHelper(testing_profile_
->GetRequestContext()));
215 cookie_helper
->StartFetching(
216 base::Bind(&BrowsingDataCookieHelperTest::FetchCallback
,
217 base::Unretained(this)));
218 base::RunLoop().RunUntilIdle();
221 TEST_F(BrowsingDataCookieHelperTest
, DomainCookie
) {
222 CreateCookiesForDomainCookieTest();
223 scoped_refptr
<BrowsingDataCookieHelper
> cookie_helper(
224 new BrowsingDataCookieHelper(testing_profile_
->GetRequestContext()));
226 cookie_helper
->StartFetching(
227 base::Bind(&BrowsingDataCookieHelperTest::DomainCookieCallback
,
228 base::Unretained(this)));
229 base::RunLoop().RunUntilIdle();
232 TEST_F(BrowsingDataCookieHelperTest
, DeleteCookie
) {
233 CreateCookiesForTest();
234 scoped_refptr
<BrowsingDataCookieHelper
> cookie_helper(
235 new BrowsingDataCookieHelper(testing_profile_
->GetRequestContext()));
237 cookie_helper
->StartFetching(
238 base::Bind(&BrowsingDataCookieHelperTest::FetchCallback
,
239 base::Unretained(this)));
240 base::RunLoop().RunUntilIdle();
242 net::CanonicalCookie cookie
= cookie_list_
[0];
243 cookie_helper
->DeleteCookie(cookie
);
245 cookie_helper
->StartFetching(
246 base::Bind(&BrowsingDataCookieHelperTest::DeleteCallback
,
247 base::Unretained(this)));
248 base::RunLoop().RunUntilIdle();
251 TEST_F(BrowsingDataCookieHelperTest
, CannedDeleteCookie
) {
252 CreateCookiesForTest();
253 scoped_refptr
<CannedBrowsingDataCookieHelper
> helper(
254 new CannedBrowsingDataCookieHelper(
255 testing_profile_
->GetRequestContext()));
257 ASSERT_TRUE(helper
->empty());
259 const GURL
origin1("http://www.google.com");
260 const GURL
origin2("http://www.gmail.google.com");
261 helper
->AddChangedCookie(origin1
, origin1
, "A=1", net::CookieOptions());
262 helper
->AddChangedCookie(origin2
, origin2
, "B=1", net::CookieOptions());
264 helper
->StartFetching(
265 base::Bind(&BrowsingDataCookieHelperTest::FetchCallback
,
266 base::Unretained(this)));
267 base::RunLoop().RunUntilIdle();
269 EXPECT_EQ(2u, helper
->GetCookieCount());
271 DeleteCookie(helper
.get(), origin1
);
273 EXPECT_EQ(1u, helper
->GetCookieCount());
274 helper
->StartFetching(
275 base::Bind(&BrowsingDataCookieHelperTest::DeleteCallback
,
276 base::Unretained(this)));
277 base::RunLoop().RunUntilIdle();
280 TEST_F(BrowsingDataCookieHelperTest
, CannedDomainCookie
) {
281 const GURL
origin("http://www.google.com");
282 net::CookieList cookie
;
284 scoped_refptr
<CannedBrowsingDataCookieHelper
> helper(
285 new CannedBrowsingDataCookieHelper(
286 testing_profile_
->GetRequestContext()));
288 ASSERT_TRUE(helper
->empty());
289 helper
->AddChangedCookie(origin
, origin
, "A=1", net::CookieOptions());
290 helper
->AddChangedCookie(origin
, origin
, "A=1; Domain=.www.google.com",
291 net::CookieOptions());
292 // Try adding invalid cookies that will be ignored.
293 helper
->AddChangedCookie(origin
, origin
, std::string(), net::CookieOptions());
294 helper
->AddChangedCookie(origin
,
296 "C=bad guy; Domain=wrongdomain.com",
297 net::CookieOptions());
299 helper
->StartFetching(
300 base::Bind(&BrowsingDataCookieHelperTest::CannedDomainCookieCallback
,
301 base::Unretained(this)));
302 cookie
= cookie_list_
;
305 ASSERT_TRUE(helper
->empty());
307 helper
->AddReadCookies(origin
, origin
, cookie
);
308 helper
->StartFetching(
309 base::Bind(&BrowsingDataCookieHelperTest::CannedDomainCookieCallback
,
310 base::Unretained(this)));
313 TEST_F(BrowsingDataCookieHelperTest
, CannedUnique
) {
314 const GURL
origin("http://www.google.com");
315 net::CookieList cookie
;
317 scoped_refptr
<CannedBrowsingDataCookieHelper
> helper(
318 new CannedBrowsingDataCookieHelper(
319 testing_profile_
->GetRequestContext()));
321 ASSERT_TRUE(helper
->empty());
322 helper
->AddChangedCookie(origin
, origin
, "A=1", net::CookieOptions());
323 helper
->AddChangedCookie(origin
, origin
, "A=1", net::CookieOptions());
324 helper
->StartFetching(
325 base::Bind(&BrowsingDataCookieHelperTest::CannedUniqueCallback
,
326 base::Unretained(this)));
328 cookie
= cookie_list_
;
330 ASSERT_TRUE(helper
->empty());
332 helper
->AddReadCookies(origin
, origin
, cookie
);
333 helper
->AddReadCookies(origin
, origin
, cookie
);
334 helper
->StartFetching(
335 base::Bind(&BrowsingDataCookieHelperTest::CannedUniqueCallback
,
336 base::Unretained(this)));
339 TEST_F(BrowsingDataCookieHelperTest
, CannedReplaceCookie
) {
340 const GURL
origin("http://www.google.com");
341 net::CookieList cookie
;
343 scoped_refptr
<CannedBrowsingDataCookieHelper
> helper(
344 new CannedBrowsingDataCookieHelper(
345 testing_profile_
->GetRequestContext()));
347 ASSERT_TRUE(helper
->empty());
348 helper
->AddChangedCookie(origin
, origin
, "A=1", net::CookieOptions());
349 helper
->AddChangedCookie(origin
, origin
, "A=2", net::CookieOptions());
350 helper
->AddChangedCookie(origin
, origin
, "A=3; Path=/example/0",
351 net::CookieOptions());
352 helper
->AddChangedCookie(origin
, origin
, "A=4; Path=/example/0",
353 net::CookieOptions());
354 helper
->AddChangedCookie(origin
, origin
, "A=5; Domain=google.com",
355 net::CookieOptions());
356 helper
->AddChangedCookie(origin
, origin
, "A=6; Domain=google.com",
357 net::CookieOptions());
358 helper
->AddChangedCookie(origin
, origin
,
359 "A=7; Domain=google.com; Path=/example/1",
360 net::CookieOptions());
361 helper
->AddChangedCookie(origin
, origin
,
362 "A=8; Domain=google.com; Path=/example/1",
363 net::CookieOptions());
365 helper
->AddChangedCookie(origin
, origin
,
366 "A=9; Domain=www.google.com",
367 net::CookieOptions());
368 helper
->AddChangedCookie(origin
, origin
,
369 "A=10; Domain=www.google.com",
370 net::CookieOptions());
372 helper
->StartFetching(
373 base::Bind(&BrowsingDataCookieHelperTest::CannedReplaceCookieCallback
,
374 base::Unretained(this)));
376 cookie
= cookie_list_
;
378 ASSERT_TRUE(helper
->empty());
380 helper
->AddReadCookies(origin
, origin
, cookie
);
381 helper
->AddReadCookies(origin
, origin
, cookie
);
382 helper
->StartFetching(
383 base::Bind(&BrowsingDataCookieHelperTest::CannedReplaceCookieCallback
,
384 base::Unretained(this)));
387 TEST_F(BrowsingDataCookieHelperTest
, CannedEmpty
) {
388 const GURL
url_google("http://www.google.com");
390 scoped_refptr
<CannedBrowsingDataCookieHelper
> helper(
391 new CannedBrowsingDataCookieHelper(
392 testing_profile_
->GetRequestContext()));
394 ASSERT_TRUE(helper
->empty());
395 helper
->AddChangedCookie(url_google
, url_google
, "a=1",
396 net::CookieOptions());
397 ASSERT_FALSE(helper
->empty());
399 ASSERT_TRUE(helper
->empty());
401 net::CookieList cookies
;
402 net::ParsedCookie
pc("a=1");
403 scoped_ptr
<net::CanonicalCookie
> cookie(
404 new net::CanonicalCookie(url_google
, pc
));
405 cookies
.push_back(*cookie
);
407 helper
->AddReadCookies(url_google
, url_google
, cookies
);
408 ASSERT_FALSE(helper
->empty());
410 ASSERT_TRUE(helper
->empty());
413 TEST_F(BrowsingDataCookieHelperTest
, CannedDifferentFrames
) {
414 GURL
frame1_url("http://www.google.com");
415 GURL
frame2_url("http://www.google.de");
416 GURL
request_url("http://www.google.com");
418 scoped_refptr
<CannedBrowsingDataCookieHelper
> helper(
419 new CannedBrowsingDataCookieHelper(
420 testing_profile_
->GetRequestContext()));
422 ASSERT_TRUE(helper
->empty());
423 helper
->AddChangedCookie(frame1_url
, request_url
, "a=1",
424 net::CookieOptions());
425 helper
->AddChangedCookie(frame1_url
, request_url
, "b=1",
426 net::CookieOptions());
427 helper
->AddChangedCookie(frame2_url
, request_url
, "c=1",
428 net::CookieOptions());
430 helper
->StartFetching(
431 base::Bind(&BrowsingDataCookieHelperTest::CannedDifferentFramesCallback
,
432 base::Unretained(this)));
435 TEST_F(BrowsingDataCookieHelperTest
, CannedGetCookieCount
) {
436 // The URL in the omnibox is a frame URL. This is not necessarily the request
437 // URL, since websites usually include other resources.
438 GURL
frame1_url("http://www.google.com");
439 GURL
frame2_url("http://www.google.de");
440 // The request URL used for all cookies that are added to the |helper|.
441 GURL
request1_url("http://static.google.com/foo/res1.html");
442 GURL
request2_url("http://static.google.com/bar/res2.html");
443 std::string
cookie_domain(".www.google.com");
444 std::string
cookie_pair1("A=1");
445 std::string
cookie_pair2("B=1");
446 // The cookie pair used for adding a cookie that overrides the cookie created
447 // with |cookie_pair1|. The cookie-name of |cookie_pair3| must match the
448 // cookie-name of |cookie-pair1|.
449 std::string
cookie_pair3("A=2");
450 // The cookie pair used for adding a non host-only cookie. The cookie-name
451 // must match the cookie-name of |cookie_pair1| in order to add a host-only
452 // and a non host-only cookie with the same name below.
453 std::string
cookie_pair4("A=3");
455 scoped_refptr
<CannedBrowsingDataCookieHelper
> helper(
456 new CannedBrowsingDataCookieHelper(
457 testing_profile_
->GetRequestContext()));
459 // Add two different cookies (distinguished by the tuple [cookie-name,
460 // domain-value, path-value]) for a HTTP request to |frame1_url| and verify
461 // that the cookie count is increased to two. The set-cookie-string consists
462 // only of the cookie-pair. This means that the host and the default-path of
463 // the |request_url| are used as domain-value and path-value for the added
465 EXPECT_EQ(0U, helper
->GetCookieCount());
466 helper
->AddChangedCookie(frame1_url
, frame1_url
, cookie_pair1
,
467 net::CookieOptions());
468 EXPECT_EQ(1U, helper
->GetCookieCount());
469 helper
->AddChangedCookie(frame1_url
, frame1_url
, cookie_pair2
,
470 net::CookieOptions());
471 EXPECT_EQ(2U, helper
->GetCookieCount());
473 // Use a different frame URL for adding another cookie that will replace one
474 // of the previously added cookies. This could happen during an automatic
475 // redirect e.g. |frame1_url| redirects to |frame2_url| and a cookie set by a
476 // request to |frame1_url| is updated.
477 helper
->AddChangedCookie(frame2_url
, frame1_url
, cookie_pair3
,
478 net::CookieOptions());
479 EXPECT_EQ(2U, helper
->GetCookieCount());
481 // Add two more cookies that are set while loading resources. The two cookies
482 // below have a differnt path-value since the request URLs have different
484 helper
->AddChangedCookie(frame2_url
, request1_url
, cookie_pair3
,
485 net::CookieOptions());
486 EXPECT_EQ(3U, helper
->GetCookieCount());
487 helper
->AddChangedCookie(frame2_url
, request2_url
, cookie_pair3
,
488 net::CookieOptions());
489 EXPECT_EQ(4U, helper
->GetCookieCount());
491 // Host-only and domain cookies are treated as seperate items. This means that
492 // the following two cookie-strings are stored as two separate cookies, even
493 // though they have the same name and are send with the same request:
495 // "A=3; Domain=www.google.com"
496 // Add a domain cookie and check if it increases the cookie count.
497 helper
->AddChangedCookie(frame2_url
, frame1_url
,
498 cookie_pair4
+ "; Domain=" + cookie_domain
,
499 net::CookieOptions());
500 EXPECT_EQ(5U, helper
->GetCookieCount());