xref: /aosp_15_r20/external/cronet/net/cookies/cookie_inclusion_status_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2020 The Chromium Authors
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 "net/cookies/cookie_inclusion_status.h"
6 
7 #include "testing/gtest/include/gtest/gtest.h"
8 
9 namespace net {
10 
TEST(CookieInclusionStatusTest,IncludeStatus)11 TEST(CookieInclusionStatusTest, IncludeStatus) {
12   int num_exclusion_reasons =
13       static_cast<int>(CookieInclusionStatus::NUM_EXCLUSION_REASONS);
14   int num_warning_reasons =
15       static_cast<int>(CookieInclusionStatus::NUM_WARNING_REASONS);
16   // Zero-argument constructor
17   CookieInclusionStatus status;
18   EXPECT_TRUE(status.IsInclude());
19   for (int i = 0; i < num_exclusion_reasons; ++i) {
20     EXPECT_FALSE(status.HasExclusionReason(
21         static_cast<CookieInclusionStatus::ExclusionReason>(i)));
22   }
23   for (int i = 0; i < num_warning_reasons; ++i) {
24     EXPECT_FALSE(status.HasWarningReason(
25         static_cast<CookieInclusionStatus::WarningReason>(i)));
26   }
27   EXPECT_FALSE(
28       status.HasExclusionReason(CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR));
29 }
30 
TEST(CookieInclusionStatusTest,ExcludeStatus)31 TEST(CookieInclusionStatusTest, ExcludeStatus) {
32   int num_exclusion_reasons =
33       static_cast<int>(CookieInclusionStatus::NUM_EXCLUSION_REASONS);
34   // Test exactly one exclusion reason and multiple (two) exclusion reasons.
35   for (int i = 0; i < num_exclusion_reasons; ++i) {
36     auto reason1 = static_cast<CookieInclusionStatus::ExclusionReason>(i);
37     if (reason1 != CookieInclusionStatus::EXCLUDE_THIRD_PARTY_PHASEOUT &&
38         reason1 != CookieInclusionStatus::
39                        EXCLUDE_THIRD_PARTY_BLOCKED_WITHIN_FIRST_PARTY_SET) {
40       continue;
41     }
42     CookieInclusionStatus status_one_reason(reason1);
43     EXPECT_FALSE(status_one_reason.IsInclude());
44     EXPECT_TRUE(status_one_reason.HasExclusionReason(reason1));
45     EXPECT_TRUE(status_one_reason.HasOnlyExclusionReason(reason1));
46 
47     for (int j = 0; j < num_exclusion_reasons; ++j) {
48       if (i == j)
49         continue;
50       auto reason2 = static_cast<CookieInclusionStatus::ExclusionReason>(j);
51       if (reason2 != CookieInclusionStatus::EXCLUDE_THIRD_PARTY_PHASEOUT &&
52           reason2 != CookieInclusionStatus::
53                          EXCLUDE_THIRD_PARTY_BLOCKED_WITHIN_FIRST_PARTY_SET) {
54         continue;
55       }
56       EXPECT_FALSE(status_one_reason.HasExclusionReason(reason2));
57       EXPECT_FALSE(status_one_reason.HasOnlyExclusionReason(reason2));
58 
59       CookieInclusionStatus status_two_reasons = status_one_reason;
60       status_two_reasons.AddExclusionReason(reason2);
61       EXPECT_FALSE(status_two_reasons.IsInclude());
62 
63       if (reason1 != CookieInclusionStatus::EXCLUDE_THIRD_PARTY_PHASEOUT &&
64           reason2 != CookieInclusionStatus::EXCLUDE_THIRD_PARTY_PHASEOUT) {
65         EXPECT_TRUE(status_two_reasons.HasExclusionReason(reason1));
66         EXPECT_TRUE(status_two_reasons.HasExclusionReason(reason2));
67       }
68     }
69   }
70 }
71 
TEST(CookieInclusionStatusTest,ExcludeStatus_MaybeClearThirdPartyPhaseoutReason)72 TEST(CookieInclusionStatusTest,
73      ExcludeStatus_MaybeClearThirdPartyPhaseoutReason) {
74   int num_exclusion_reasons =
75       static_cast<int>(CookieInclusionStatus::NUM_EXCLUSION_REASONS);
76   CookieInclusionStatus::ExclusionReason reason1 =
77       CookieInclusionStatus::EXCLUDE_THIRD_PARTY_PHASEOUT;
78   const CookieInclusionStatus status_one_reason(reason1);
79   ASSERT_FALSE(status_one_reason.IsInclude());
80   ASSERT_TRUE(status_one_reason.HasOnlyExclusionReason(reason1));
81 
82   for (int j = 0; j < num_exclusion_reasons; ++j) {
83     auto reason2 = static_cast<CookieInclusionStatus::ExclusionReason>(j);
84     if (reason1 == reason2) {
85       continue;
86     }
87     EXPECT_FALSE(status_one_reason.HasExclusionReason(reason2)) << reason2;
88 
89     CookieInclusionStatus status_two_reasons = status_one_reason;
90     status_two_reasons.AddExclusionReason(reason2);
91     EXPECT_FALSE(status_two_reasons.IsInclude());
92 
93     if (reason2 == CookieInclusionStatus::
94                        EXCLUDE_THIRD_PARTY_BLOCKED_WITHIN_FIRST_PARTY_SET) {
95       EXPECT_TRUE(status_two_reasons.HasExclusionReason(reason1));
96       EXPECT_TRUE(status_two_reasons.HasExclusionReason(reason2));
97     } else {
98       EXPECT_TRUE(status_two_reasons.HasOnlyExclusionReason(reason2));
99     }
100   }
101 }
102 
TEST(CookieInclusionStatusTest,AddExclusionReason_MaybeClearThirdPartyPhaseoutReason)103 TEST(CookieInclusionStatusTest,
104      AddExclusionReason_MaybeClearThirdPartyPhaseoutReason) {
105   CookieInclusionStatus status;
106   status.AddWarningReason(CookieInclusionStatus::WARN_THIRD_PARTY_PHASEOUT);
107   ASSERT_TRUE(status.ShouldWarn());
108   ASSERT_TRUE(status.HasExactlyWarningReasonsForTesting(
109       {CookieInclusionStatus::WARN_THIRD_PARTY_PHASEOUT}));
110   // Adding an exclusion reason should clear 3PCD warning reason.
111   status.AddExclusionReason(
112       CookieInclusionStatus::EXCLUDE_THIRD_PARTY_PHASEOUT);
113   EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
114       {CookieInclusionStatus::EXCLUDE_THIRD_PARTY_PHASEOUT}));
115   EXPECT_FALSE(status.ShouldWarn());
116 
117   status.AddExclusionReason(
118       CookieInclusionStatus::
119           EXCLUDE_THIRD_PARTY_BLOCKED_WITHIN_FIRST_PARTY_SET);
120   EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
121       {CookieInclusionStatus::EXCLUDE_THIRD_PARTY_PHASEOUT,
122        CookieInclusionStatus::
123            EXCLUDE_THIRD_PARTY_BLOCKED_WITHIN_FIRST_PARTY_SET}));
124   // Adding an exclusion reason unrelated with 3PCD should clear 3PCD related
125   // exclusion reasons.
126   status.AddExclusionReason(
127       CookieInclusionStatus::EXCLUDE_SAMESITE_NONE_INSECURE);
128   EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
129       {CookieInclusionStatus::EXCLUDE_SAMESITE_NONE_INSECURE}));
130   EXPECT_FALSE(status.IsInclude());
131 }
132 
TEST(CookieInclusionStatusTest,AddExclusionReason)133 TEST(CookieInclusionStatusTest, AddExclusionReason) {
134   CookieInclusionStatus status;
135   status.AddWarningReason(
136       CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE);
137   status.AddExclusionReason(CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR);
138   EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
139       {CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR}));
140   // Adding an exclusion reason other than
141   // EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX or
142   // EXCLUDE_SAMESITE_NONE_INSECURE should clear any SameSite warning.
143   EXPECT_FALSE(status.ShouldWarn());
144 
145   status = CookieInclusionStatus();
146   status.AddWarningReason(
147       CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT);
148   status.AddExclusionReason(
149       CookieInclusionStatus::EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX);
150   EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
151       {CookieInclusionStatus::EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX}));
152   EXPECT_TRUE(status.HasExactlyWarningReasonsForTesting(
153       {CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT}));
154 }
155 
TEST(CookieInclusionStatusTest,ExemptionReason)156 TEST(CookieInclusionStatusTest, ExemptionReason) {
157   CookieInclusionStatus status;
158   status.MaybeSetExemptionReason(
159       CookieInclusionStatus::ExemptionReason::k3PCDMetadata);
160   ASSERT_EQ(status.exemption_reason(),
161             CookieInclusionStatus::ExemptionReason::k3PCDMetadata);
162   ASSERT_TRUE(status.IsInclude());
163   ASSERT_EQ(status.GetDebugString(),
164             "INCLUDE, DO_NOT_WARN, Exemption3PCDMetadata");
165 
166   // Updating exemption reason would be no-op.
167   status.MaybeSetExemptionReason(
168       CookieInclusionStatus::ExemptionReason::kEnterprisePolicy);
169   EXPECT_EQ(status.exemption_reason(),
170             CookieInclusionStatus::ExemptionReason::k3PCDMetadata);
171 
172   // Adding an exclusion reason resets the exemption reason.
173   status.AddExclusionReason(CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR);
174   EXPECT_EQ(status.exemption_reason(),
175             CookieInclusionStatus::ExemptionReason::kNone);
176 
177   // Setting exemption reason when the cookie is already excluded would be
178   // no-op.
179   status.MaybeSetExemptionReason(
180       CookieInclusionStatus::ExemptionReason::kEnterprisePolicy);
181   EXPECT_EQ(status.exemption_reason(),
182             CookieInclusionStatus::ExemptionReason::kNone);
183 }
184 
TEST(CookieInclusionStatusTest,CheckEachWarningReason)185 TEST(CookieInclusionStatusTest, CheckEachWarningReason) {
186   CookieInclusionStatus status;
187 
188   int num_warning_reasons =
189       static_cast<int>(CookieInclusionStatus::NUM_WARNING_REASONS);
190   EXPECT_FALSE(status.ShouldWarn());
191   for (int i = 0; i < num_warning_reasons; ++i) {
192     auto reason = static_cast<CookieInclusionStatus::WarningReason>(i);
193     status.AddWarningReason(reason);
194     EXPECT_TRUE(status.IsInclude());
195     EXPECT_TRUE(status.ShouldWarn());
196     EXPECT_TRUE(status.HasWarningReason(reason));
197     for (int j = 0; j < num_warning_reasons; ++j) {
198       if (i == j)
199         continue;
200       EXPECT_FALSE(status.HasWarningReason(
201           static_cast<CookieInclusionStatus::WarningReason>(j)));
202     }
203     status.RemoveWarningReason(reason);
204     EXPECT_FALSE(status.ShouldWarn());
205   }
206 }
207 
TEST(CookieInclusionStatusTest,RemoveExclusionReason)208 TEST(CookieInclusionStatusTest, RemoveExclusionReason) {
209   CookieInclusionStatus status(CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR);
210   ASSERT_TRUE(
211       status.HasExclusionReason(CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR));
212 
213   status.RemoveExclusionReason(CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR);
214   EXPECT_FALSE(
215       status.HasExclusionReason(CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR));
216 
217   // Removing a nonexistent exclusion reason doesn't do anything.
218   ASSERT_FALSE(
219       status.HasExclusionReason(CookieInclusionStatus::NUM_EXCLUSION_REASONS));
220   status.RemoveExclusionReason(CookieInclusionStatus::NUM_EXCLUSION_REASONS);
221   EXPECT_FALSE(
222       status.HasExclusionReason(CookieInclusionStatus::NUM_EXCLUSION_REASONS));
223 }
224 
TEST(CookieInclusionStatusTest,RemoveWarningReason)225 TEST(CookieInclusionStatusTest, RemoveWarningReason) {
226   CookieInclusionStatus status(
227       CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR,
228       CookieInclusionStatus::WARN_SAMESITE_NONE_INSECURE);
229   EXPECT_TRUE(status.ShouldWarn());
230   ASSERT_TRUE(status.HasWarningReason(
231       CookieInclusionStatus::WARN_SAMESITE_NONE_INSECURE));
232 
233   status.RemoveWarningReason(
234       CookieInclusionStatus::WARN_SAMESITE_NONE_INSECURE);
235   EXPECT_FALSE(status.ShouldWarn());
236   EXPECT_FALSE(status.HasWarningReason(
237       CookieInclusionStatus::WARN_SAMESITE_NONE_INSECURE));
238 
239   // Removing a nonexistent warning reason doesn't do anything.
240   ASSERT_FALSE(status.HasWarningReason(
241       CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT));
242   status.RemoveWarningReason(
243       CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT);
244   EXPECT_FALSE(status.ShouldWarn());
245   EXPECT_FALSE(status.HasWarningReason(
246       CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT));
247 }
248 
TEST(CookieInclusionStatusTest,HasSchemefulDowngradeWarning)249 TEST(CookieInclusionStatusTest, HasSchemefulDowngradeWarning) {
250   std::vector<CookieInclusionStatus::WarningReason> downgrade_warnings = {
251       CookieInclusionStatus::WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE,
252       CookieInclusionStatus::WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE,
253       CookieInclusionStatus::WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE,
254       CookieInclusionStatus::WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE,
255       CookieInclusionStatus::WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE,
256   };
257 
258   CookieInclusionStatus empty_status;
259   EXPECT_FALSE(empty_status.HasSchemefulDowngradeWarning());
260 
261   CookieInclusionStatus not_downgrade;
262   not_downgrade.AddWarningReason(
263       CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT);
264   EXPECT_FALSE(not_downgrade.HasSchemefulDowngradeWarning());
265 
266   for (auto warning : downgrade_warnings) {
267     CookieInclusionStatus status;
268     status.AddWarningReason(warning);
269     CookieInclusionStatus::WarningReason reason;
270 
271     EXPECT_TRUE(status.HasSchemefulDowngradeWarning(&reason));
272     EXPECT_EQ(warning, reason);
273   }
274 }
275 
TEST(CookieInclusionStatusTest,ShouldRecordDowngradeMetrics)276 TEST(CookieInclusionStatusTest, ShouldRecordDowngradeMetrics) {
277   EXPECT_TRUE(CookieInclusionStatus::MakeFromReasonsForTesting({})
278                   .ShouldRecordDowngradeMetrics());
279 
280   EXPECT_TRUE(CookieInclusionStatus::MakeFromReasonsForTesting(
281                   {
282                       CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT,
283                   })
284                   .ShouldRecordDowngradeMetrics());
285 
286   EXPECT_TRUE(CookieInclusionStatus::MakeFromReasonsForTesting(
287                   {
288                       CookieInclusionStatus::EXCLUDE_SAMESITE_LAX,
289                   })
290                   .ShouldRecordDowngradeMetrics());
291 
292   EXPECT_TRUE(CookieInclusionStatus::MakeFromReasonsForTesting(
293                   {
294                       CookieInclusionStatus::
295                           EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX,
296                   })
297                   .ShouldRecordDowngradeMetrics());
298 
299   // Note: the following cases cannot occur under normal circumstances.
300   EXPECT_TRUE(CookieInclusionStatus::MakeFromReasonsForTesting(
301                   {
302                       CookieInclusionStatus::
303                           EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX,
304                       CookieInclusionStatus::EXCLUDE_SAMESITE_LAX,
305                   })
306                   .ShouldRecordDowngradeMetrics());
307   EXPECT_FALSE(CookieInclusionStatus::MakeFromReasonsForTesting(
308                    {
309                        CookieInclusionStatus::EXCLUDE_SAMESITE_NONE_INSECURE,
310                        CookieInclusionStatus::EXCLUDE_SAMESITE_LAX,
311                    })
312                    .ShouldRecordDowngradeMetrics());
313 }
314 
TEST(CookieInclusionStatusTest,RemoveExclusionReasons)315 TEST(CookieInclusionStatusTest, RemoveExclusionReasons) {
316   CookieInclusionStatus status =
317       CookieInclusionStatus::MakeFromReasonsForTesting({
318           CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR,
319           CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT,
320           CookieInclusionStatus::EXCLUDE_USER_PREFERENCES,
321       });
322   ASSERT_TRUE(status.HasExactlyExclusionReasonsForTesting({
323       CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR,
324       CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT,
325       CookieInclusionStatus::EXCLUDE_USER_PREFERENCES,
326   }));
327 
328   status.RemoveExclusionReasons(
329       {CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR,
330        CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR,
331        CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT});
332   EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting({
333       CookieInclusionStatus::EXCLUDE_USER_PREFERENCES,
334   }));
335 
336   // Removing a nonexistent exclusion reason doesn't do anything.
337   ASSERT_FALSE(
338       status.HasExclusionReason(CookieInclusionStatus::NUM_EXCLUSION_REASONS));
339   status.RemoveExclusionReasons({CookieInclusionStatus::NUM_EXCLUSION_REASONS});
340   EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting({
341       CookieInclusionStatus::EXCLUDE_USER_PREFERENCES,
342   }));
343 }
344 
TEST(CookieInclusionStatusTest,ValidateExclusionAndWarningFromWire)345 TEST(CookieInclusionStatusTest, ValidateExclusionAndWarningFromWire) {
346   uint32_t exclusion_reasons = 0ul;
347   uint32_t warning_reasons = 0ul;
348 
349   EXPECT_TRUE(CookieInclusionStatus::ValidateExclusionAndWarningFromWire(
350       exclusion_reasons, warning_reasons));
351 
352   exclusion_reasons = static_cast<uint32_t>(~0ul);
353   warning_reasons = static_cast<uint32_t>(~0ul);
354   EXPECT_FALSE(CookieInclusionStatus::ValidateExclusionAndWarningFromWire(
355       exclusion_reasons, warning_reasons));
356   EXPECT_FALSE(CookieInclusionStatus::ValidateExclusionAndWarningFromWire(
357       exclusion_reasons, 0u));
358   EXPECT_FALSE(CookieInclusionStatus::ValidateExclusionAndWarningFromWire(
359       0u, warning_reasons));
360 
361   exclusion_reasons = (1u << CookieInclusionStatus::EXCLUDE_DOMAIN_MISMATCH);
362   warning_reasons = (1u << CookieInclusionStatus::WARN_PORT_MISMATCH);
363   EXPECT_TRUE(CookieInclusionStatus::ValidateExclusionAndWarningFromWire(
364       exclusion_reasons, warning_reasons));
365 
366   exclusion_reasons = (1u << CookieInclusionStatus::NUM_EXCLUSION_REASONS);
367   warning_reasons = (1u << CookieInclusionStatus::NUM_WARNING_REASONS);
368   EXPECT_FALSE(CookieInclusionStatus::ValidateExclusionAndWarningFromWire(
369       exclusion_reasons, warning_reasons));
370 
371   exclusion_reasons =
372       (1u << (CookieInclusionStatus::NUM_EXCLUSION_REASONS - 1));
373   warning_reasons = (1u << (CookieInclusionStatus::NUM_WARNING_REASONS - 1));
374   EXPECT_TRUE(CookieInclusionStatus::ValidateExclusionAndWarningFromWire(
375       exclusion_reasons, warning_reasons));
376 }
377 
TEST(CookieInclusionStatusTest,ExcludedByUserPreferencesOrTPCD)378 TEST(CookieInclusionStatusTest, ExcludedByUserPreferencesOrTPCD) {
379   CookieInclusionStatus status =
380       CookieInclusionStatus::MakeFromReasonsForTesting(
381           {CookieInclusionStatus::ExclusionReason::EXCLUDE_USER_PREFERENCES});
382   EXPECT_TRUE(status.ExcludedByUserPreferencesOrTPCD());
383 
384   status = CookieInclusionStatus::MakeFromReasonsForTesting({
385       CookieInclusionStatus::ExclusionReason::EXCLUDE_THIRD_PARTY_PHASEOUT,
386   });
387   EXPECT_TRUE(status.ExcludedByUserPreferencesOrTPCD());
388 
389   status = CookieInclusionStatus::MakeFromReasonsForTesting({
390       CookieInclusionStatus::ExclusionReason::EXCLUDE_THIRD_PARTY_PHASEOUT,
391       CookieInclusionStatus::ExclusionReason::
392           EXCLUDE_THIRD_PARTY_BLOCKED_WITHIN_FIRST_PARTY_SET,
393   });
394   EXPECT_TRUE(status.ExcludedByUserPreferencesOrTPCD());
395 
396   status = CookieInclusionStatus::MakeFromReasonsForTesting({
397       CookieInclusionStatus::ExclusionReason::EXCLUDE_USER_PREFERENCES,
398       CookieInclusionStatus::ExclusionReason::EXCLUDE_FAILURE_TO_STORE,
399   });
400   EXPECT_FALSE(status.ExcludedByUserPreferencesOrTPCD());
401 
402   status = CookieInclusionStatus::MakeFromReasonsForTesting({
403       CookieInclusionStatus::ExclusionReason::
404           EXCLUDE_THIRD_PARTY_BLOCKED_WITHIN_FIRST_PARTY_SET,
405   });
406   EXPECT_FALSE(status.ExcludedByUserPreferencesOrTPCD());
407 
408   status = CookieInclusionStatus::MakeFromReasonsForTesting({
409       CookieInclusionStatus::ExclusionReason::EXCLUDE_FAILURE_TO_STORE,
410   });
411   EXPECT_FALSE(status.ExcludedByUserPreferencesOrTPCD());
412 }
413 
414 }  // namespace net
415