Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / net / cookies / canonical_cookie_unittest.cc
blobfc0d45374cd89b4c05cb754873555a9e8d327d31
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 "net/cookies/canonical_cookie.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "net/cookies/cookie_constants.h"
9 #include "net/cookies/cookie_options.h"
10 #include "testing/gtest/include/gtest/gtest.h"
11 #include "url/gurl.h"
13 namespace net {
15 TEST(CanonicalCookieTest, GetCookieSourceFromURL) {
16 EXPECT_EQ("http://example.com/", CanonicalCookie::GetCookieSourceFromURL(
17 GURL("http://example.com")));
18 EXPECT_EQ("http://example.com/", CanonicalCookie::GetCookieSourceFromURL(
19 GURL("http://example.com/")));
20 EXPECT_EQ("http://example.com/", CanonicalCookie::GetCookieSourceFromURL(
21 GURL("http://example.com/test")));
22 EXPECT_EQ("file:///tmp/test.html", CanonicalCookie::GetCookieSourceFromURL(
23 GURL("file:///tmp/test.html")));
24 EXPECT_EQ("http://example.com/", CanonicalCookie::GetCookieSourceFromURL(
25 GURL("http://example.com:1234/")));
26 EXPECT_EQ("http://example.com/", CanonicalCookie::GetCookieSourceFromURL(
27 GURL("https://example.com/")));
28 EXPECT_EQ("http://example.com/", CanonicalCookie::GetCookieSourceFromURL(
29 GURL("http://user:pwd@example.com/")));
30 EXPECT_EQ("http://example.com/", CanonicalCookie::GetCookieSourceFromURL(
31 GURL("http://example.com/test?foo")));
32 EXPECT_EQ("http://example.com/", CanonicalCookie::GetCookieSourceFromURL(
33 GURL("http://example.com/test#foo")));
36 TEST(CanonicalCookieTest, Constructor) {
37 GURL url("http://www.example.com/test");
38 base::Time current_time = base::Time::Now();
40 CanonicalCookie cookie(url, "A", "2", "www.example.com", "/test",
41 current_time, base::Time(), current_time, false, false,
42 false, COOKIE_PRIORITY_DEFAULT);
43 EXPECT_EQ(url.GetOrigin().spec(), cookie.Source());
44 EXPECT_EQ("A", cookie.Name());
45 EXPECT_EQ("2", cookie.Value());
46 EXPECT_EQ("www.example.com", cookie.Domain());
47 EXPECT_EQ("/test", cookie.Path());
48 EXPECT_FALSE(cookie.IsSecure());
49 EXPECT_FALSE(cookie.IsHttpOnly());
50 EXPECT_FALSE(cookie.IsFirstPartyOnly());
52 CanonicalCookie cookie2(url, "A", "2", std::string(), std::string(),
53 current_time, base::Time(), current_time, false,
54 false, false, COOKIE_PRIORITY_DEFAULT);
55 EXPECT_EQ(url.GetOrigin().spec(), cookie.Source());
56 EXPECT_EQ("A", cookie2.Name());
57 EXPECT_EQ("2", cookie2.Value());
58 EXPECT_EQ("", cookie2.Domain());
59 EXPECT_EQ("", cookie2.Path());
60 EXPECT_FALSE(cookie2.IsSecure());
61 EXPECT_FALSE(cookie2.IsHttpOnly());
62 EXPECT_FALSE(cookie2.IsFirstPartyOnly());
65 TEST(CanonicalCookieTest, Create) {
66 // Test creating cookies from a cookie string.
67 GURL url("http://www.example.com/test/foo.html");
68 base::Time creation_time = base::Time::Now();
69 CookieOptions options;
71 scoped_ptr<CanonicalCookie> cookie(
72 CanonicalCookie::Create(url, "A=2", creation_time, options));
73 EXPECT_EQ(url.GetOrigin().spec(), cookie->Source());
74 EXPECT_EQ("A", cookie->Name());
75 EXPECT_EQ("2", cookie->Value());
76 EXPECT_EQ("www.example.com", cookie->Domain());
77 EXPECT_EQ("/test", cookie->Path());
78 EXPECT_FALSE(cookie->IsSecure());
80 GURL url2("http://www.foo.com");
81 cookie.reset(CanonicalCookie::Create(url2, "B=1", creation_time, options));
82 EXPECT_EQ(url2.GetOrigin().spec(), cookie->Source());
83 EXPECT_EQ("B", cookie->Name());
84 EXPECT_EQ("1", cookie->Value());
85 EXPECT_EQ("www.foo.com", cookie->Domain());
86 EXPECT_EQ("/", cookie->Path());
87 EXPECT_FALSE(cookie->IsSecure());
89 // Test creating secure cookies. RFC 6265 allows insecure urls to set secure
90 // cookies.
91 cookie.reset(
92 CanonicalCookie::Create(url, "A=2; Secure", creation_time, options));
93 EXPECT_TRUE(cookie.get());
94 EXPECT_TRUE(cookie->IsSecure());
96 // Test creating http only cookies.
97 cookie.reset(
98 CanonicalCookie::Create(url, "A=2; HttpOnly", creation_time, options));
99 EXPECT_FALSE(cookie.get());
100 CookieOptions httponly_options;
101 httponly_options.set_include_httponly();
102 cookie.reset(CanonicalCookie::Create(url, "A=2; HttpOnly", creation_time,
103 httponly_options));
104 EXPECT_TRUE(cookie->IsHttpOnly());
106 // Test creating http only cookies.
107 CookieOptions first_party_options;
108 first_party_options.set_first_party_url(url);
109 cookie.reset(CanonicalCookie::Create(url, "A=2; First-Party-Only",
110 creation_time, httponly_options));
111 EXPECT_TRUE(cookie.get());
112 EXPECT_TRUE(cookie->IsFirstPartyOnly());
114 // Test the creating cookies using specific parameter instead of a cookie
115 // string.
116 cookie.reset(CanonicalCookie::Create(
117 url, "A", "2", "www.example.com", "/test", creation_time, base::Time(),
118 false, false, false, COOKIE_PRIORITY_DEFAULT));
119 EXPECT_EQ(url.GetOrigin().spec(), cookie->Source());
120 EXPECT_EQ("A", cookie->Name());
121 EXPECT_EQ("2", cookie->Value());
122 EXPECT_EQ(".www.example.com", cookie->Domain());
123 EXPECT_EQ("/test", cookie->Path());
124 EXPECT_FALSE(cookie->IsSecure());
125 EXPECT_FALSE(cookie->IsHttpOnly());
126 EXPECT_FALSE(cookie->IsFirstPartyOnly());
128 cookie.reset(CanonicalCookie::Create(
129 url, "A", "2", ".www.example.com", "/test", creation_time, base::Time(),
130 false, false, false, COOKIE_PRIORITY_DEFAULT));
131 EXPECT_EQ(url.GetOrigin().spec(), cookie->Source());
132 EXPECT_EQ("A", cookie->Name());
133 EXPECT_EQ("2", cookie->Value());
134 EXPECT_EQ(".www.example.com", cookie->Domain());
135 EXPECT_EQ("/test", cookie->Path());
136 EXPECT_FALSE(cookie->IsSecure());
137 EXPECT_FALSE(cookie->IsHttpOnly());
138 EXPECT_FALSE(cookie->IsFirstPartyOnly());
141 TEST(CanonicalCookieTest, EmptyExpiry) {
142 GURL url("http://www7.ipdl.inpit.go.jp/Tokujitu/tjkta.ipdl?N0000=108");
143 base::Time creation_time = base::Time::Now();
144 CookieOptions options;
146 std::string cookie_line =
147 "ACSTM=20130308043820420042; path=/; domain=ipdl.inpit.go.jp; Expires=";
148 scoped_ptr<CanonicalCookie> cookie(
149 CanonicalCookie::Create(url, cookie_line, creation_time, options));
150 EXPECT_TRUE(cookie.get());
151 EXPECT_FALSE(cookie->IsPersistent());
152 EXPECT_FALSE(cookie->IsExpired(creation_time));
153 EXPECT_EQ(base::Time(), cookie->ExpiryDate());
155 // With a stale server time
156 options.set_server_time(creation_time - base::TimeDelta::FromHours(1));
157 cookie.reset(
158 CanonicalCookie::Create(url, cookie_line, creation_time, options));
159 EXPECT_TRUE(cookie.get());
160 EXPECT_FALSE(cookie->IsPersistent());
161 EXPECT_FALSE(cookie->IsExpired(creation_time));
162 EXPECT_EQ(base::Time(), cookie->ExpiryDate());
164 // With a future server time
165 options.set_server_time(creation_time + base::TimeDelta::FromHours(1));
166 cookie.reset(
167 CanonicalCookie::Create(url, cookie_line, creation_time, options));
168 EXPECT_TRUE(cookie.get());
169 EXPECT_FALSE(cookie->IsPersistent());
170 EXPECT_FALSE(cookie->IsExpired(creation_time));
171 EXPECT_EQ(base::Time(), cookie->ExpiryDate());
174 TEST(CanonicalCookieTest, IsEquivalent) {
175 GURL url("http://www.example.com/");
176 std::string cookie_name = "A";
177 std::string cookie_value = "2EDA-EF";
178 std::string cookie_domain = ".www.example.com";
179 std::string cookie_path = "/";
180 base::Time creation_time = base::Time::Now();
181 base::Time last_access_time = creation_time;
182 base::Time expiration_time = creation_time + base::TimeDelta::FromDays(2);
183 bool secure(false);
184 bool httponly(false);
185 bool firstparty(false);
187 // Test that a cookie is equivalent to itself.
188 scoped_ptr<CanonicalCookie> cookie(new CanonicalCookie(
189 url, cookie_name, cookie_value, cookie_domain, cookie_path, creation_time,
190 expiration_time, last_access_time, secure, httponly, firstparty,
191 COOKIE_PRIORITY_MEDIUM));
192 EXPECT_TRUE(cookie->IsEquivalent(*cookie));
194 // Test that two identical cookies are equivalent.
195 scoped_ptr<CanonicalCookie> other_cookie(new CanonicalCookie(
196 url, cookie_name, cookie_value, cookie_domain, cookie_path, creation_time,
197 expiration_time, last_access_time, secure, httponly, firstparty,
198 COOKIE_PRIORITY_MEDIUM));
199 EXPECT_TRUE(cookie->IsEquivalent(*other_cookie));
201 // Tests that use different variations of attribute values that
202 // DON'T affect cookie equivalence.
203 other_cookie.reset(
204 new CanonicalCookie(url, cookie_name, "2", cookie_domain, cookie_path,
205 creation_time, expiration_time, last_access_time,
206 secure, httponly, firstparty, COOKIE_PRIORITY_HIGH));
207 EXPECT_TRUE(cookie->IsEquivalent(*other_cookie));
209 base::Time other_creation_time =
210 creation_time + base::TimeDelta::FromMinutes(2);
211 other_cookie.reset(new CanonicalCookie(
212 url, cookie_name, "2", cookie_domain, cookie_path, other_creation_time,
213 expiration_time, last_access_time, secure, httponly, firstparty,
214 COOKIE_PRIORITY_MEDIUM));
215 EXPECT_TRUE(cookie->IsEquivalent(*other_cookie));
217 other_cookie.reset(new CanonicalCookie(
218 url, cookie_name, cookie_name, cookie_domain, cookie_path, creation_time,
219 expiration_time, last_access_time, true, httponly, firstparty,
220 COOKIE_PRIORITY_LOW));
221 EXPECT_TRUE(cookie->IsEquivalent(*other_cookie));
223 other_cookie.reset(new CanonicalCookie(
224 url, cookie_name, cookie_name, cookie_domain, cookie_path, creation_time,
225 expiration_time, last_access_time, secure, true, firstparty,
226 COOKIE_PRIORITY_LOW));
227 EXPECT_TRUE(cookie->IsEquivalent(*other_cookie));
229 other_cookie.reset(new CanonicalCookie(
230 url, cookie_name, cookie_name, cookie_domain, cookie_path, creation_time,
231 expiration_time, last_access_time, secure, httponly, true,
232 COOKIE_PRIORITY_LOW));
233 EXPECT_TRUE(cookie->IsEquivalent(*other_cookie));
235 // Tests that use different variations of attribute values that
236 // DO affect cookie equivalence.
237 other_cookie.reset(new CanonicalCookie(
238 url, "B", cookie_value, cookie_domain, cookie_path, creation_time,
239 expiration_time, last_access_time, secure, httponly, firstparty,
240 COOKIE_PRIORITY_MEDIUM));
241 EXPECT_FALSE(cookie->IsEquivalent(*other_cookie));
243 other_cookie.reset(new CanonicalCookie(
244 url, cookie_name, cookie_value, "www.example.com", cookie_path,
245 creation_time, expiration_time, last_access_time, secure, httponly,
246 firstparty, COOKIE_PRIORITY_MEDIUM));
247 EXPECT_TRUE(cookie->IsDomainCookie());
248 EXPECT_FALSE(other_cookie->IsDomainCookie());
249 EXPECT_FALSE(cookie->IsEquivalent(*other_cookie));
251 other_cookie.reset(new CanonicalCookie(
252 url, cookie_name, cookie_value, ".example.com", cookie_path,
253 creation_time, expiration_time, last_access_time, secure, httponly,
254 firstparty, COOKIE_PRIORITY_MEDIUM));
255 EXPECT_FALSE(cookie->IsEquivalent(*other_cookie));
257 other_cookie.reset(new CanonicalCookie(
258 url, cookie_name, cookie_value, cookie_domain, "/test/0", creation_time,
259 expiration_time, last_access_time, secure, httponly, firstparty,
260 COOKIE_PRIORITY_MEDIUM));
261 EXPECT_FALSE(cookie->IsEquivalent(*other_cookie));
264 TEST(CanonicalCookieTest, IsDomainMatch) {
265 GURL url("http://www.example.com/test/foo.html");
266 base::Time creation_time = base::Time::Now();
267 CookieOptions options;
269 scoped_ptr<CanonicalCookie> cookie(
270 CanonicalCookie::Create(url, "A=2", creation_time, options));
271 EXPECT_TRUE(cookie->IsHostCookie());
272 EXPECT_TRUE(cookie->IsDomainMatch("www.example.com"));
273 EXPECT_TRUE(cookie->IsDomainMatch("www.example.com"));
274 EXPECT_FALSE(cookie->IsDomainMatch("foo.www.example.com"));
275 EXPECT_FALSE(cookie->IsDomainMatch("www0.example.com"));
276 EXPECT_FALSE(cookie->IsDomainMatch("example.com"));
278 cookie.reset(CanonicalCookie::Create(url, "A=2; Domain=www.example.com",
279 creation_time, options));
280 EXPECT_TRUE(cookie->IsDomainCookie());
281 EXPECT_TRUE(cookie->IsDomainMatch("www.example.com"));
282 EXPECT_TRUE(cookie->IsDomainMatch("www.example.com"));
283 EXPECT_TRUE(cookie->IsDomainMatch("foo.www.example.com"));
284 EXPECT_FALSE(cookie->IsDomainMatch("www0.example.com"));
285 EXPECT_FALSE(cookie->IsDomainMatch("example.com"));
287 cookie.reset(CanonicalCookie::Create(url, "A=2; Domain=.www.example.com",
288 creation_time, options));
289 EXPECT_TRUE(cookie->IsDomainMatch("www.example.com"));
290 EXPECT_TRUE(cookie->IsDomainMatch("www.example.com"));
291 EXPECT_TRUE(cookie->IsDomainMatch("foo.www.example.com"));
292 EXPECT_FALSE(cookie->IsDomainMatch("www0.example.com"));
293 EXPECT_FALSE(cookie->IsDomainMatch("example.com"));
296 TEST(CanonicalCookieTest, IsOnPath) {
297 base::Time creation_time = base::Time::Now();
298 CookieOptions options;
300 scoped_ptr<CanonicalCookie> cookie(CanonicalCookie::Create(
301 GURL("http://www.example.com"), "A=2", creation_time, options));
302 EXPECT_TRUE(cookie->IsOnPath("/"));
303 EXPECT_TRUE(cookie->IsOnPath("/test"));
304 EXPECT_TRUE(cookie->IsOnPath("/test/bar.html"));
306 // Test the empty string edge case.
307 EXPECT_FALSE(cookie->IsOnPath(std::string()));
309 cookie.reset(
310 CanonicalCookie::Create(GURL("http://www.example.com/test/foo.html"),
311 "A=2", creation_time, options));
312 EXPECT_FALSE(cookie->IsOnPath("/"));
313 EXPECT_TRUE(cookie->IsOnPath("/test"));
314 EXPECT_TRUE(cookie->IsOnPath("/test/bar.html"));
315 EXPECT_TRUE(cookie->IsOnPath("/test/sample/bar.html"));
318 TEST(CanonicalCookieTest, IncludeForRequestURL) {
319 GURL url("http://www.example.com");
320 base::Time creation_time = base::Time::Now();
321 CookieOptions options;
323 scoped_ptr<CanonicalCookie> cookie(
324 CanonicalCookie::Create(url, "A=2", creation_time, options));
325 EXPECT_TRUE(cookie->IncludeForRequestURL(url, options));
326 EXPECT_TRUE(cookie->IncludeForRequestURL(
327 GURL("http://www.example.com/foo/bar"), options));
328 EXPECT_TRUE(cookie->IncludeForRequestURL(
329 GURL("https://www.example.com/foo/bar"), options));
330 EXPECT_FALSE(
331 cookie->IncludeForRequestURL(GURL("https://sub.example.com"), options));
332 EXPECT_FALSE(cookie->IncludeForRequestURL(GURL("https://sub.www.example.com"),
333 options));
335 // Test that cookie with a cookie path that does not match the url path are
336 // not included.
337 cookie.reset(CanonicalCookie::Create(url, "A=2; Path=/foo/bar", creation_time,
338 options));
339 EXPECT_FALSE(cookie->IncludeForRequestURL(url, options));
340 EXPECT_TRUE(cookie->IncludeForRequestURL(
341 GURL("http://www.example.com/foo/bar/index.html"), options));
343 // Test that a secure cookie is not included for a non secure URL.
344 GURL secure_url("https://www.example.com");
345 cookie.reset(CanonicalCookie::Create(secure_url, "A=2; Secure", creation_time,
346 options));
347 EXPECT_TRUE(cookie->IsSecure());
348 EXPECT_TRUE(cookie->IncludeForRequestURL(secure_url, options));
349 EXPECT_FALSE(cookie->IncludeForRequestURL(url, options));
351 // Test that http only cookies are only included if the include httponly flag
352 // is set on the cookie options.
353 options.set_include_httponly();
354 cookie.reset(
355 CanonicalCookie::Create(url, "A=2; HttpOnly", creation_time, options));
356 EXPECT_TRUE(cookie->IsHttpOnly());
357 EXPECT_TRUE(cookie->IncludeForRequestURL(url, options));
358 options.set_exclude_httponly();
359 EXPECT_FALSE(cookie->IncludeForRequestURL(url, options));
362 TEST(CanonicalCookieTest, IncludeFirstPartyForFirstPartyURL) {
363 GURL insecure_url("http://example.test");
364 GURL secure_url("https://example.test");
365 GURL secure_url_with_path("https://example.test/foo/bar/index.html");
366 GURL third_party_url("https://not-example.test");
367 base::Time creation_time = base::Time::Now();
368 CookieOptions options;
369 scoped_ptr<CanonicalCookie> cookie;
371 // First-party-only cookies are not inlcuded if a top-level URL is unset.
372 cookie.reset(CanonicalCookie::Create(secure_url, "A=2; First-Party-Only",
373 creation_time, options));
374 EXPECT_TRUE(cookie->IsFirstPartyOnly());
375 options.set_first_party_url(GURL());
376 EXPECT_FALSE(cookie->IncludeForRequestURL(secure_url, options));
378 // First-party-only cookies are included only if the cookie's origin matches
379 // the
380 // first-party origin.
381 options.set_first_party_url(secure_url);
382 EXPECT_TRUE(cookie->IncludeForRequestURL(secure_url, options));
383 options.set_first_party_url(insecure_url);
384 EXPECT_FALSE(cookie->IncludeForRequestURL(secure_url, options));
385 options.set_first_party_url(third_party_url);
386 EXPECT_FALSE(cookie->IncludeForRequestURL(secure_url, options));
388 // "First-Party-Only" doesn't override the 'secure' flag.
389 cookie.reset(CanonicalCookie::Create(
390 secure_url, "A=2; Secure; First-Party-Only", creation_time, options));
391 options.set_first_party_url(secure_url);
392 EXPECT_TRUE(cookie->IncludeForRequestURL(secure_url, options));
393 EXPECT_FALSE(cookie->IncludeForRequestURL(insecure_url, options));
394 options.set_first_party_url(insecure_url);
395 EXPECT_FALSE(cookie->IncludeForRequestURL(secure_url, options));
396 EXPECT_FALSE(cookie->IncludeForRequestURL(insecure_url, options));
398 // "First-Party-Only" doesn't override the 'path' flag.
399 cookie.reset(CanonicalCookie::Create(secure_url_with_path,
400 "A=2; First-Party-Only; path=/foo/bar",
401 creation_time, options));
402 options.set_first_party_url(secure_url_with_path);
403 EXPECT_TRUE(cookie->IncludeForRequestURL(secure_url_with_path, options));
404 EXPECT_FALSE(cookie->IncludeForRequestURL(secure_url, options));
405 options.set_first_party_url(secure_url);
406 EXPECT_TRUE(cookie->IncludeForRequestURL(secure_url_with_path, options));
407 EXPECT_FALSE(cookie->IncludeForRequestURL(secure_url, options));
410 TEST(CanonicalCookieTest, PartialCompare) {
411 GURL url("http://www.example.com");
412 base::Time creation_time = base::Time::Now();
413 CookieOptions options;
414 scoped_ptr<CanonicalCookie> cookie(
415 CanonicalCookie::Create(url, "a=b", creation_time, options));
416 scoped_ptr<CanonicalCookie> cookie_different_path(
417 CanonicalCookie::Create(url, "a=b; path=/foo", creation_time, options));
418 scoped_ptr<CanonicalCookie> cookie_different_value(
419 CanonicalCookie::Create(url, "a=c", creation_time, options));
421 // Cookie is equivalent to itself.
422 EXPECT_FALSE(cookie->PartialCompare(*cookie));
424 // Changing the path affects the ordering.
425 EXPECT_TRUE(cookie->PartialCompare(*cookie_different_path));
426 EXPECT_FALSE(cookie_different_path->PartialCompare(*cookie));
428 // Changing the value does not affect the ordering.
429 EXPECT_FALSE(cookie->PartialCompare(*cookie_different_value));
430 EXPECT_FALSE(cookie_different_value->PartialCompare(*cookie));
432 // Cookies identical for PartialCompare() are equivalent.
433 EXPECT_TRUE(cookie->IsEquivalent(*cookie_different_value));
434 EXPECT_TRUE(cookie->IsEquivalent(*cookie));
437 TEST(CanonicalCookieTest, FullCompare) {
438 GURL url("http://www.example.com");
439 base::Time creation_time = base::Time::Now();
440 CookieOptions options;
441 scoped_ptr<CanonicalCookie> cookie(
442 CanonicalCookie::Create(url, "a=b", creation_time, options));
443 scoped_ptr<CanonicalCookie> cookie_different_path(
444 CanonicalCookie::Create(url, "a=b; path=/foo", creation_time, options));
445 scoped_ptr<CanonicalCookie> cookie_different_value(
446 CanonicalCookie::Create(url, "a=c", creation_time, options));
448 // Cookie is equivalent to itself.
449 EXPECT_FALSE(cookie->FullCompare(*cookie));
451 // Changing the path affects the ordering.
452 EXPECT_TRUE(cookie->FullCompare(*cookie_different_path));
453 EXPECT_FALSE(cookie_different_path->FullCompare(*cookie));
455 // Changing the value affects the ordering.
456 EXPECT_TRUE(cookie->FullCompare(*cookie_different_value));
457 EXPECT_FALSE(cookie_different_value->FullCompare(*cookie));
459 // FullCompare() implies PartialCompare().
460 auto check_consistency =
461 [](const CanonicalCookie& a, const CanonicalCookie& b) {
462 if (a.FullCompare(b))
463 EXPECT_FALSE(b.PartialCompare(a));
464 else if (b.FullCompare(a))
465 EXPECT_FALSE(a.PartialCompare(b));
468 check_consistency(*cookie, *cookie_different_path);
469 check_consistency(*cookie, *cookie_different_value);
470 check_consistency(*cookie_different_path, *cookie_different_value);
473 } // namespace net