1 /* 2 * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.webkit.network; 27 28 import com.sun.javafx.logging.PlatformLogger; 29 import com.sun.javafx.logging.PlatformLogger.Level; 30 31 import java.io.BufferedReader; 32 import java.io.IOException; 33 import java.io.InputStream; 34 import java.io.InputStreamReader; 35 import java.net.IDN; 36 import java.util.Collections; 37 import java.util.LinkedHashMap; 38 import java.util.Map; 39 40 /** 41 * A collection of static utility methods dealing with "public suffixes". 42 */ 43 final class PublicSuffixes { 44 45 private static final PlatformLogger logger = 46 PlatformLogger.getLogger(PublicSuffixes.class.getName()); 47 48 49 /** 50 * Public suffix list rule types. 51 */ 52 private enum Rule { 53 SIMPLE_RULE, 54 WILDCARD_RULE, 55 EXCEPTION_RULE, 56 } 57 58 59 /** 60 * The mapping from domain names to public suffix list rules. 61 */ 62 private static final Map<String,Rule> RULES = 63 loadRules("effective_tld_names.dat"); 64 65 66 /** 67 * The private default constructor. Ensures non-instantiability. 68 */ 69 private PublicSuffixes() { 70 throw new AssertionError(); 71 } 72 73 74 /** 75 * Determines if a domain is a public suffix. 76 */ 77 static boolean isPublicSuffix(String domain) { 78 if (domain.length() == 0) { 79 return false; 80 } 81 Rule rule = RULES.get(domain); 82 if (rule == Rule.EXCEPTION_RULE) { 83 return false; 84 } else if (rule == Rule.SIMPLE_RULE || rule == Rule.WILDCARD_RULE) { 85 return true; 86 } else { 87 int pos = domain.indexOf('.') + 1; 88 if (pos == 0) { 89 pos = domain.length(); 90 } 91 String parent = domain.substring(pos); 92 return RULES.get(parent) == Rule.WILDCARD_RULE; 93 } 94 } 95 96 /** 97 * Loads the public suffix list from a given resource. 98 */ 99 private static Map<String,Rule> loadRules(String resourceName) { 100 logger.finest("resourceName: [{0}]", resourceName); 101 Map<String,Rule> result = null; 102 103 InputStream is = PublicSuffixes.class.getResourceAsStream(resourceName); 104 if (is != null) { 105 BufferedReader reader = null; 106 try { 107 reader = new BufferedReader(new InputStreamReader(is, "UTF-8")); 108 result = loadRules(reader); 109 } catch (IOException ex) { 110 logger.warning("Unexpected error", ex); 111 } finally { 112 try { 113 if (reader != null) { 114 reader.close(); 115 } 116 } catch (IOException ex) { 117 logger.warning("Unexpected error", ex); 118 } 119 } 120 } else { 121 logger.warning("Resource not found: [{0}]", 122 resourceName); 123 } 124 125 result = result != null 126 ? Collections.unmodifiableMap(result) 127 : Collections.<String,Rule>emptyMap(); 128 if (logger.isLoggable(Level.FINEST)) { 129 logger.finest("result: {0}", toLogString(result)); 130 } 131 return result; 132 } 133 134 /** 135 * Loads the public suffix list from a given reader. 136 */ 137 private static Map<String,Rule> loadRules(BufferedReader reader) 138 throws IOException 139 { 140 Map<String,Rule> result = new LinkedHashMap<String, Rule>(); 141 String line; 142 while ((line = reader.readLine()) != null) { 143 line = line.split("\\s+", 2)[0]; 144 if (line.length() == 0) { 145 continue; 146 } 147 if (line.startsWith("//")) { 148 continue; 149 } 150 Rule rule; 151 if (line.startsWith("!")) { 152 line = line.substring(1); 153 rule = Rule.EXCEPTION_RULE; 154 } else if (line.startsWith("*.")) { 155 line = line.substring(2); 156 rule = Rule.WILDCARD_RULE; 157 } else { 158 rule = Rule.SIMPLE_RULE; 159 } 160 try { 161 line = IDN.toASCII(line, IDN.ALLOW_UNASSIGNED); 162 } catch (Exception ex) { 163 logger.warning(String.format("Error parsing rule: [%s]", line), ex); 164 continue; 165 } 166 result.put(line, rule); 167 } 168 return result; 169 } 170 171 /** 172 * Converts a map of rules to a string suitable for displaying 173 * in the log. 174 */ 175 private static String toLogString(Map<String,Rule> rules) { 176 if (rules.isEmpty()) { 177 return "{}"; 178 } 179 StringBuilder sb = new StringBuilder(); 180 for (Map.Entry<String,Rule> entry : rules.entrySet()) { 181 sb.append(String.format("%n ")); 182 sb.append(entry.getKey()); 183 sb.append(": "); 184 sb.append(entry.getValue()); 185 } 186 return sb.toString(); 187 } 188 }