| 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 = NaN; |
| - 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 (isNaN(cutoff)) |
| + 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); |