Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Unified Diff: lib/abp2blocklist.js

Issue 29452289: Issue 5283 - Add support for $websocket and $webrtc (Closed) Base URL: https://hg.adblockplus.org/abp2blocklist
Patch Set: Created May 31, 2017, 2:42 a.m.
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | node_modules/filterClasses.js » ('j') | node_modules/filterClasses.js » ('J')
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/abp2blocklist.js
===================================================================
--- a/lib/abp2blocklist.js
+++ b/lib/abp2blocklist.js
@@ -28,16 +28,18 @@
| typeMap.STYLESHEET
| typeMap.SCRIPT
| typeMap.FONT
| typeMap.MEDIA
| typeMap.POPUP
| typeMap.OBJECT
| typeMap.OBJECT_SUBREQUEST
| typeMap.XMLHTTPREQUEST
+ | typeMap.WEBSOCKET
+ | typeMap.WEBRTC
| typeMap.PING
| typeMap.SUBDOCUMENT
| typeMap.OTHER);
function parseDomains(domains, included, excluded)
{
for (let domain in domains)
{
@@ -59,16 +61,27 @@
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
function matchDomain(domain)
{
return "^https?://([^/:]*\\.)?" + escapeRegExp(domain).toLowerCase() + "[/:]";
}
+function getURLSchemes(contentType)
+{
+ if (contentType == typeMap.WEBSOCKET)
+ return ["wss?://"];
+
+ if (contentType == typeMap.WEBRTC)
+ return ["stuns?:", "turns?:"];
+
+ return ["https?://"];
+}
+
function findSubdomainsInList(domain, list)
{
let subdomains = [];
let suffixLength = domain.length + 1;
for (let name of list)
{
if (name.length > suffixLength && name.slice(-suffixLength) == "." + domain)
@@ -92,35 +105,39 @@
/**
* Parse the given filter "regexpSource" string. Producing a regular expression,
* extracting the hostname (if any), deciding if the regular expression is safe
* to be converted + matched as lower case and noting if the source contains
* anything after the hostname.)
*
* @param {string} text regexpSource property of a filter
+ * @param {string} urlScheme The URL scheme to use in the regular expression
* @returns {object} An object containing a regular expression string, a bool
* indicating if the filter can be safely matched as lower
* case, a hostname string (or undefined) and a bool
* indicating if the source only contains a hostname or not:
* {regexp: "...",
* canSafelyMatchAsLowercase: true/false,
* hostname: "...",
* justHostname: true/false}
*/
-function parseFilterRegexpSource(text)
+function parseFilterRegexpSource(text, urlScheme)
{
let regexp = [];
let lastIndex = text.length - 1;
let hostname;
let hostnameStart = null;
let hostnameFinished = false;
let justHostname = false;
let canSafelyMatchAsLowercase = false;
+ if (!urlScheme)
+ urlScheme = getURLSchemes()[0];
+
for (let i = 0; i < text.length; i++)
{
let c = text[i];
if (hostnameFinished)
justHostname = false;
// If we're currently inside the hostname we have to be careful not to
@@ -161,17 +178,17 @@
{
regexp.push("$");
break;
}
if (i == 1 && text[0] == "|")
{
hostnameStart = i + 1;
canSafelyMatchAsLowercase = true;
- regexp.push("https?://([^/]+\\.)?");
+ regexp.push(urlScheme + "([^/]+\\.)?");
break;
}
regexp.push("\\|");
break;
case "/":
if (!hostnameFinished &&
text.charAt(i-2) == ":" && text.charAt(i-1) == "/")
{
@@ -188,81 +205,97 @@
default:
if (hostnameFinished && (c >= "a" && c <= "z" ||
c >= "A" && c <= "Z"))
canSafelyMatchAsLowercase = false;
regexp.push(c);
}
}
+ if (regexp.length == 0 || regexp[0] != "^")
+ regexp.unshift("^" + urlScheme + ".*");
+
return {
regexp: regexp.join(""),
canSafelyMatchAsLowercase: canSafelyMatchAsLowercase,
hostname: hostname,
justHostname: justHostname
};
}
-function getResourceTypes(filter)
+function getResourceTypes(contentType)
{
let types = [];
- if (filter.contentType & typeMap.IMAGE)
+ if (contentType & typeMap.IMAGE)
types.push("image");
- if (filter.contentType & typeMap.STYLESHEET)
+ if (contentType & typeMap.STYLESHEET)
types.push("style-sheet");
- if (filter.contentType & typeMap.SCRIPT)
+ if (contentType & typeMap.SCRIPT)
types.push("script");
- if (filter.contentType & typeMap.FONT)
+ if (contentType & typeMap.FONT)
types.push("font");
- if (filter.contentType & (typeMap.MEDIA | typeMap.OBJECT))
+ if (contentType & (typeMap.MEDIA | typeMap.OBJECT))
types.push("media");
- if (filter.contentType & typeMap.POPUP)
+ if (contentType & typeMap.POPUP)
types.push("popup");
- if (filter.contentType & (typeMap.XMLHTTPREQUEST |
+ if (contentType & (typeMap.XMLHTTPREQUEST |
+ typeMap.WEBSOCKET |
+ typeMap.WEBRTC |
typeMap.OBJECT_SUBREQUEST |
typeMap.PING |
typeMap.OTHER))
+ {
types.push("raw");
- if (filter.contentType & typeMap.SUBDOCUMENT)
+ }
+ if (contentType & typeMap.SUBDOCUMENT)
types.push("document");
return types;
}
function convertFilterAddRules(rules, filter, action, withResourceTypes,
exceptionDomains)
{
- let parsed = parseFilterRegexpSource(filter.regexpSource);
+ let contentType = filter.contentType;
+
+ // Support WebSocket and WebRTC only if they're the only option. If we try to
+ // support them otherwise (e.g. $xmlhttprequest,websocket,webrtc), we end up
+ // having to generate multiple rules, which bloats the rule set and is not
+ // really necessary in practice.
+ if ((contentType & typeMap.WEBSOCKET && contentType != typeMap.WEBSOCKET) ||
+ (contentType & typeMap.WEBRTC && contentType != typeMap.WEBRTC))
+ {
+ contentType &= ~(typeMap.WEBSOCKET | typeMap.WEBRTC);
+ }
+
+ let urlSchemes = getURLSchemes(contentType);
+ let parsed = parseFilterRegexpSource(filter.regexpSource, urlSchemes[0]);
// For the special case of $document whitelisting filters with just a domain
// we can generate an equivalent blocking rule exception using if-domain.
if (filter instanceof filterClasses.WhitelistFilter &&
- filter.contentType & typeMap.DOCUMENT &&
+ contentType & typeMap.DOCUMENT &&
parsed.justHostname)
{
rules.push({
trigger: {
"url-filter": ".*",
"if-domain": ["*" + parsed.hostname]
},
action: {type: "ignore-previous-rules"}
});
// If the filter contains other supported options we'll need to generate
// further rules for it, but if not we can simply return now.
- if (!(filter.contentType & whitelistableRequestTypes))
+ if (!(contentType & whitelistableRequestTypes))
return;
}
let trigger = {"url-filter": parsed.regexp};
- // Limit rules to HTTP(S) URLs
Manish Jethani 2017/05/31 02:51:43 This has been moved into parseFilterRegexpSource.
- if (!/^(\^|http)/i.test(trigger["url-filter"]))
- trigger["url-filter"] = "^https?://.*" + trigger["url-filter"];
-
// For rules containing only a hostname we know that we're matching against
// a lowercase string unless the matchCase option was passed.
if (parsed.canSafelyMatchAsLowercase && !filter.matchCase)
trigger["url-filter"] = trigger["url-filter"].toLowerCase();
if (parsed.canSafelyMatchAsLowercase || filter.matchCase)
trigger["url-filter-is-case-sensitive"] = true;
@@ -271,17 +304,17 @@
parseDomains(filter.domains, included, excluded);
if (exceptionDomains)
excluded = excluded.concat(exceptionDomains);
if (withResourceTypes)
{
- trigger["resource-type"] = getResourceTypes(filter);
+ trigger["resource-type"] = getResourceTypes(contentType);
if (trigger["resource-type"].length == 0)
return;
}
if (filter.thirdParty != null)
trigger["load-type"] = [filter.thirdParty ? "third-party" : "first-party"];
@@ -311,16 +344,34 @@
}
}
else if (excluded.length > 0)
{
trigger["unless-domain"] = excluded.map(name => "*" + name);
}
rules.push({trigger: trigger, action: {type: action}});
+
+ // Generate additional rules for any alternative URL schemes.
+ if (urlSchemes.length > 1 &&
+ trigger["url-filter"].startsWith("^" + urlSchemes[0]))
+ {
+ // Always make a deep copy of the rule, since rules may have to be
+ // manipulated individually at a later stage.
+ let stringifiedTrigger = JSON.stringify(trigger);
+
+ for (let i = 1; i < urlSchemes.length; i++)
+ {
+ let altTrigger = Object.assign(JSON.parse(stringifiedTrigger), {
+ "url-filter": "^" + urlSchemes[i] +
+ trigger["url-filter"].substring(urlSchemes[0].length + 1)
+ });
+ rules.push({trigger: altTrigger, action: {type: action}});
+ }
+ }
}
function hasNonASCI(obj)
{
if (typeof obj == "string")
{
if (/[^\x00-\x7F]/.test(obj))
return true;
« no previous file with comments | « no previous file | node_modules/filterClasses.js » ('j') | node_modules/filterClasses.js » ('J')

Powered by Google App Engine
This is Rietveld