1 /*
2 * Copyright 2015 The Netty Project
3 *
4 * The Netty Project licenses this file to you under the Apache License,
5 * version 2.0 (the "License"); you may not use this file except in compliance
6 * with the License. You may obtain a copy of the License at:
7 *
8 * https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations
14 * under the License.
15 */
16 package io.netty5.resolver;
17
18 import java.io.File;
19 import java.io.IOException;
20 import java.io.Reader;
21 import java.net.Inet4Address;
22 import java.net.Inet6Address;
23 import java.net.InetAddress;
24 import java.nio.charset.Charset;
25 import java.util.HashMap;
26 import java.util.List;
27 import java.util.Map;
28
29 /**
30 * A parser for hosts files.
31 * The produced mappings contain only the first entry per hostname.
32 * Consider using {@link HostsFileEntriesProvider} when mappings with all entries per hostname are needed.
33 */
34 public final class HostsFileParser {
35
36 /**
37 * Parse hosts file at standard OS location using the systems default {@link Charset} for decoding.
38 *
39 * @return a {@link HostsFileEntries}
40 */
41 public static HostsFileEntries parseSilently() {
42 return hostsFileEntries(HostsFileEntriesProvider.parser().parseSilently());
43 }
44
45 /**
46 * Parse hosts file at standard OS location using the given {@link Charset}s one after each other until
47 * we were able to parse something or none is left.
48 *
49 * @param charsets the {@link Charset}s to try as file encodings when parsing.
50 * @return a {@link HostsFileEntries}
51 */
52 public static HostsFileEntries parseSilently(Charset... charsets) {
53 return hostsFileEntries(HostsFileEntriesProvider.parser().parseSilently(charsets));
54 }
55
56 /**
57 * Parse hosts file at standard OS location using the system default {@link Charset} for decoding.
58 *
59 * @return a {@link HostsFileEntries}
60 * @throws IOException file could not be read
61 */
62 public static HostsFileEntries parse() throws IOException {
63 return hostsFileEntries(HostsFileEntriesProvider.parser().parse());
64 }
65
66 /**
67 * Parse a hosts file using the system default {@link Charset} for decoding.
68 *
69 * @param file the file to be parsed
70 * @return a {@link HostsFileEntries}
71 * @throws IOException file could not be read
72 */
73 public static HostsFileEntries parse(File file) throws IOException {
74 return hostsFileEntries(HostsFileEntriesProvider.parser().parse(file));
75 }
76
77 /**
78 * Parse a hosts file.
79 *
80 * @param file the file to be parsed
81 * @param charsets the {@link Charset}s to try as file encodings when parsing.
82 * @return a {@link HostsFileEntries}
83 * @throws IOException file could not be read
84 */
85 public static HostsFileEntries parse(File file, Charset... charsets) throws IOException {
86 return hostsFileEntries(HostsFileEntriesProvider.parser().parse(file, charsets));
87 }
88
89 /**
90 * Parse a reader of hosts file format.
91 *
92 * @param reader the file to be parsed
93 * @return a {@link HostsFileEntries}
94 * @throws IOException file could not be read
95 */
96 public static HostsFileEntries parse(Reader reader) throws IOException {
97 return hostsFileEntries(HostsFileEntriesProvider.parser().parse(reader));
98 }
99
100 /**
101 * Can't be instantiated.
102 */
103 private HostsFileParser() {
104 }
105
106 @SuppressWarnings("unchecked")
107 private static HostsFileEntries hostsFileEntries(HostsFileEntriesProvider provider) {
108 return provider == HostsFileEntriesProvider.EMPTY ? HostsFileEntries.EMPTY :
109 new HostsFileEntries((Map<String, Inet4Address>) toMapWithSingleValue(provider.ipv4Entries()),
110 (Map<String, Inet6Address>) toMapWithSingleValue(provider.ipv6Entries()));
111 }
112
113 private static Map<String, ?> toMapWithSingleValue(Map<String, List<InetAddress>> fromMapWithListValue) {
114 Map<String, InetAddress> result = new HashMap<>(fromMapWithListValue.size());
115 for (Map.Entry<String, List<InetAddress>> entry : fromMapWithListValue.entrySet()) {
116 List<InetAddress> value = entry.getValue();
117 if (!value.isEmpty()) {
118 result.put(entry.getKey(), value.get(0));
119 }
120 }
121 return result;
122 }
123 }