Skip to content

Commit ea49484

Browse files
committed
this fixes gorhill#1067 + partially fixes gorhill#1070
1 parent cfbefd0 commit ea49484

18 files changed

Lines changed: 264 additions & 117 deletions

platform/chromium/vapi-background.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -824,7 +824,7 @@ vAPI.net.registerListeners = function() {
824824
// something else. Test case for "unfriendly" font URLs:
825825
// https://www.google.com/fonts
826826
if ( details.type === 'object' ) {
827-
if ( headerValue(details.responseHeaders, 'content-type').lastIndexOf('font/', 0) === 0 ) {
827+
if ( headerValue(details.responseHeaders, 'content-type').startsWith('font/') ) {
828828
details.type = 'font';
829829
var r = onBeforeRequestClient(details);
830830
if ( typeof r === 'object' && r.cancel === true ) {

platform/firefox/vapi-background.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2361,7 +2361,7 @@ vAPI.net.registerListeners = function() {
23612361
var tabId = tabWatcher.tabIdFromTarget(browser);
23622362

23632363
// Ignore notifications related to our popup
2364-
if ( details.url.lastIndexOf(vAPI.getURL('popup.html'), 0) === 0 ) {
2364+
if ( details.url.startsWith(vAPI.getURL('popup.html')) ) {
23652365
return;
23662366
}
23672367

src/background.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
<script src="lib/punycode.js"></script>
99
<script src="lib/publicsuffixlist.js"></script>
1010
<script src="lib/yamd5.js"></script>
11+
<script src="js/polyfill.js"></script>
1112
<script src="js/vapi-common.js"></script>
1213
<script src="js/vapi-background.js"></script>
1314
<script src="js/background.js"></script>

src/js/assets.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ var getTextFileFromURL = function(url, onLoad, onError) {
312312
// appears to be a HTML document: could happen when server serves
313313
// some kind of error page I suppose
314314
var text = this.responseText.trim();
315-
if ( text.charAt(0) === '<' && text.slice(-1) === '>' ) {
315+
if ( text.startsWith('<') && text.endsWith('>') ) {
316316
return onError.call(this);
317317
}
318318
return onLoad.call(this);

src/js/cosmetic-filtering.js

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ var FilterHostname = function(s, hostname) {
191191
};
192192

193193
FilterHostname.prototype.retrieve = function(hostname, out) {
194-
if ( hostname.slice(-this.hostname.length) === this.hostname ) {
194+
if ( hostname.endsWith(this.hostname) ) {
195195
out.push(this.s);
196196
}
197197
};
@@ -219,7 +219,7 @@ var FilterEntity = function(s, entity) {
219219
};
220220

221221
FilterEntity.prototype.retrieve = function(entity, out) {
222-
if ( entity.slice(-this.entity.length) === this.entity ) {
222+
if ( entity.endsWith(this.entity) ) {
223223
out.push(this.s);
224224
}
225225
};
@@ -244,7 +244,6 @@ var FilterParser = function() {
244244
this.hostnames = [];
245245
this.invalid = false;
246246
this.cosmetic = true;
247-
this.reScriptContains = /^script:contains\(.+?\)$/;
248247
};
249248

250249
/******************************************************************************/
@@ -321,7 +320,7 @@ FilterParser.prototype.parse = function(raw) {
321320
// Cosmetic filters with explicit style properties can apply only:
322321
// - to specific cosmetic filters (those which apply to a specific site)
323322
// - to block cosmetic filters (not exception cosmetic filters)
324-
if ( this.suffix.slice(-1) === '}' ) {
323+
if ( this.suffix.endsWith('}') ) {
325324
// Not supported for now: this code will ensure some backward
326325
// compatibility for when cosmetic filters with explicit style
327326
// properties start to be in use.
@@ -341,7 +340,7 @@ FilterParser.prototype.parse = function(raw) {
341340
// Normalize high-medium selectors: `href` is assumed to imply `a` tag. We
342341
// need to do this here in order to correctly avoid duplicates. The test
343342
// is designed to minimize overhead -- this is a low occurrence filter.
344-
if ( this.suffix.charAt(1) === '[' && this.suffix.slice(2, 9) === 'href^="' ) {
343+
if ( this.suffix.startsWith('[href^="', 1) ) {
345344
this.suffix = this.suffix.slice(1);
346345
}
347346

@@ -357,9 +356,9 @@ FilterParser.prototype.parse = function(raw) {
357356

358357
// Inline script tag filter?
359358
if (
360-
this.suffix.charAt(0) !== 's' ||
361-
this.reScriptContains.test(this.suffix) === false )
362-
{
359+
this.suffix.startsWith('script:contains(') === false ||
360+
this.suffix.endsWith(')') === false
361+
) {
363362
return this;
364363
}
365364

@@ -370,17 +369,17 @@ FilterParser.prototype.parse = function(raw) {
370369
return this;
371370
}
372371

373-
var suffix = this.suffix;
372+
var suffix = this.suffix.slice(16, -1);
374373
this.suffix = 'script//:';
375374

376375
// Plain string-based?
377-
if ( suffix.charAt(16) !== '/' || suffix.slice(-2) !== '/)' ) {
378-
this.suffix += suffix.slice(16, -1).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
376+
if ( suffix.startsWith('/') === false || suffix.endsWith('/') === false ) {
377+
this.suffix += suffix.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
379378
return this;
380379
}
381380

382381
// Regex-based
383-
this.suffix += suffix.slice(17, -2).replace(/\\/g, '\\');
382+
this.suffix += suffix.slice(1, -1);
384383

385384
// Valid regex?
386385
if ( isBadRegex(this.suffix) ) {
@@ -687,7 +686,7 @@ FilterContainer.prototype.isValidSelector = (function() {
687686
return true;
688687
} catch (e) {
689688
}
690-
if ( s.lastIndexOf('script//:', 0) === 0 ) {
689+
if ( s.startsWith('script//:') ) {
691690
return true;
692691
}
693692
console.error('uBlock> invalid cosmetic filter:', s);
@@ -730,10 +729,10 @@ FilterContainer.prototype.compile = function(s, out) {
730729
var hostname;
731730
while ( i-- ) {
732731
hostname = hostnames[i];
733-
if ( hostname.charAt(0) !== '~' ) {
732+
if ( hostname.startsWith('~') === false ) {
734733
applyGlobally = false;
735734
}
736-
if ( hostname.slice(-2) === '.*' ) {
735+
if ( hostname.endsWith('.*') ) {
737736
this.compileEntitySelector(hostname, parsed, out);
738737
} else {
739738
this.compileHostnameSelector(hostname, parsed, out);
@@ -839,7 +838,7 @@ FilterContainer.prototype.reHighMedium = /^\[href\^="https?:\/\/([^"]{8})[^"]*"\
839838
FilterContainer.prototype.compileHostnameSelector = function(hostname, parsed, out) {
840839
// https://github.com/chrisaljoudi/uBlock/issues/145
841840
var unhide = parsed.unhide;
842-
if ( hostname.charAt(0) === '~' ) {
841+
if ( hostname.startsWith('~') ) {
843842
hostname = hostname.slice(1);
844843
unhide ^= 1;
845844
}
@@ -915,7 +914,7 @@ FilterContainer.prototype.fromCompiledContent = function(text, lineBeg, skip) {
915914
// h ir twitter.com .promoted-tweet
916915
if ( fields[0] === 'h' ) {
917916
// Special filter: script tags. Not a real CSS selector.
918-
if ( fields[3].lastIndexOf('script//:', 0) === 0 ) {
917+
if ( fields[3].startsWith('script//:') ) {
919918
this.createScriptTagFilter(fields[2], fields[3].slice(9));
920919
continue;
921920
}
@@ -951,7 +950,7 @@ FilterContainer.prototype.fromCompiledContent = function(text, lineBeg, skip) {
951950
// entity selector
952951
if ( fields[0] === 'e' ) {
953952
// Special filter: script tags. Not a real CSS selector.
954-
if ( fields[2].lastIndexOf('script//:', 0) === 0 ) {
953+
if ( fields[2].startsWith('script//:') ) {
955954
this.createScriptTagFilter(fields[1], fields[2].slice(9));
956955
continue;
957956
}
@@ -1224,16 +1223,17 @@ FilterContainer.prototype.addToSelectorCache = function(details) {
12241223
/******************************************************************************/
12251224

12261225
FilterContainer.prototype.removeFromSelectorCache = function(targetHostname, type) {
1226+
var targetHostnameLength = targetHostname.length;
12271227
for ( var hostname in this.selectorCache ) {
12281228
if ( this.selectorCache.hasOwnProperty(hostname) === false ) {
12291229
continue;
12301230
}
12311231
if ( targetHostname !== '*' ) {
1232-
if ( hostname.slice(0 - targetHostname.length) !== targetHostname ) {
1232+
if ( hostname.endsWith(targetHostname) === false ) {
12331233
continue;
12341234
}
1235-
if ( hostname.length !== targetHostname.length &&
1236-
hostname.charAt(0 - targetHostname.length - 1) !== '.' ) {
1235+
if ( hostname.length !== targetHostnameLength &&
1236+
hostname.charAt(hostname.length - targetHostnameLength - 1) !== '.' ) {
12371237
continue;
12381238
}
12391239
}

src/js/dynamic-net-filtering.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ var isIPAddress = function(hostname) {
8989
if ( reIPv4VeryCoarse.test(hostname) ) {
9090
return true;
9191
}
92-
return hostname.charAt(0) === '[';
92+
return hostname.startsWith('[');
9393
};
9494

9595
/******************************************************************************/
@@ -325,7 +325,7 @@ var is3rdParty = function(srcHostname, desHostname) {
325325
// etc.
326326
var srcDomain = domainFromHostname(srcHostname) || srcHostname;
327327

328-
if ( desHostname.slice(0 - srcDomain.length) !== srcDomain ) {
328+
if ( desHostname.endsWith(srcDomain) === false ) {
329329
return true;
330330
}
331331
// Do not confuse 'example.com' with 'anotherexample.com'
@@ -548,7 +548,7 @@ Matrix.prototype.fromString = function(text, append) {
548548

549549
// Ignore special rules:
550550
// hostname-based switch rules
551-
if ( fields[0].slice(-1) === ':' ) {
551+
if ( fields[0].endsWith(':') ) {
552552
continue;
553553
}
554554

src/js/hnswitches.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ var isIPAddress = function(hostname) {
8080
if ( reIPv4VeryCoarse.test(hostname) ) {
8181
return true;
8282
}
83-
return hostname.charAt(0) === '[';
83+
return hostname.startsWith('[');
8484
};
8585

8686
/******************************************************************************/
@@ -177,7 +177,7 @@ HnSwitches.prototype.toggleBranchZ = function(switchName, targetHostname, newSta
177177
if ( hostname.length <= targetLen ) {
178178
continue;
179179
}
180-
if ( hostname.slice(-targetLen) !== targetHostname ) {
180+
if ( hostname.endsWith(targetHostname) === false ) {
181181
continue;
182182
}
183183
if ( hostname.charAt(hostname.length - targetLen - 1) !== '.' ) {

src/js/logger-ui-inspector.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
var showdomButton = uDom.nodeFromId('showdom');
3333

3434
// Don't bother if the browser is not modern enough.
35-
if ( typeof Map === undefined || typeof WeakMap === undefined ) {
35+
if ( typeof Map === undefined || Map.polyfill || typeof WeakMap === undefined ) {
3636
showdomButton.classList.add('disabled');
3737
return;
3838
}

src/js/messaging.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1287,7 +1287,7 @@ var onMessage = function(request, sender, callback) {
12871287
if ( pageStore === null ) {
12881288
continue;
12891289
}
1290-
if ( pageStore.rawURL.lastIndexOf(loggerURL, 0) === 0 ) {
1290+
if ( pageStore.rawURL.startsWith(loggerURL) ) {
12911291
continue;
12921292
}
12931293
tabIds[tabId] = pageStore.title;

src/js/polyfill.js

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
/*******************************************************************************
2+
3+
uBlock Origin - a browser extension to block requests.
4+
Copyright (C) 2015 Raymond Hill
5+
6+
This program is free software: you can redistribute it and/or modify
7+
it under the terms of the GNU General Public License as published by
8+
the Free Software Foundation, either version 3 of the License, or
9+
(at your option) any later version.
10+
11+
This program is distributed in the hope that it will be useful,
12+
but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
GNU General Public License for more details.
15+
16+
You should have received a copy of the GNU General Public License
17+
along with this program. If not, see {http://www.gnu.org/licenses/}.
18+
19+
Home: https://github.com/gorhill/uBlock
20+
*/
21+
22+
/******************************************************************************/
23+
24+
(function() {
25+
26+
'use strict';
27+
28+
/******************************************************************************/
29+
30+
// https://github.com/gorhill/uBlock/issues/1067
31+
// https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith
32+
// Firefox 17/Chromium 41 supports `startsWith`.
33+
34+
if ( String.prototype.startsWith instanceof Function === false ) {
35+
String.prototype.startsWith = function(needle, pos) {
36+
if ( typeof pos !== 'number' ) {
37+
pos = 0;
38+
}
39+
return this.lastIndexOf(needle, pos) === pos;
40+
};
41+
}
42+
43+
// https://github.com/gorhill/uBlock/issues/1067
44+
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/endsWith
45+
// Firefox 17/Chromium 41 supports `endsWith`.
46+
47+
if ( String.prototype.endsWith instanceof Function === false ) {
48+
String.prototype.endsWith = function(needle, pos) {
49+
if ( typeof pos !== 'number' ) {
50+
pos = this.length;
51+
}
52+
pos -= needle.length;
53+
return this.indexOf(needle, pos) === pos;
54+
};
55+
}
56+
57+
/******************************************************************************/
58+
59+
// https://github.com/gorhill/uBlock/issues/1070
60+
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set#Browser_compatibility
61+
// This polyfill is designed to fulfill *only* what uBlock Origin needs -- this
62+
// is not an accurate API of the real Set() type.
63+
64+
if ( typeof self.Set !== 'function' ) {
65+
self.Set = function() {
66+
this.clear();
67+
};
68+
69+
self.Set.polyfill = true;
70+
71+
self.Set.prototype.clear = function() {
72+
this._set = Object.create(null);
73+
this.size = 0;
74+
};
75+
76+
self.Set.prototype.add = function(k) {
77+
if ( this._set[k] === undefined ) {
78+
this._set[k] = true;
79+
this.size += 1;
80+
}
81+
};
82+
83+
self.Set.prototype.delete = function(k) {
84+
if ( this._set[k] !== undefined ) {
85+
delete this._set[k];
86+
this.size -= 1;
87+
}
88+
};
89+
90+
self.Set.prototype.has = function(k) {
91+
return this._set[k] !== undefined;
92+
};
93+
}
94+
95+
/******************************************************************************/
96+
97+
// https://github.com/gorhill/uBlock/issues/1070
98+
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set#Browser_compatibility
99+
// This polyfill is designed to fulfill *only* what uBlock Origin needs -- this
100+
// is not an accurate API of the real Map() type.
101+
102+
if ( typeof self.Map !== 'function' ) {
103+
self.Map = function() {
104+
this.clear();
105+
};
106+
107+
self.Map.polyfill = true;
108+
109+
self.Map.prototype.clear = function() {
110+
this._map = Object.create(null);
111+
this.size = 0;
112+
};
113+
114+
self.Map.prototype.delete = function(k) {
115+
if ( this._map[k] !== undefined ) {
116+
delete this._map[k];
117+
this.size -= 1;
118+
}
119+
};
120+
121+
self.Map.prototype.get = function(k) {
122+
return this._map[k];
123+
};
124+
125+
self.Set.prototype.has = function(k) {
126+
return this._map[k] !== undefined;
127+
};
128+
129+
self.Map.prototype.set = function(k, v) {
130+
if ( v !== undefined ) {
131+
if ( this._map[k] === undefined ) {
132+
this.size += 1;
133+
}
134+
this._map[k] = v;
135+
} else {
136+
if ( this._map[k] !== undefined ) {
137+
this.size -= 1;
138+
}
139+
delete this._map[k];
140+
}
141+
};
142+
}
143+
144+
/******************************************************************************/
145+
146+
})();

0 commit comments

Comments
 (0)