xref: /aosp_15_r20/external/cronet/net/dns/dns_hosts_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2012 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/dns/dns_hosts.h"
6 
7 #include "base/test/metrics/histogram_tester.h"
8 #include "base/trace_event/memory_usage_estimator.h"
9 #include "build/build_config.h"
10 #include "net/base/cronet_buildflags.h"
11 #include "net/base/ip_address.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13 
14 namespace net {
15 
16 namespace {
17 
18 struct ExpectedHostsEntry {
19   const char* host;
20   AddressFamily family;
21   const char* ip;
22 };
23 
PopulateExpectedHosts(const ExpectedHostsEntry * entries,size_t num_entries,DnsHosts * expected_hosts_out)24 void PopulateExpectedHosts(const ExpectedHostsEntry* entries,
25                            size_t num_entries,
26                            DnsHosts* expected_hosts_out) {
27   for (size_t i = 0; i < num_entries; ++i) {
28     DnsHostsKey key(entries[i].host, entries[i].family);
29     IPAddress& ip_ref = (*expected_hosts_out)[key];
30     ASSERT_TRUE(ip_ref.empty());
31     ASSERT_TRUE(ip_ref.AssignFromIPLiteral(entries[i].ip));
32     ASSERT_EQ(ip_ref.size(),
33         (entries[i].family == ADDRESS_FAMILY_IPV4) ? 4u : 16u);
34   }
35 }
36 
TEST(DnsHostsTest,ParseHosts)37 TEST(DnsHostsTest, ParseHosts) {
38   const std::string kContents =
39       "127.0.0.1       localhost # standard\n"
40       "\n"
41       "1.0.0.1 localhost # ignored, first hit above\n"
42       "fe00::x example company # ignored, malformed IPv6\n"
43       "1.0.0.300 company # ignored, malformed IPv4\n"
44       "1.0.0.1 # ignored, missing hostname\n"
45       "1.0.0.1\t CoMpANy # normalized to 'company' \n"
46       "::1\tlocalhost ip6-localhost ip6-loopback # comment # within a comment\n"
47       "\t fe00::0 ip6-localnet\r\n"
48       "2048::2 example\n"
49       "2048::1 company example # ignored for 'example' \n"
50       "127.0.0.1 cache1\n"
51       "127.0.0.1 cache2 # should reuse parsed IP\n"
52       "256.0.0.0 cache3 # bogus IP should not clear parsed IP cache\n"
53       "127.0.0.1 cache4 # should still be reused\n"
54       "127.0.0.2 cache5\n"
55       "127.0.0.3 .foo # entries with leading dot are ignored\n"
56       "127.0.0.3 . # just a dot is ignored\n"
57       "127.0.0.4 bar. # trailing dot is allowed, for now\n"
58       "gibberish\n"
59       "127.0.0.5 fóó.test # canonicalizes to 'xn--f-vgaa.test' due to RFC3490\n"
60       "127.0.0.6 127.0.0.1 # ignore IP host\n"
61       "2048::3 [::1] # ignore IP host";
62 
63   const ExpectedHostsEntry kEntries[] = {
64       {"localhost", ADDRESS_FAMILY_IPV4, "127.0.0.1"},
65       {"company", ADDRESS_FAMILY_IPV4, "1.0.0.1"},
66       {"localhost", ADDRESS_FAMILY_IPV6, "::1"},
67       {"ip6-localhost", ADDRESS_FAMILY_IPV6, "::1"},
68       {"ip6-loopback", ADDRESS_FAMILY_IPV6, "::1"},
69       {"ip6-localnet", ADDRESS_FAMILY_IPV6, "fe00::0"},
70       {"company", ADDRESS_FAMILY_IPV6, "2048::1"},
71       {"example", ADDRESS_FAMILY_IPV6, "2048::2"},
72       {"cache1", ADDRESS_FAMILY_IPV4, "127.0.0.1"},
73       {"cache2", ADDRESS_FAMILY_IPV4, "127.0.0.1"},
74       {"cache4", ADDRESS_FAMILY_IPV4, "127.0.0.1"},
75       {"cache5", ADDRESS_FAMILY_IPV4, "127.0.0.2"},
76       {"bar.", ADDRESS_FAMILY_IPV4, "127.0.0.4"},
77       {"xn--f-vgaa.test", ADDRESS_FAMILY_IPV4, "127.0.0.5"},
78   };
79 
80   DnsHosts expected_hosts, actual_hosts;
81   PopulateExpectedHosts(kEntries, std::size(kEntries), &expected_hosts);
82 
83   base::HistogramTester histograms;
84   ParseHosts(kContents, &actual_hosts);
85   ASSERT_EQ(expected_hosts, actual_hosts);
86   histograms.ExpectUniqueSample("Net.DNS.DnsHosts.Count", std::size(kEntries),
87                                 1);
88 #if !BUILDFLAG(CRONET_BUILD)
89   histograms.ExpectUniqueSample(
90       "Net.DNS.DnsHosts.EstimateMemoryUsage",
91       base::trace_event::EstimateMemoryUsage(actual_hosts), 1);
92 #endif
93 }
94 
TEST(DnsHostsTest,ParseHosts_CommaIsToken)95 TEST(DnsHostsTest, ParseHosts_CommaIsToken) {
96   const std::string kContents = "127.0.0.1 comma1,comma2";
97 
98   const ExpectedHostsEntry kEntries[] = {
99     { "comma1,comma2", ADDRESS_FAMILY_IPV4, "127.0.0.1" },
100   };
101 
102   DnsHosts expected_hosts, actual_hosts;
103   PopulateExpectedHosts(kEntries, std::size(kEntries), &expected_hosts);
104   ParseHostsWithCommaModeForTesting(
105       kContents, &actual_hosts, PARSE_HOSTS_COMMA_IS_TOKEN);
106   ASSERT_EQ(0UL, actual_hosts.size());
107 }
108 
TEST(DnsHostsTest,ParseHosts_CommaIsWhitespace)109 TEST(DnsHostsTest, ParseHosts_CommaIsWhitespace) {
110   std::string kContents = "127.0.0.1 comma1,comma2";
111 
112   const ExpectedHostsEntry kEntries[] = {
113     { "comma1", ADDRESS_FAMILY_IPV4, "127.0.0.1" },
114     { "comma2", ADDRESS_FAMILY_IPV4, "127.0.0.1" },
115   };
116 
117   DnsHosts expected_hosts, actual_hosts;
118   PopulateExpectedHosts(kEntries, std::size(kEntries), &expected_hosts);
119   ParseHostsWithCommaModeForTesting(
120       kContents, &actual_hosts, PARSE_HOSTS_COMMA_IS_WHITESPACE);
121   ASSERT_EQ(expected_hosts, actual_hosts);
122 }
123 
124 // Test that the right comma mode is used on each platform.
TEST(DnsHostsTest,ParseHosts_CommaModeByPlatform)125 TEST(DnsHostsTest, ParseHosts_CommaModeByPlatform) {
126   std::string kContents = "127.0.0.1 comma1,comma2";
127   DnsHosts actual_hosts;
128   ParseHosts(kContents, &actual_hosts);
129 
130 #if BUILDFLAG(IS_APPLE)
131   const ExpectedHostsEntry kEntries[] = {
132     { "comma1", ADDRESS_FAMILY_IPV4, "127.0.0.1" },
133     { "comma2", ADDRESS_FAMILY_IPV4, "127.0.0.1" },
134   };
135   DnsHosts expected_hosts;
136   PopulateExpectedHosts(kEntries, std::size(kEntries), &expected_hosts);
137   ASSERT_EQ(expected_hosts, actual_hosts);
138 #else
139   ASSERT_EQ(0UL, actual_hosts.size());
140 #endif
141 }
142 
TEST(DnsHostsTest,HostsParser_Empty)143 TEST(DnsHostsTest, HostsParser_Empty) {
144   DnsHosts hosts;
145   ParseHosts("", &hosts);
146   EXPECT_EQ(0u, hosts.size());
147 }
148 
TEST(DnsHostsTest,HostsParser_OnlyWhitespace)149 TEST(DnsHostsTest, HostsParser_OnlyWhitespace) {
150   DnsHosts hosts;
151   ParseHosts(" ", &hosts);
152   EXPECT_EQ(0u, hosts.size());
153 }
154 
TEST(DnsHostsTest,HostsParser_EndsWithNothing)155 TEST(DnsHostsTest, HostsParser_EndsWithNothing) {
156   DnsHosts hosts;
157   ParseHosts("127.0.0.1 localhost", &hosts);
158   EXPECT_EQ(1u, hosts.size());
159 }
160 
TEST(DnsHostsTest,HostsParser_EndsWithWhitespace)161 TEST(DnsHostsTest, HostsParser_EndsWithWhitespace) {
162   DnsHosts hosts;
163   ParseHosts("127.0.0.1 localhost ", &hosts);
164   EXPECT_EQ(1u, hosts.size());
165 }
166 
TEST(DnsHostsTest,HostsParser_EndsWithComment)167 TEST(DnsHostsTest, HostsParser_EndsWithComment) {
168   DnsHosts hosts;
169   ParseHosts("127.0.0.1 localhost # comment", &hosts);
170   EXPECT_EQ(1u, hosts.size());
171 }
172 
TEST(DnsHostsTest,HostsParser_EndsWithNewline)173 TEST(DnsHostsTest, HostsParser_EndsWithNewline) {
174   DnsHosts hosts;
175   ParseHosts("127.0.0.1 localhost\n", &hosts);
176   EXPECT_EQ(1u, hosts.size());
177 }
178 
TEST(DnsHostsTest,HostsParser_EndsWithTwoNewlines)179 TEST(DnsHostsTest, HostsParser_EndsWithTwoNewlines) {
180   DnsHosts hosts;
181   ParseHosts("127.0.0.1 localhost\n\n", &hosts);
182   EXPECT_EQ(1u, hosts.size());
183 }
184 
TEST(DnsHostsTest,HostsParser_EndsWithNewlineAndWhitespace)185 TEST(DnsHostsTest, HostsParser_EndsWithNewlineAndWhitespace) {
186   DnsHosts hosts;
187   ParseHosts("127.0.0.1 localhost\n ", &hosts);
188   EXPECT_EQ(1u, hosts.size());
189 }
190 
TEST(DnsHostsTest,HostsParser_EndsWithNewlineAndToken)191 TEST(DnsHostsTest, HostsParser_EndsWithNewlineAndToken) {
192   DnsHosts hosts;
193   ParseHosts("127.0.0.1 localhost\ntoken", &hosts);
194   EXPECT_EQ(1u, hosts.size());
195 }
196 
197 }  // namespace
198 
199 }  // namespace net
200