this fixes #1067 + partially fixes #1070

This commit is contained in:
gorhill 2015-12-15 10:40:40 -05:00
parent cfbefd096d
commit ea49484dd3
18 changed files with 264 additions and 117 deletions

View File

@ -824,7 +824,7 @@ vAPI.net.registerListeners = function() {
// something else. Test case for "unfriendly" font URLs:
// https://www.google.com/fonts
if ( details.type === 'object' ) {
if ( headerValue(details.responseHeaders, 'content-type').lastIndexOf('font/', 0) === 0 ) {
if ( headerValue(details.responseHeaders, 'content-type').startsWith('font/') ) {
details.type = 'font';
var r = onBeforeRequestClient(details);
if ( typeof r === 'object' && r.cancel === true ) {

View File

@ -2361,7 +2361,7 @@ vAPI.net.registerListeners = function() {
var tabId = tabWatcher.tabIdFromTarget(browser);
// Ignore notifications related to our popup
if ( details.url.lastIndexOf(vAPI.getURL('popup.html'), 0) === 0 ) {
if ( details.url.startsWith(vAPI.getURL('popup.html')) ) {
return;
}

View File

@ -8,6 +8,7 @@
<script src="lib/punycode.js"></script>
<script src="lib/publicsuffixlist.js"></script>
<script src="lib/yamd5.js"></script>
<script src="js/polyfill.js"></script>
<script src="js/vapi-common.js"></script>
<script src="js/vapi-background.js"></script>
<script src="js/background.js"></script>

View File

@ -312,7 +312,7 @@ var getTextFileFromURL = function(url, onLoad, onError) {
// appears to be a HTML document: could happen when server serves
// some kind of error page I suppose
var text = this.responseText.trim();
if ( text.charAt(0) === '<' && text.slice(-1) === '>' ) {
if ( text.startsWith('<') && text.endsWith('>') ) {
return onError.call(this);
}
return onLoad.call(this);

View File

@ -191,7 +191,7 @@ var FilterHostname = function(s, hostname) {
};
FilterHostname.prototype.retrieve = function(hostname, out) {
if ( hostname.slice(-this.hostname.length) === this.hostname ) {
if ( hostname.endsWith(this.hostname) ) {
out.push(this.s);
}
};
@ -219,7 +219,7 @@ var FilterEntity = function(s, entity) {
};
FilterEntity.prototype.retrieve = function(entity, out) {
if ( entity.slice(-this.entity.length) === this.entity ) {
if ( entity.endsWith(this.entity) ) {
out.push(this.s);
}
};
@ -244,7 +244,6 @@ var FilterParser = function() {
this.hostnames = [];
this.invalid = false;
this.cosmetic = true;
this.reScriptContains = /^script:contains\(.+?\)$/;
};
/******************************************************************************/
@ -321,7 +320,7 @@ FilterParser.prototype.parse = function(raw) {
// Cosmetic filters with explicit style properties can apply only:
// - to specific cosmetic filters (those which apply to a specific site)
// - to block cosmetic filters (not exception cosmetic filters)
if ( this.suffix.slice(-1) === '}' ) {
if ( this.suffix.endsWith('}') ) {
// Not supported for now: this code will ensure some backward
// compatibility for when cosmetic filters with explicit style
// properties start to be in use.
@ -341,7 +340,7 @@ FilterParser.prototype.parse = function(raw) {
// Normalize high-medium selectors: `href` is assumed to imply `a` tag. We
// need to do this here in order to correctly avoid duplicates. The test
// is designed to minimize overhead -- this is a low occurrence filter.
if ( this.suffix.charAt(1) === '[' && this.suffix.slice(2, 9) === 'href^="' ) {
if ( this.suffix.startsWith('[href^="', 1) ) {
this.suffix = this.suffix.slice(1);
}
@ -357,9 +356,9 @@ FilterParser.prototype.parse = function(raw) {
// Inline script tag filter?
if (
this.suffix.charAt(0) !== 's' ||
this.reScriptContains.test(this.suffix) === false )
{
this.suffix.startsWith('script:contains(') === false ||
this.suffix.endsWith(')') === false
) {
return this;
}
@ -370,17 +369,17 @@ FilterParser.prototype.parse = function(raw) {
return this;
}
var suffix = this.suffix;
var suffix = this.suffix.slice(16, -1);
this.suffix = 'script//:';
// Plain string-based?
if ( suffix.charAt(16) !== '/' || suffix.slice(-2) !== '/)' ) {
this.suffix += suffix.slice(16, -1).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
if ( suffix.startsWith('/') === false || suffix.endsWith('/') === false ) {
this.suffix += suffix.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
return this;
}
// Regex-based
this.suffix += suffix.slice(17, -2).replace(/\\/g, '\\');
this.suffix += suffix.slice(1, -1);
// Valid regex?
if ( isBadRegex(this.suffix) ) {
@ -687,7 +686,7 @@ FilterContainer.prototype.isValidSelector = (function() {
return true;
} catch (e) {
}
if ( s.lastIndexOf('script//:', 0) === 0 ) {
if ( s.startsWith('script//:') ) {
return true;
}
console.error('uBlock> invalid cosmetic filter:', s);
@ -730,10 +729,10 @@ FilterContainer.prototype.compile = function(s, out) {
var hostname;
while ( i-- ) {
hostname = hostnames[i];
if ( hostname.charAt(0) !== '~' ) {
if ( hostname.startsWith('~') === false ) {
applyGlobally = false;
}
if ( hostname.slice(-2) === '.*' ) {
if ( hostname.endsWith('.*') ) {
this.compileEntitySelector(hostname, parsed, out);
} else {
this.compileHostnameSelector(hostname, parsed, out);
@ -839,7 +838,7 @@ FilterContainer.prototype.reHighMedium = /^\[href\^="https?:\/\/([^"]{8})[^"]*"\
FilterContainer.prototype.compileHostnameSelector = function(hostname, parsed, out) {
// https://github.com/chrisaljoudi/uBlock/issues/145
var unhide = parsed.unhide;
if ( hostname.charAt(0) === '~' ) {
if ( hostname.startsWith('~') ) {
hostname = hostname.slice(1);
unhide ^= 1;
}
@ -915,7 +914,7 @@ FilterContainer.prototype.fromCompiledContent = function(text, lineBeg, skip) {
// h ir twitter.com .promoted-tweet
if ( fields[0] === 'h' ) {
// Special filter: script tags. Not a real CSS selector.
if ( fields[3].lastIndexOf('script//:', 0) === 0 ) {
if ( fields[3].startsWith('script//:') ) {
this.createScriptTagFilter(fields[2], fields[3].slice(9));
continue;
}
@ -951,7 +950,7 @@ FilterContainer.prototype.fromCompiledContent = function(text, lineBeg, skip) {
// entity selector
if ( fields[0] === 'e' ) {
// Special filter: script tags. Not a real CSS selector.
if ( fields[2].lastIndexOf('script//:', 0) === 0 ) {
if ( fields[2].startsWith('script//:') ) {
this.createScriptTagFilter(fields[1], fields[2].slice(9));
continue;
}
@ -1224,16 +1223,17 @@ FilterContainer.prototype.addToSelectorCache = function(details) {
/******************************************************************************/
FilterContainer.prototype.removeFromSelectorCache = function(targetHostname, type) {
var targetHostnameLength = targetHostname.length;
for ( var hostname in this.selectorCache ) {
if ( this.selectorCache.hasOwnProperty(hostname) === false ) {
continue;
}
if ( targetHostname !== '*' ) {
if ( hostname.slice(0 - targetHostname.length) !== targetHostname ) {
if ( hostname.endsWith(targetHostname) === false ) {
continue;
}
if ( hostname.length !== targetHostname.length &&
hostname.charAt(0 - targetHostname.length - 1) !== '.' ) {
if ( hostname.length !== targetHostnameLength &&
hostname.charAt(hostname.length - targetHostnameLength - 1) !== '.' ) {
continue;
}
}

View File

@ -89,7 +89,7 @@ var isIPAddress = function(hostname) {
if ( reIPv4VeryCoarse.test(hostname) ) {
return true;
}
return hostname.charAt(0) === '[';
return hostname.startsWith('[');
};
/******************************************************************************/
@ -325,7 +325,7 @@ var is3rdParty = function(srcHostname, desHostname) {
// etc.
var srcDomain = domainFromHostname(srcHostname) || srcHostname;
if ( desHostname.slice(0 - srcDomain.length) !== srcDomain ) {
if ( desHostname.endsWith(srcDomain) === false ) {
return true;
}
// Do not confuse 'example.com' with 'anotherexample.com'
@ -548,7 +548,7 @@ Matrix.prototype.fromString = function(text, append) {
// Ignore special rules:
// hostname-based switch rules
if ( fields[0].slice(-1) === ':' ) {
if ( fields[0].endsWith(':') ) {
continue;
}

View File

@ -80,7 +80,7 @@ var isIPAddress = function(hostname) {
if ( reIPv4VeryCoarse.test(hostname) ) {
return true;
}
return hostname.charAt(0) === '[';
return hostname.startsWith('[');
};
/******************************************************************************/
@ -177,7 +177,7 @@ HnSwitches.prototype.toggleBranchZ = function(switchName, targetHostname, newSta
if ( hostname.length <= targetLen ) {
continue;
}
if ( hostname.slice(-targetLen) !== targetHostname ) {
if ( hostname.endsWith(targetHostname) === false ) {
continue;
}
if ( hostname.charAt(hostname.length - targetLen - 1) !== '.' ) {

View File

@ -32,7 +32,7 @@
var showdomButton = uDom.nodeFromId('showdom');
// Don't bother if the browser is not modern enough.
if ( typeof Map === undefined || typeof WeakMap === undefined ) {
if ( typeof Map === undefined || Map.polyfill || typeof WeakMap === undefined ) {
showdomButton.classList.add('disabled');
return;
}

View File

@ -1287,7 +1287,7 @@ var onMessage = function(request, sender, callback) {
if ( pageStore === null ) {
continue;
}
if ( pageStore.rawURL.lastIndexOf(loggerURL, 0) === 0 ) {
if ( pageStore.rawURL.startsWith(loggerURL) ) {
continue;
}
tabIds[tabId] = pageStore.title;

146
src/js/polyfill.js Normal file
View File

@ -0,0 +1,146 @@
/*******************************************************************************
uBlock Origin - a browser extension to block requests.
Copyright (C) 2015 Raymond Hill
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
Home: https://github.com/gorhill/uBlock
*/
/******************************************************************************/
(function() {
'use strict';
/******************************************************************************/
// https://github.com/gorhill/uBlock/issues/1067
// https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith
// Firefox 17/Chromium 41 supports `startsWith`.
if ( String.prototype.startsWith instanceof Function === false ) {
String.prototype.startsWith = function(needle, pos) {
if ( typeof pos !== 'number' ) {
pos = 0;
}
return this.lastIndexOf(needle, pos) === pos;
};
}
// https://github.com/gorhill/uBlock/issues/1067
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/endsWith
// Firefox 17/Chromium 41 supports `endsWith`.
if ( String.prototype.endsWith instanceof Function === false ) {
String.prototype.endsWith = function(needle, pos) {
if ( typeof pos !== 'number' ) {
pos = this.length;
}
pos -= needle.length;
return this.indexOf(needle, pos) === pos;
};
}
/******************************************************************************/
// https://github.com/gorhill/uBlock/issues/1070
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set#Browser_compatibility
// This polyfill is designed to fulfill *only* what uBlock Origin needs -- this
// is not an accurate API of the real Set() type.
if ( typeof self.Set !== 'function' ) {
self.Set = function() {
this.clear();
};
self.Set.polyfill = true;
self.Set.prototype.clear = function() {
this._set = Object.create(null);
this.size = 0;
};
self.Set.prototype.add = function(k) {
if ( this._set[k] === undefined ) {
this._set[k] = true;
this.size += 1;
}
};
self.Set.prototype.delete = function(k) {
if ( this._set[k] !== undefined ) {
delete this._set[k];
this.size -= 1;
}
};
self.Set.prototype.has = function(k) {
return this._set[k] !== undefined;
};
}
/******************************************************************************/
// https://github.com/gorhill/uBlock/issues/1070
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set#Browser_compatibility
// This polyfill is designed to fulfill *only* what uBlock Origin needs -- this
// is not an accurate API of the real Map() type.
if ( typeof self.Map !== 'function' ) {
self.Map = function() {
this.clear();
};
self.Map.polyfill = true;
self.Map.prototype.clear = function() {
this._map = Object.create(null);
this.size = 0;
};
self.Map.prototype.delete = function(k) {
if ( this._map[k] !== undefined ) {
delete this._map[k];
this.size -= 1;
}
};
self.Map.prototype.get = function(k) {
return this._map[k];
};
self.Set.prototype.has = function(k) {
return this._map[k] !== undefined;
};
self.Map.prototype.set = function(k, v) {
if ( v !== undefined ) {
if ( this._map[k] === undefined ) {
this.size += 1;
}
this._map[k] = v;
} else {
if ( this._map[k] !== undefined ) {
this.size -= 1;
}
delete this._map[k];
}
};
}
/******************************************************************************/
})();

View File

@ -227,11 +227,11 @@ RedirectEngine.prototype.compileRuleFromStaticFilter = function(line) {
var srcs = [];
var options = matches[3].split(','), option;
while ( (option = options.pop()) ) {
if ( option.lastIndexOf('redirect=', 0) === 0 ) {
if ( option.startsWith('redirect=') ) {
redirect = option.slice(9);
continue;
}
if ( option.lastIndexOf('domain=', 0) === 0 ) {
if ( option.startsWith('domain=') ) {
srcs = option.slice(7).split('|');
continue;
}
@ -251,7 +251,7 @@ RedirectEngine.prototype.compileRuleFromStaticFilter = function(line) {
}
// Need one single type -- not negated.
if ( type === undefined || type.charAt(0) === '~' ) {
if ( type === undefined || type.startsWith('~') ) {
return;
}
@ -270,7 +270,7 @@ RedirectEngine.prototype.compileRuleFromStaticFilter = function(line) {
if ( src === '' ) {
continue;
}
if ( src.charAt(0) === '~' ) {
if ( src.startsWith('~') ) {
continue;
}
// Need at least one specific src or des.
@ -376,7 +376,7 @@ RedirectEngine.prototype.resourcesFromString = function(text) {
line = text.slice(lineBeg, lineEnd);
lineBeg = lineEnd + 1;
if ( line.charAt(0) === '#' ) {
if ( line.startsWith('#') ) {
continue;
}

View File

@ -99,7 +99,7 @@ var fromNetFilter = function(details) {
var fromCosmeticFilter = function(details) {
var filter = details.rawFilter;
var exception = filter.lastIndexOf('#@#', 0) === 0;
var exception = filter.startsWith('#@#');
filter = exception ? filter.slice(3) : filter.slice(2);

View File

@ -168,13 +168,11 @@ var atoi = function(s) {
return cachedParseInt(s, 10);
};
var isFirstParty = function(firstPartyDomain, hostname) {
if ( hostname.slice(0 - firstPartyDomain.length) !== firstPartyDomain ) {
return false;
}
var isFirstParty = function(domain, hostname) {
// Be sure to not confuse 'example.com' with 'anotherexample.com'
var c = hostname.charAt(hostname.length - firstPartyDomain.length - 1);
return c === '.' || c === '';
return hostname.endsWith(domain) &&
(hostname.length === domain.length ||
hostname.charAt(hostname.length - domain.length - 1) === '.');
};
var isBadRegex = function(s) {
@ -235,26 +233,25 @@ var hostnameTestPicker = function(owner) {
// Only one hostname
if ( domainOpt.indexOf('|') === -1 ) {
return domainOpt.charAt(0) !== '~' ? hostnameHitTest : hostnameMissTest;
return domainOpt.startsWith('~') ? hostnameMissTest : hostnameHitTest;
}
// Multiple hostnames: use a dictionary.
var dict = owner._hostnameDict = Object.create(null);
var hostnames = domainOpt.split('|');
var i, hostname;
var i, hostname, dict;
// First find out whether we have a homogeneous dictionary
var hit = false, miss = false;
i = hostnames.length;
while ( i-- ) {
if ( hostnames[i].charAt(0) !== '~' ) {
hit = true;
if ( miss ) {
if ( hostnames[i].startsWith('~') ) {
miss = true;
if ( hit ) {
break;
}
} else {
miss = true;
if ( hit ) {
hit = true;
if ( miss ) {
break;
}
}
@ -264,40 +261,44 @@ var hostnameTestPicker = function(owner) {
// Spotted one occurrence in EasyList Lite (cjxlist.txt):
// domain=photobucket.com|~secure.photobucket.com
if ( hit && miss ) {
dict = owner._hostnameDict = new Map();
i = hostnames.length;
while ( i-- ) {
hostname = hostnames[i];
if ( hostname.charAt(0) !== '~' ) {
dict[hostname] = true;
if ( hostname.startsWith('~') ) {
dict.set(hostname.slice(1), false);
} else {
dict[hostname.slice(1)] = false;
dict.set(hostname, true);
}
}
return hostnameMixedSetTest;
}
// Homogeneous dictionary.
dict = owner._hostnameDict = new Set();
i = hostnames.length;
while ( i-- ) {
hostname = hostnames[i];
if ( hostname.charAt(0) !== '~' ) {
dict[hostname] = true;
} else {
dict[hostname.slice(1)] = true;
}
dict.add(hostname.startsWith('~') ? hostname.slice(1) : hostname);
}
return hit ? hostnameHitSetTest : hostnameMissSetTest;
};
var hostnameHitTest = function(owner) {
var hostname = owner.domainOpt;
return pageHostnameRegister.slice(0 - hostname.length) === hostname;
var current = pageHostnameRegister;
var target = owner.domainOpt;
return current.endsWith(target) &&
(current.length === target.length ||
current.charAt(current.length - target.length - 1) === '.');
};
var hostnameMissTest = function(owner) {
var hostname = owner.domainOpt;
return pageHostnameRegister.slice(1 - hostname.length) !== hostname.slice(1);
var current = pageHostnameRegister;
var target = owner.domainOpt;
return current.endsWith(target) === false ||
(current.length !== target.length &&
current.charAt(current.length - target.length - 1) !== '.');
};
var hostnameHitSetTest = function(owner) {
@ -305,7 +306,7 @@ var hostnameHitSetTest = function(owner) {
var needle = pageHostnameRegister;
var pos;
for (;;) {
if ( dict[needle] ) {
if ( dict.has(needle) ) {
return true;
}
pos = needle.indexOf('.');
@ -322,7 +323,7 @@ var hostnameMissSetTest = function(owner) {
var needle = pageHostnameRegister;
var pos;
for (;;) {
if ( dict[needle] ) {
if ( dict.has(needle) ) {
return false;
}
pos = needle.indexOf('.');
@ -341,11 +342,11 @@ var hostnameMixedSetTest = function(owner) {
var hit = false;
var v, pos;
for (;;) {
v = dict[needle] || undefined;
v = dict.get(needle);
if ( v === false ) {
return false;
}
if ( v /* === true */ ) {
if ( v === true ) {
hit = true;
}
pos = needle.indexOf('.');
@ -393,7 +394,7 @@ var FilterPlain = function(s, tokenBeg) {
};
FilterPlain.prototype.match = function(url, tokenBeg) {
return url.substr(tokenBeg - this.tokenBeg, this.s.length) === this.s;
return url.startsWith(this.s, tokenBeg - this.tokenBeg);
};
FilterPlain.fid =
@ -424,8 +425,8 @@ var FilterPlainHostname = function(s, tokenBeg, domainOpt) {
};
FilterPlainHostname.prototype.match = function(url, tokenBeg) {
return this.hostnameTest(this) &&
url.substr(tokenBeg - this.tokenBeg, this.s.length) === this.s;
return url.startsWith(this.s, tokenBeg - this.tokenBeg) &&
this.hostnameTest(this);
};
FilterPlainHostname.fid =
@ -453,7 +454,7 @@ var FilterPlainPrefix0 = function(s) {
};
FilterPlainPrefix0.prototype.match = function(url, tokenBeg) {
return url.substr(tokenBeg, this.s.length) === this.s;
return url.startsWith(this.s, tokenBeg);
};
FilterPlainPrefix0.fid =
@ -482,8 +483,8 @@ var FilterPlainPrefix0Hostname = function(s, domainOpt) {
};
FilterPlainPrefix0Hostname.prototype.match = function(url, tokenBeg) {
return this.hostnameTest(this) &&
url.substr(tokenBeg, this.s.length) === this.s;
return url.startsWith(this.s, tokenBeg) &&
this.hostnameTest(this);
};
FilterPlainPrefix0Hostname.fid =
@ -511,7 +512,7 @@ var FilterPlainPrefix1 = function(s) {
};
FilterPlainPrefix1.prototype.match = function(url, tokenBeg) {
return url.substr(tokenBeg - 1, this.s.length) === this.s;
return url.startsWith(this.s, tokenBeg - 1);
};
FilterPlainPrefix1.fid =
@ -540,8 +541,8 @@ var FilterPlainPrefix1Hostname = function(s, domainOpt) {
};
FilterPlainPrefix1Hostname.prototype.match = function(url, tokenBeg) {
return this.hostnameTest(this) &&
url.substr(tokenBeg - 1, this.s.length) === this.s;
return url.startsWith(this.s, tokenBeg - 1) &&
this.hostnameTest(this);
};
FilterPlainPrefix1Hostname.fid =
@ -569,7 +570,7 @@ var FilterPlainLeftAnchored = function(s) {
};
FilterPlainLeftAnchored.prototype.match = function(url) {
return url.slice(0, this.s.length) === this.s;
return url.startsWith(this.s);
};
FilterPlainLeftAnchored.fid =
@ -598,8 +599,8 @@ var FilterPlainLeftAnchoredHostname = function(s, domainOpt) {
};
FilterPlainLeftAnchoredHostname.prototype.match = function(url) {
return this.hostnameTest(this) &&
url.slice(0, this.s.length) === this.s;
return url.startsWith(this.s) &&
this.hostnameTest(this);
};
FilterPlainLeftAnchoredHostname.fid =
@ -627,7 +628,7 @@ var FilterPlainRightAnchored = function(s) {
};
FilterPlainRightAnchored.prototype.match = function(url) {
return url.slice(-this.s.length) === this.s;
return url.endsWith(this.s);
};
FilterPlainRightAnchored.fid =
@ -656,8 +657,8 @@ var FilterPlainRightAnchoredHostname = function(s, domainOpt) {
};
FilterPlainRightAnchoredHostname.prototype.match = function(url) {
return this.hostnameTest(this) &&
url.slice(-this.s.length) === this.s;
return url.endsWith(this.s) &&
this.hostnameTest(this);
};
FilterPlainRightAnchoredHostname.fid =
@ -688,7 +689,7 @@ var FilterPlainHnAnchored = function(s) {
};
FilterPlainHnAnchored.prototype.match = function(url, tokenBeg) {
if ( url.substr(tokenBeg, this.s.length) !== this.s ) {
if ( url.startsWith(this.s, tokenBeg) === false ) {
return false;
}
// Valid only if hostname-valid characters to the left of token
@ -715,6 +716,7 @@ FilterPlainHnAnchored.fromSelfie = function(s) {
};
// https://www.youtube.com/watch?v=71YS6xDB-E4
// https://www.youtube.com/watch?v=qBPML7ton0E
/******************************************************************************/
@ -727,10 +729,10 @@ var FilterPlainHnAnchoredHostname = function(s, domainOpt) {
};
FilterPlainHnAnchoredHostname.prototype.match = function(url, tokenBeg) {
if ( this.hostnameTest(this) === false ) {
return false;
}
if ( url.substr(tokenBeg, this.s.length) !== this.s ) {
if (
url.startsWith(this.s, tokenBeg) === false ||
this.hostnameTest(this) === false
) {
return false;
}
// Valid only if hostname-valid characters to the left of token
@ -805,10 +807,8 @@ FilterGenericHostname.prototype = Object.create(FilterGeneric.prototype);
FilterGenericHostname.prototype.constructor = FilterGenericHostname;
FilterGenericHostname.prototype.match = function(url) {
if ( this.hostnameTest(this) === false ) {
return false;
}
return FilterGeneric.prototype.match.call(this, url);
return this.hostnameTest(this) &&
FilterGeneric.prototype.match.call(this, url);
};
FilterGenericHostname.fid =
@ -884,10 +884,8 @@ FilterGenericHnAnchoredHostname.prototype = Object.create(FilterGenericHnAnchore
FilterGenericHnAnchoredHostname.prototype.constructor = FilterGenericHnAnchoredHostname;
FilterGenericHnAnchoredHostname.prototype.match = function(url) {
if ( this.hostnameTest(this) === false ) {
return false;
}
return FilterGenericHnAnchored.prototype.match.call(this, url);
return this.hostnameTest(this) &&
FilterGenericHnAnchored.prototype.match.call(this, url);
};
FilterGenericHnAnchoredHostname.fid =
@ -1004,7 +1002,7 @@ FilterHostnameDict.prototype.cutoff = 250;
FilterHostnameDict.prototype.meltBucket = function(len, bucket) {
var map = {};
if ( bucket.charAt(0) === ' ' ) {
if ( bucket.startsWith(' ') ) {
bucket.trim().split(' ').map(function(k) {
map[k] = true;
});
@ -1105,7 +1103,7 @@ FilterHostnameDict.prototype.matchesExactly = function(hn) {
if ( typeof bucket === 'object' ) {
bucket = this.dict[key] = this.freezeBucket(bucket);
}
if ( bucket.charAt(0) === ' ' ) {
if ( bucket.startsWith(' ') ) {
return bucket.indexOf(' ' + hn + ' ') !== -1;
}
// binary search
@ -1379,7 +1377,7 @@ FilterParser.prototype.parseOptions = function(s) {
var opt, not;
for ( var i = 0; i < opts.length; i++ ) {
opt = opts[i];
not = opt.charAt(0) === '~';
not = opt.startsWith('~');
if ( not ) {
opt = opt.slice(1);
}
@ -1411,7 +1409,7 @@ FilterParser.prototype.parseOptions = function(s) {
this.parseOptType(opt, not);
continue;
}
if ( opt.lastIndexOf('domain=', 0) === 0 ) {
if ( opt.startsWith('domain=') ) {
this.domainOpt = opt.slice(7);
continue;
}
@ -1423,7 +1421,7 @@ FilterParser.prototype.parseOptions = function(s) {
this.parseOptParty(true, not);
continue;
}
if ( opt.lastIndexOf('redirect=', 0) === 0 ) {
if ( opt.startsWith('redirect=') ) {
if ( this.action === BlockAction ) {
this.redirect = true;
continue;
@ -1466,7 +1464,7 @@ FilterParser.prototype.parse = function(raw) {
// block or allow filter?
// Important: this must be executed before parsing options
if ( s.lastIndexOf('@@', 0) === 0 ) {
if ( s.startsWith('@@') ) {
this.action = AllowAction;
s = s.slice(2);
}
@ -1475,7 +1473,7 @@ FilterParser.prototype.parse = function(raw) {
// https://github.com/gorhill/uBlock/issues/842
// - ensure sure we are not dealing with a regex-based filter.
// - lookup the last occurrence of `$`.
if ( s.charAt(0) !== '/' || s.slice(-1) !== '/' ) {
if ( s.startsWith('/') === false || s.endsWith('/') === false ) {
pos = s.lastIndexOf('$');
if ( pos !== -1 ) {
// https://github.com/gorhill/uBlock/issues/952
@ -1490,7 +1488,7 @@ FilterParser.prototype.parse = function(raw) {
}
// regex?
if ( s.charAt(0) === '/' && s.slice(-1) === '/' && s.length > 2 ) {
if ( s.startsWith('/') && s.endsWith('/') && s.length > 2 ) {
this.isRegex = true;
this.f = s.slice(1, -1);
if ( isBadRegex(this.f) ) {
@ -1505,7 +1503,7 @@ FilterParser.prototype.parse = function(raw) {
}
// hostname-anchored
if ( s.lastIndexOf('||', 0) === 0 ) {
if ( s.startsWith('||') ) {
this.hostnameAnchored = true;
s = s.slice(2);
@ -1519,7 +1517,7 @@ FilterParser.prototype.parse = function(raw) {
}
// https://github.com/chrisaljoudi/uBlock/issues/1096
if ( s.charAt(0) === '^' ) {
if ( s.startsWith('^') ) {
this.unsupported = true;
return this;
}
@ -1533,13 +1531,13 @@ FilterParser.prototype.parse = function(raw) {
}
// left-anchored
if ( s.charAt(0) === '|' ) {
if ( s.startsWith('|') ) {
this.anchor = -1;
s = s.slice(1);
}
// right-anchored
if ( s.slice(-1) === '|' ) {
if ( s.endsWith('|') ) {
this.anchor = 1;
s = s.slice(0, -1);
}
@ -1547,11 +1545,11 @@ FilterParser.prototype.parse = function(raw) {
// normalize placeholders
if ( this.reHasWildcard.test(s) ) {
// remove pointless leading *
if ( s.charAt(0) === '*' ) {
if ( s.startsWith('*') ) {
s = s.replace(/^\*+([^%0-9a-z])/, '$1');
}
// remove pointless trailing *
if ( s.slice(-1) === '*' ) {
if ( s.endsWith('*') ) {
s = s.replace(/([^%0-9a-z])\*+$/, '$1');
}
}

View File

@ -125,7 +125,7 @@
// https://github.com/gorhill/uBlock/issues/277
// uBlock's filter lists are always enabled by default, so we
// have to include in backup only those which are turned off.
if ( path.lastIndexOf('assets/ublock/', 0) === 0 ) {
if ( path.startsWith('assets/ublock/') ) {
if ( entry.off !== true ) {
delete result[path];
}

View File

@ -453,7 +453,7 @@ vAPI.tabs.onNavigation = function(details) {
// TODO: Eventually, we will have to use an API to check whether a scheme
// is supported as I suspect we are going to start to see `ws`, `wss`
// as well soon.
if ( pageStore && tabContext.rawURL.lastIndexOf('http', 0) === 0 ) {
if ( pageStore && tabContext.rawURL.startsWith('http') ) {
pageStore.hostnameToCountMap[tabContext.rootHostname] = 0;
}
};
@ -618,7 +618,7 @@ vAPI.tabs.onPopupUpdated = (function() {
// If the page URL is that of our "blocked page" URL, extract the URL of
// the page which was blocked.
if ( targetURL.lastIndexOf(vAPI.getURL('document-blocked.html'), 0) === 0 ) {
if ( targetURL.startsWith(vAPI.getURL('document-blocked.html')) ) {
var matches = /details=([^&]+)/.exec(targetURL);
if ( matches !== null ) {
targetURL = JSON.parse(atob(matches[1])).url;

View File

@ -47,7 +47,9 @@ var isHandcraftedWhitelistDirective = function(directive) {
var matchWhitelistDirective = function(url, hostname, directive) {
// Directive is a plain hostname
if ( directive.indexOf('/') === -1 ) {
return hostname.slice(-directive.length) === directive;
return hostname.endsWith(directive) &&
(hostname.length === directive.length ||
hostname.charAt(hostname.length - directive.length - 1) === '.');
}
// Match URL exactly
if ( directive.indexOf('*') === -1 ) {
@ -187,7 +189,7 @@ var matchWhitelistDirective = function(url, hostname, directive) {
}
// Don't throw out commented out lines: user might want to fix them
if ( line.charAt(0) === '#' ) {
if ( line.startsWith('#') ) {
key = '#';
directive = line;
}

View File

@ -179,7 +179,7 @@ URI.set = function(uri) {
}
this.hostname = matches[1] !== undefined ? matches[1] : '';
// http://en.wikipedia.org/wiki/FQDN
if ( this.hostname.slice(-1) === '.' ) {
if ( this.hostname.endsWith('.') ) {
this.hostname = this.hostname.slice(0, -1);
}
this.port = matches[2] !== undefined ? matches[2].slice(1) : '';
@ -271,7 +271,7 @@ URI.hostnameFromURI = function(uri) {
}
// http://en.wikipedia.org/wiki/FQDN
var hostname = matches[1];
if ( hostname.slice(-1) === '.' ) {
if ( hostname.endsWith('.') ) {
hostname = hostname.slice(0, -1);
}
return hostname.toLowerCase();

View File

@ -92,7 +92,7 @@ var indexOfMatch = function(urls, url) {
if ( entry.url.length > urlLen ) {
continue;
}
if ( url.lastIndexOf(entry.url, 0) === 0 ) {
if ( url.startsWith(entry.url) ) {
return i;
}
}