Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -179,13 +179,17 @@ private void put(URI uri, Cookie cookie) {
}
host = canonicalize(host);

if (PublicSuffixes.isPublicSuffix(cookie.getDomain())) {
if (cookie.getDomain().equals(host)) {
cookie.setDomain("");
} else {
logger.finest("Domain is public suffix, "
+ "ignoring cookie");
return;
if (!PublicSuffixes.pslFileExists()) {
cookie.setDomain("");
} else {
if (PublicSuffixes.isPublicSuffix(cookie.getDomain())) {
if (cookie.getDomain().equals(host)) {
cookie.setDomain("");
} else {
logger.finest("Domain is public suffix, "
+ "ignoring cookie");
return;
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,20 @@
import com.sun.javafx.logging.PlatformLogger.Level;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.IDN;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

/**
* A collection of static utility methods dealing with "public suffixes".
Expand All @@ -57,10 +64,30 @@ private enum Rule {


/**
* The mapping from domain names to public suffix list rules.
* The mapping from top-level domain names to public suffix list rules.
*/
private static final Map<String,Rule> RULES =
loadRules("effective_tld_names.dat");
private static final Map<String, Rules> rulesCache = new ConcurrentHashMap<>();


/**
* The public suffix list file.
*/
private static final File pslFile = AccessController.doPrivileged((PrivilegedAction<File>)
() -> new File(System.getProperty("java.home"), "lib/security/public_suffix_list.dat"));


/*
* Determines whether the public suffix list file is available.
*/
private static final boolean pslFileExists = AccessController.doPrivileged(
(PrivilegedAction<Boolean>) () -> {
if (!pslFile.exists()) {
logger.warning("Resource not found: " +
"lib/security/public_suffix_list.dat");
return false;
}
return true;
});


/**
Expand All @@ -71,101 +98,132 @@ private PublicSuffixes() {
}


/**
* Returns whether the public suffix list file is available.
*/
static boolean pslFileExists() {
return pslFileExists;
}


/**
* Determines if a domain is a public suffix.
*/
static boolean isPublicSuffix(String domain) {
if (domain.length() == 0) {
return false;
}
Rule rule = RULES.get(domain);
if (rule == Rule.EXCEPTION_RULE) {

if (!pslFileExists()) {
return false;
} else if (rule == Rule.SIMPLE_RULE || rule == Rule.WILDCARD_RULE) {
return true;
} else {
int pos = domain.indexOf('.') + 1;
if (pos == 0) {
pos = domain.length();
}
String parent = domain.substring(pos);
return RULES.get(parent) == Rule.WILDCARD_RULE;
}

Rules rules = Rules.getRules(domain);
return rules == null ? false : rules.match(domain);
}

/**
* Loads the public suffix list from a given resource.
*/
private static Map<String,Rule> loadRules(String resourceName) {
logger.finest("resourceName: [{0}]", resourceName);
Map<String,Rule> result = null;

InputStream is = PublicSuffixes.class.getResourceAsStream(resourceName);
if (is != null) {
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
result = loadRules(reader);
} catch (IOException ex) {
logger.warning("Unexpected error", ex);
} finally {
private static class Rules {

private final Map<String, Rule> rules = new HashMap<>();

private Rules(InputStream is) throws IOException {
InputStreamReader isr = new InputStreamReader(is, "UTF-8");
BufferedReader reader = new BufferedReader(isr);

String line;
int type = reader.read();
while (type != -1 && (line = reader.readLine()) != null) {
Rule rule;
if (line.startsWith("!")) {
line = line.substring(1);
rule = Rule.EXCEPTION_RULE;
} else if (line.startsWith("*.")) {
line = line.substring(2);
rule = Rule.WILDCARD_RULE;
} else {
rule = Rule.SIMPLE_RULE;
}
try {
if (reader != null) {
reader.close();
}
} catch (IOException ex) {
logger.warning("Unexpected error", ex);
line = IDN.toASCII(line, IDN.ALLOW_UNASSIGNED);
} catch (Exception ex) {
logger.warning(String.format("Error parsing rule: [%s]", line), ex);
continue;
}
rules.put(line, rule);
type = reader.read();
}
if (logger.isLoggable(Level.FINEST)) {
logger.finest("rules: {0}", toLogString(rules));
}
} else {
logger.warning("Resource not found: [{0}]",
resourceName);
}

result = result != null
? Collections.unmodifiableMap(result)
: Collections.<String,Rule>emptyMap();
if (logger.isLoggable(Level.FINEST)) {
logger.finest("result: {0}", toLogString(result));
static Rules getRules(String domain) {
String tld = getTopLevelDomain(domain);
if (tld.isEmpty()) {
return null;
}
return rulesCache.computeIfAbsent(tld, k -> createRules(tld));
}
return result;
}

/**
* Loads the public suffix list from a given reader.
*/
private static Map<String,Rule> loadRules(BufferedReader reader)
throws IOException
{
Map<String,Rule> result = new LinkedHashMap<String, Rule>();
String line;
while ((line = reader.readLine()) != null) {
line = line.split("\\s+", 2)[0];
if (line.length() == 0) {
continue;
private static String getTopLevelDomain(String domain) {
domain = IDN.toUnicode(domain, IDN.ALLOW_UNASSIGNED);
int n = domain.lastIndexOf('.');
if (n == -1) {
return domain;
}
if (line.startsWith("//")) {
continue;
return domain.substring(n + 1);
}

private static Rules createRules(String tld) {
try (InputStream pubSuffixStream = getPubSuffixStream()) {
if (pubSuffixStream == null) {
return null;
}
ZipInputStream zis = new ZipInputStream(pubSuffixStream);
ZipEntry ze = zis.getNextEntry();
while (ze != null) {
if (ze.getName().equals(tld)) {
return new Rules(zis);
} else {
ze = zis.getNextEntry();
}
}
} catch (IOException ex) {
logger.warning("Unexpected error", ex);
}
Rule rule;
if (line.startsWith("!")) {
line = line.substring(1);
rule = Rule.EXCEPTION_RULE;
} else if (line.startsWith("*.")) {
line = line.substring(2);
rule = Rule.WILDCARD_RULE;
return null;
}

private static InputStream getPubSuffixStream() {
InputStream is = AccessController.doPrivileged(
(PrivilegedAction<InputStream>) () -> {
try {
return new FileInputStream(pslFile);
} catch (FileNotFoundException ex) {
logger.warning("Resource not found: " +
"lib/security/public_suffix_list.dat");
return null;
}
}
);
return is;
}

boolean match(String domain) {
Rule rule = rules.get(domain);
if (rule == Rule.EXCEPTION_RULE) {
return false;
} else if (rule == Rule.SIMPLE_RULE || rule == Rule.WILDCARD_RULE) {
return true;
} else {
rule = Rule.SIMPLE_RULE;
}
try {
line = IDN.toASCII(line, IDN.ALLOW_UNASSIGNED);
} catch (Exception ex) {
logger.warning(String.format("Error parsing rule: [%s]", line), ex);
continue;
int pos = domain.indexOf('.') + 1;
if (pos == 0) {
pos = domain.length();
}
String parent = domain.substring(pos);
return rules.get(parent) == Rule.WILDCARD_RULE;
}
result.put(line, rule);
}
return result;
}

/**
Expand Down
Loading