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