1 // Copyright 2018 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.
4
5 #include "services/network/public/cpp/cookie_manager_mojom_traits.h"
6
7 #include <set>
8 #include <vector>
9
10 #include "base/test/gtest_util.h"
11 #include "mojo/public/cpp/base/time_mojom_traits.h"
12 #include "mojo/public/cpp/test_support/test_utils.h"
13 #include "net/base/schemeful_site.h"
14 #include "net/cookies/cookie_constants.h"
15 #include "services/network/public/cpp/cookie_manager_mojom_traits.h"
16 #include "services/network/public/mojom/cookie_manager.mojom.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18 #include "url/third_party/mozilla/url_parse.h"
19
20 namespace network {
21 namespace {
22
23 template <typename MojoType, typename NativeType>
SerializeAndDeserializeEnum(NativeType in,NativeType * out)24 bool SerializeAndDeserializeEnum(NativeType in, NativeType* out) {
25 MojoType intermediate = mojo::EnumTraits<MojoType, NativeType>::ToMojom(in);
26 return mojo::EnumTraits<MojoType, NativeType>::FromMojom(intermediate, out);
27 }
28
TEST(CookieManagerTraitsTest,Roundtrips_CanonicalCookie)29 TEST(CookieManagerTraitsTest, Roundtrips_CanonicalCookie) {
30 net::CanonicalCookie original(
31 "A", "B", "x.y", "/path", base::Time(), base::Time(), base::Time(), false,
32 false, net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_LOW,
33 false, net::CookieSourceScheme::kSecure, 8433);
34
35 net::CanonicalCookie copied;
36
37 EXPECT_TRUE(mojo::test::SerializeAndDeserialize<mojom::CanonicalCookie>(
38 &original, &copied));
39
40 EXPECT_EQ(original.Name(), copied.Name());
41 EXPECT_EQ(original.Value(), copied.Value());
42 EXPECT_EQ(original.Domain(), copied.Domain());
43 EXPECT_EQ(original.Path(), copied.Path());
44 EXPECT_EQ(original.CreationDate(), copied.CreationDate());
45 EXPECT_EQ(original.LastAccessDate(), copied.LastAccessDate());
46 EXPECT_EQ(original.ExpiryDate(), copied.ExpiryDate());
47 EXPECT_EQ(original.IsSecure(), copied.IsSecure());
48 EXPECT_EQ(original.IsHttpOnly(), copied.IsHttpOnly());
49 EXPECT_EQ(original.SameSite(), copied.SameSite());
50 EXPECT_EQ(original.Priority(), copied.Priority());
51 EXPECT_EQ(original.IsSameParty(), copied.IsSameParty());
52 EXPECT_EQ(original.SourceScheme(), copied.SourceScheme());
53 EXPECT_EQ(original.SourcePort(), copied.SourcePort());
54
55 // Test port edge cases: unspecified.
56 net::CanonicalCookie original_unspecified(
57 "A", "B", "x.y", "/path", base::Time(), base::Time(), base::Time(), false,
58 false, net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_LOW,
59 false, net::CookieSourceScheme::kSecure, url::PORT_UNSPECIFIED);
60 net::CanonicalCookie copied_unspecified;
61
62 EXPECT_TRUE(mojo::test::SerializeAndDeserialize<mojom::CanonicalCookie>(
63 &original_unspecified, &copied_unspecified));
64
65 EXPECT_EQ(original_unspecified.SourcePort(), copied_unspecified.SourcePort());
66
67 // Test port edge cases: invalid.
68 net::CanonicalCookie original_invalid(
69 "A", "B", "x.y", "/path", base::Time(), base::Time(), base::Time(), false,
70 false, net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_LOW,
71 false, net::CookieSourceScheme::kSecure, url::PORT_INVALID);
72 net::CanonicalCookie copied_invalid;
73
74 EXPECT_TRUE(mojo::test::SerializeAndDeserialize<mojom::CanonicalCookie>(
75 &original_invalid, &copied_invalid));
76
77 EXPECT_EQ(original_invalid.SourcePort(), copied_invalid.SourcePort());
78
79 // Serializer returns false if cookie is non-canonical.
80 // Example is non-canonical because of newline in name.
81
82 original = net::CanonicalCookie("A\n", "B", "x.y", "/path", base::Time(),
83 base::Time(), base::Time(), false, false,
84 net::CookieSameSite::NO_RESTRICTION,
85 net::COOKIE_PRIORITY_LOW, false);
86
87 EXPECT_FALSE(mojo::test::SerializeAndDeserialize<mojom::CanonicalCookie>(
88 &original, &copied));
89 }
90
TEST(CookieManagerTraitsTest,Roundtrips_CookieInclusionStatus)91 TEST(CookieManagerTraitsTest, Roundtrips_CookieInclusionStatus) {
92 // This status + warning combo doesn't really make sense. It's just an
93 // arbitrary selection of values to test the serialization/deserialization.
94 net::CookieInclusionStatus original =
95 net::CookieInclusionStatus::MakeFromReasonsForTesting(
96 {net::CookieInclusionStatus::EXCLUDE_SAMESITE_LAX,
97 net::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX,
98 net::CookieInclusionStatus::EXCLUDE_SECURE_ONLY},
99 {net::CookieInclusionStatus::
100 WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT,
101 net::CookieInclusionStatus::WARN_SAMESITE_NONE_INSECURE,
102 net::CookieInclusionStatus::
103 WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE});
104
105 net::CookieInclusionStatus copied;
106
107 EXPECT_TRUE(mojo::test::SerializeAndDeserialize<mojom::CookieInclusionStatus>(
108 &original, &copied));
109 EXPECT_TRUE(copied.HasExactlyExclusionReasonsForTesting(
110 {net::CookieInclusionStatus::EXCLUDE_SAMESITE_LAX,
111 net::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX,
112 net::CookieInclusionStatus::EXCLUDE_SECURE_ONLY}));
113 EXPECT_TRUE(copied.HasExactlyWarningReasonsForTesting(
114 {net::CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT,
115 net::CookieInclusionStatus::WARN_SAMESITE_NONE_INSECURE,
116 net::CookieInclusionStatus::
117 WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE}));
118
119 net::CookieInclusionStatus invalid;
120 invalid.set_exclusion_reasons(~0u);
121
122 EXPECT_FALSE(
123 mojo::test::SerializeAndDeserialize<mojom::CookieInclusionStatus>(
124 &invalid, &copied));
125 }
126
TEST(CookieManagerTraitsTest,Rountrips_CookieAccessResult)127 TEST(CookieManagerTraitsTest, Rountrips_CookieAccessResult) {
128 net::CookieAccessResult original = net::CookieAccessResult(
129 net::CookieEffectiveSameSite::LAX_MODE,
130 net::CookieInclusionStatus(
131 net::CookieInclusionStatus::
132 EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX,
133 net::CookieInclusionStatus::
134 WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT),
135 net::CookieAccessSemantics::LEGACY);
136 net::CookieAccessResult copied;
137
138 EXPECT_TRUE(mojo::test::SerializeAndDeserialize<mojom::CookieAccessResult>(
139 &original, &copied));
140
141 EXPECT_EQ(original.effective_same_site, copied.effective_same_site);
142 EXPECT_TRUE(copied.status.HasExactlyExclusionReasonsForTesting(
143 {net::CookieInclusionStatus::
144 EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX}));
145 EXPECT_TRUE(copied.status.HasExactlyWarningReasonsForTesting(
146 {net::CookieInclusionStatus::
147 WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT}));
148 }
149
TEST(CookieManagerTraitsTest,Rountrips_CookieWithAccessResult)150 TEST(CookieManagerTraitsTest, Rountrips_CookieWithAccessResult) {
151 net::CanonicalCookie original_cookie(
152 "A", "B", "x.y", "/path", base::Time(), base::Time(), base::Time(),
153 /* secure = */ true, /* http_only = */ false,
154 net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_LOW, false);
155
156 net::CookieWithAccessResult original = {original_cookie,
157 net::CookieAccessResult()};
158 net::CookieWithAccessResult copied;
159
160 EXPECT_TRUE(
161 mojo::test::SerializeAndDeserialize<mojom::CookieWithAccessResult>(
162 &original, &copied));
163
164 EXPECT_EQ(original.cookie.Name(), copied.cookie.Name());
165 EXPECT_EQ(original.cookie.Value(), copied.cookie.Value());
166 EXPECT_EQ(original.cookie.Domain(), copied.cookie.Domain());
167 EXPECT_EQ(original.cookie.Path(), copied.cookie.Path());
168 EXPECT_EQ(original.cookie.CreationDate(), copied.cookie.CreationDate());
169 EXPECT_EQ(original.cookie.LastAccessDate(), copied.cookie.LastAccessDate());
170 EXPECT_EQ(original.cookie.ExpiryDate(), copied.cookie.ExpiryDate());
171 EXPECT_EQ(original.cookie.IsSecure(), copied.cookie.IsSecure());
172 EXPECT_EQ(original.cookie.IsHttpOnly(), copied.cookie.IsHttpOnly());
173 EXPECT_EQ(original.cookie.SameSite(), copied.cookie.SameSite());
174 EXPECT_EQ(original.cookie.Priority(), copied.cookie.Priority());
175 EXPECT_EQ(original.cookie.IsSameParty(), copied.cookie.IsSameParty());
176 EXPECT_EQ(original.access_result.effective_same_site,
177 copied.access_result.effective_same_site);
178 EXPECT_EQ(original.access_result.status, copied.access_result.status);
179 }
180
TEST(CookieManagerTraitsTest,Rountrips_CookieAndLineWithAccessResult)181 TEST(CookieManagerTraitsTest, Rountrips_CookieAndLineWithAccessResult) {
182 net::CanonicalCookie original_cookie(
183 "A", "B", "x.y", "/path", base::Time(), base::Time(), base::Time(),
184 /* secure = */ true, /* http_only = */ false,
185 net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_LOW, false);
186
187 net::CookieAndLineWithAccessResult original(original_cookie, "cookie-string",
188 net::CookieAccessResult());
189 net::CookieAndLineWithAccessResult copied;
190
191 EXPECT_TRUE(
192 mojo::test::SerializeAndDeserialize<mojom::CookieAndLineWithAccessResult>(
193 &original, &copied));
194
195 EXPECT_EQ(original.cookie->Name(), copied.cookie->Name());
196 EXPECT_EQ(original.cookie->Value(), copied.cookie->Value());
197 EXPECT_EQ(original.cookie->Domain(), copied.cookie->Domain());
198 EXPECT_EQ(original.cookie->Path(), copied.cookie->Path());
199 EXPECT_EQ(original.cookie->CreationDate(), copied.cookie->CreationDate());
200 EXPECT_EQ(original.cookie->LastAccessDate(), copied.cookie->LastAccessDate());
201 EXPECT_EQ(original.cookie->ExpiryDate(), copied.cookie->ExpiryDate());
202 EXPECT_EQ(original.cookie->IsSecure(), copied.cookie->IsSecure());
203 EXPECT_EQ(original.cookie->IsHttpOnly(), copied.cookie->IsHttpOnly());
204 EXPECT_EQ(original.cookie->SameSite(), copied.cookie->SameSite());
205 EXPECT_EQ(original.cookie->Priority(), copied.cookie->Priority());
206 EXPECT_EQ(original.access_result.effective_same_site,
207 copied.access_result.effective_same_site);
208 EXPECT_EQ(original.cookie_string, copied.cookie_string);
209 }
210
TEST(CookieManagerTraitsTest,Roundtrips_CookieSameSite)211 TEST(CookieManagerTraitsTest, Roundtrips_CookieSameSite) {
212 for (net::CookieSameSite cookie_state :
213 {net::CookieSameSite::NO_RESTRICTION, net::CookieSameSite::LAX_MODE,
214 net::CookieSameSite::STRICT_MODE, net::CookieSameSite::UNSPECIFIED}) {
215 net::CookieSameSite roundtrip;
216 ASSERT_TRUE(SerializeAndDeserializeEnum<mojom::CookieSameSite>(cookie_state,
217 &roundtrip));
218 EXPECT_EQ(cookie_state, roundtrip);
219 }
220 }
221
TEST(CookieManagerTraitsTest,Roundtrips_CookieEffectiveSameSite)222 TEST(CookieManagerTraitsTest, Roundtrips_CookieEffectiveSameSite) {
223 for (net::CookieEffectiveSameSite cookie_state :
224 {net::CookieEffectiveSameSite::NO_RESTRICTION,
225 net::CookieEffectiveSameSite::LAX_MODE,
226 net::CookieEffectiveSameSite::STRICT_MODE,
227 net::CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE,
228 net::CookieEffectiveSameSite::UNDEFINED}) {
229 net::CookieEffectiveSameSite roundtrip;
230 ASSERT_TRUE(SerializeAndDeserializeEnum<mojom::CookieEffectiveSameSite>(
231 cookie_state, &roundtrip));
232 EXPECT_EQ(cookie_state, roundtrip);
233 }
234 }
235
TEST(CookieManagerTraitsTest,Roundtrips_ContextType)236 TEST(CookieManagerTraitsTest, Roundtrips_ContextType) {
237 using ContextType = net::CookieOptions::SameSiteCookieContext::ContextType;
238 for (ContextType context_type :
239 {ContextType::CROSS_SITE, ContextType::SAME_SITE_LAX_METHOD_UNSAFE,
240 ContextType::SAME_SITE_LAX, ContextType::SAME_SITE_STRICT}) {
241 ContextType roundtrip;
242 ASSERT_TRUE(SerializeAndDeserializeEnum<mojom::ContextType>(context_type,
243 &roundtrip));
244 EXPECT_EQ(context_type, roundtrip);
245 }
246 }
247
TEST(CookieManagerTraitsTest,Roundtrips_CookieAccessSemantics)248 TEST(CookieManagerTraitsTest, Roundtrips_CookieAccessSemantics) {
249 for (net::CookieAccessSemantics access_semantics :
250 {net::CookieAccessSemantics::UNKNOWN,
251 net::CookieAccessSemantics::NONLEGACY,
252 net::CookieAccessSemantics::LEGACY}) {
253 net::CookieAccessSemantics roundtrip;
254 ASSERT_TRUE(SerializeAndDeserializeEnum<mojom::CookieAccessSemantics>(
255 access_semantics, &roundtrip));
256 EXPECT_EQ(access_semantics, roundtrip);
257 }
258 }
259
TEST(CookieManagerTraitsTest,Roundtrips_CookieChangeCause)260 TEST(CookieManagerTraitsTest, Roundtrips_CookieChangeCause) {
261 for (net::CookieChangeCause change_cause :
262 {net::CookieChangeCause::INSERTED, net::CookieChangeCause::EXPLICIT,
263 net::CookieChangeCause::UNKNOWN_DELETION,
264 net::CookieChangeCause::OVERWRITE, net::CookieChangeCause::EXPIRED,
265 net::CookieChangeCause::EVICTED,
266 net::CookieChangeCause::EXPIRED_OVERWRITE}) {
267 net::CookieChangeCause roundtrip;
268 ASSERT_TRUE(SerializeAndDeserializeEnum<mojom::CookieChangeCause>(
269 change_cause, &roundtrip));
270 EXPECT_EQ(change_cause, roundtrip);
271 }
272 }
273
TEST(CookieManagerTraitsTest,Roundtrips_CookieSameSiteContext)274 TEST(CookieManagerTraitsTest, Roundtrips_CookieSameSiteContext) {
275 using ContextType = net::CookieOptions::SameSiteCookieContext::ContextType;
276
277 const ContextType all_context_types[]{
278 ContextType::CROSS_SITE, ContextType::SAME_SITE_LAX_METHOD_UNSAFE,
279 ContextType::SAME_SITE_LAX, ContextType::SAME_SITE_STRICT};
280
281 for (ContextType context_type : all_context_types) {
282 for (ContextType schemeful_context_type : all_context_types) {
283 net::CookieOptions::SameSiteCookieContext context_in, copy;
284 // We want to test malformed SameSiteCookieContexts. Since the constructor
285 // will DCHECK for these use the setters to bypass it.
286 context_in.set_context(context_type);
287 context_in.set_schemeful_context(schemeful_context_type);
288
289 EXPECT_EQ(
290 mojo::test::SerializeAndDeserialize<mojom::CookieSameSiteContext>(
291 &context_in, ©),
292 schemeful_context_type <= context_type);
293
294 if (schemeful_context_type <= context_type)
295 EXPECT_EQ(context_in, copy);
296 }
297 }
298 }
299
TEST(CookieManagerTraitsTest,Roundtrips_CookieOptions)300 TEST(CookieManagerTraitsTest, Roundtrips_CookieOptions) {
301 {
302 net::CookieOptions least_trusted, copy;
303 EXPECT_FALSE(least_trusted.return_excluded_cookies());
304
305 least_trusted.set_return_excluded_cookies(); // differ from default.
306
307 EXPECT_TRUE(mojo::test::SerializeAndDeserialize<mojom::CookieOptions>(
308 &least_trusted, ©));
309 EXPECT_TRUE(copy.exclude_httponly());
310 EXPECT_EQ(
311 net::CookieOptions::SameSiteCookieContext(
312 net::CookieOptions::SameSiteCookieContext::ContextType::CROSS_SITE),
313 copy.same_site_cookie_context());
314 EXPECT_TRUE(copy.return_excluded_cookies());
315 }
316
317 {
318 net::CookieOptions very_trusted, copy;
319 auto kPartyContext = std::set<net::SchemefulSite>{
320 net::SchemefulSite(url::Origin::Create(GURL("https://a.test")))};
321 very_trusted.set_include_httponly();
322 very_trusted.set_same_site_cookie_context(
323 net::CookieOptions::SameSiteCookieContext::MakeInclusive());
324 very_trusted.set_full_party_context(kPartyContext);
325
326 EXPECT_TRUE(mojo::test::SerializeAndDeserialize<mojom::CookieOptions>(
327 &very_trusted, ©));
328 EXPECT_FALSE(copy.exclude_httponly());
329 EXPECT_EQ(net::CookieOptions::SameSiteCookieContext::MakeInclusive(),
330 copy.same_site_cookie_context());
331 EXPECT_FALSE(copy.return_excluded_cookies());
332 EXPECT_EQ(kPartyContext, copy.full_party_context());
333 }
334 }
335
TEST(CookieManagerTraitsTest,Roundtrips_FullPartyContext)336 TEST(CookieManagerTraitsTest, Roundtrips_FullPartyContext) {
337 {
338 std::vector<std::set<net::SchemefulSite>> kTestCases = {
339 std::set<net::SchemefulSite>(),
340 std::set<net::SchemefulSite>{net::SchemefulSite()},
341 std::set<net::SchemefulSite>{
342 net::SchemefulSite(url::Origin::Create(GURL("https://a.test")))},
343 std::set<net::SchemefulSite>{
344 net::SchemefulSite(url::Origin::Create(GURL("http://a.test"))),
345 net::SchemefulSite(url::Origin::Create(GURL("http://b.test")))},
346 };
347
348 for (const std::set<net::SchemefulSite>& fpc : kTestCases) {
349 net::CookieOptions options, copy;
350 options.set_full_party_context(fpc);
351 EXPECT_TRUE(mojo::test::SerializeAndDeserialize<mojom::CookieOptions>(
352 &options, ©));
353 EXPECT_EQ(fpc, copy.full_party_context());
354 }
355 }
356 {
357 base::Optional<std::set<net::SchemefulSite>> kFullPartyContext =
358 base::nullopt;
359 net::CookieOptions options, copy;
360 options.set_full_party_context(kFullPartyContext);
361 EXPECT_TRUE(mojo::test::SerializeAndDeserialize<mojom::CookieOptions>(
362 &options, ©));
363 EXPECT_EQ(kFullPartyContext, copy.full_party_context());
364 }
365 }
366
TEST(CookieManagerTraitsTest,Roundtrips_CookieChangeInfo)367 TEST(CookieManagerTraitsTest, Roundtrips_CookieChangeInfo) {
368 net::CanonicalCookie original_cookie(
369 "A", "B", "x.y", "/path", base::Time(), base::Time(), base::Time(),
370 /* secure = */ false, /* http_only = */ false,
371 net::CookieSameSite::UNSPECIFIED, net::COOKIE_PRIORITY_LOW, false);
372
373 net::CookieChangeInfo original(
374 original_cookie,
375 net::CookieAccessResult(net::CookieEffectiveSameSite::UNDEFINED,
376 net::CookieInclusionStatus(),
377 net::CookieAccessSemantics::LEGACY),
378 net::CookieChangeCause::EXPLICIT);
379
380 net::CookieChangeInfo copied;
381
382 EXPECT_TRUE(mojo::test::SerializeAndDeserialize<mojom::CookieChangeInfo>(
383 &original, &copied));
384
385 EXPECT_EQ(original.cookie.Name(), copied.cookie.Name());
386 EXPECT_EQ(original.cookie.Value(), copied.cookie.Value());
387 EXPECT_EQ(original.cookie.Domain(), copied.cookie.Domain());
388 EXPECT_EQ(original.cookie.Path(), copied.cookie.Path());
389 EXPECT_EQ(original.cookie.CreationDate(), copied.cookie.CreationDate());
390 EXPECT_EQ(original.cookie.LastAccessDate(), copied.cookie.LastAccessDate());
391 EXPECT_EQ(original.cookie.ExpiryDate(), copied.cookie.ExpiryDate());
392 EXPECT_EQ(original.cookie.IsSecure(), copied.cookie.IsSecure());
393 EXPECT_EQ(original.cookie.IsHttpOnly(), copied.cookie.IsHttpOnly());
394 EXPECT_EQ(original.cookie.SameSite(), copied.cookie.SameSite());
395 EXPECT_EQ(original.cookie.Priority(), copied.cookie.Priority());
396 EXPECT_EQ(original.access_result.access_semantics,
397 copied.access_result.access_semantics);
398 EXPECT_EQ(original.cause, copied.cause);
399 }
400
401 // TODO: Add tests for CookiePriority, more extensive CookieOptions ones
402
403 } // namespace
404 } // namespace network
405