Index: lib/domain.js |
=================================================================== |
--- a/lib/domain.js |
+++ b/lib/domain.js |
@@ -15,16 +15,56 @@ |
* along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. |
*/ |
"use strict"; |
const publicSuffixes = require("../data/publicSuffixList.json"); |
/** |
+ * Map of public suffixes to their offsets. |
+ * @type {Map.<string,number>} |
+ */ |
+let publicSuffixMap = buildPublicSuffixMap(); |
+ |
+/** |
+ * Builds a map of public suffixes to their offsets. |
+ * @returns {Map.<string,number>} |
+ */ |
+function buildPublicSuffixMap() |
+{ |
+ let map = new Map(); |
+ |
+ for (let key in publicSuffixes) |
+ map.set(key, publicSuffixes[key]); |
+ |
+ return map; |
+} |
+ |
+/** |
+ * Yields all suffixes for a domain. For example, given the domain |
+ * <code>www.example.com</code>, this function yields |
+ * <code>www.example.com</code>, <code>example.com</code>, and |
+ * <code>com</code>, in that order. |
+ * |
+ * @param {string} domain The domain. |
+ * @yields {string} The next suffix for the domain. |
+ */ |
+function* suffixes(domain) |
+{ |
+ while (domain != "") |
+ { |
+ yield domain; |
+ |
+ let dotIndex = domain.indexOf("."); |
+ domain = dotIndex == -1 ? "" : domain.substr(dotIndex + 1); |
+ } |
+} |
+ |
+/** |
* Checks whether the given hostname is a domain. |
* |
* @param {string} hostname |
* @returns {boolean} |
*/ |
function isDomain(hostname) |
{ |
// No hostname or IPv4 address, also considering hexadecimal octets. |
@@ -39,48 +79,60 @@ |
/** |
* Gets the base domain for the given hostname. |
* |
* @param {string} hostname |
* @returns {string} |
*/ |
function getDomain(hostname) |
{ |
- let bits = hostname.split("."); |
- let cutoff = bits.length - 2; |
+ let slices = []; |
+ let cutoff = null; |
- for (let i = 0; i < bits.length; i++) |
+ for (let suffix of suffixes(hostname)) |
{ |
- let offset = publicSuffixes[bits.slice(i).join(".")]; |
+ slices.push(suffix); |
+ |
+ let offset = publicSuffixMap.get(suffix); |
if (typeof offset != "undefined") |
{ |
- cutoff = i - offset; |
+ cutoff = slices.length - 1 - offset; |
break; |
} |
} |
+ if (cutoff == null) |
+ return slices.length > 2 ? slices[slices.length - 2] : hostname; |
+ |
if (cutoff <= 0) |
return hostname; |
- return bits.slice(cutoff).join("."); |
+ return slices[cutoff]; |
} |
+exports.getDomain = getDomain; |
+ |
/** |
* Checks whether a request's origin is different from its document's origin. |
* |
* @param {URL} url The request URL. |
* @param {string} documentHostname The IDNA-encoded hostname of the document. |
* |
* @returns {boolean} |
*/ |
function isThirdParty(url, documentHostname) |
{ |
- let requestHostname = url.hostname.replace(/\.+$/, ""); |
- documentHostname = documentHostname.replace(/\.+$/, ""); |
+ let requestHostname = url.hostname; |
+ |
+ if (requestHostname[requestHostname.length - 1] == ".") |
+ requestHostname = requestHostname.replace(/\.+$/, ""); |
+ |
+ if (documentHostname[documentHostname.length - 1] == ".") |
+ documentHostname = documentHostname.replace(/\.+$/, ""); |
if (requestHostname == documentHostname) |
return false; |
if (!isDomain(requestHostname) || !isDomain(documentHostname)) |
return true; |
return getDomain(requestHostname) != getDomain(documentHostname); |