diff --git a/src/js/cosmetic-filtering.js b/src/js/cosmetic-filtering.js index 0660e0ecc..cc9b7bf4d 100644 --- a/src/js/cosmetic-filtering.js +++ b/src/js/cosmetic-filtering.js @@ -1338,9 +1338,9 @@ FilterContainer.prototype.createUserScriptRule = function(hash, hostname, select // https://github.com/gorhill/uBlock/issues/1954 // 01234567890123456789 -// script:inject(token) -// ^ ^ -// 14 -1 +// script:inject(token[, arg[, ...]]) +// ^ ^ +// 14 -1 FilterContainer.prototype.retrieveUserScripts = function(domain, hostname) { if ( this.userScriptCount === 0 ) { return; } @@ -1377,7 +1377,7 @@ FilterContainer.prototype.retrieveUserScripts = function(domain, hostname) { } var i = selectors.length; while ( i-- ) { - this._lookupUserScript(scripts, selectors[i].slice(14, -1), reng, out); + this._lookupUserScript(scripts, selectors[i].slice(14, -1).trim(), reng, out); } if ( out.length === 0 ) { @@ -1404,13 +1404,32 @@ FilterContainer.prototype.retrieveUserScripts = function(domain, hostname) { return out.join('\n'); }; -FilterContainer.prototype._lookupUserScript = function(dict, token, reng, out) { - if ( dict.has(token) ) { return; } - var content = reng.resourceContentFromName(token, 'application/javascript'); - if ( content ) { - dict.set(token, out.length); - out.push(content); +/******************************************************************************/ + +FilterContainer.prototype._lookupUserScript = function(dict, raw, reng, out) { + if ( dict.has(raw) ) { return; } + var token, args, + pos = raw.indexOf(','); + if ( pos === -1 ) { + token = raw; + } else { + token = raw.slice(0, pos).trim(); + args = raw.slice(pos + 1).trim(); } + var content = reng.resourceContentFromName(token, 'application/javascript'); + if ( !content ) { return; } + if ( args ) { + var i = 1; + while ( args !== '' ) { + pos = args.indexOf(','); + if ( pos === -1 ) { pos = args.length; } + content = content.replace('{{' + i + '}}', args.slice(0, pos).trim()); + args = args.slice(pos + 1).trim(); + i++; + } + } + dict.set(raw, out.length); + out.push(content); }; /******************************************************************************/ diff --git a/src/js/messaging.js b/src/js/messaging.js index f2140b9bf..b422d1abc 100644 --- a/src/js/messaging.js +++ b/src/js/messaging.js @@ -481,22 +481,21 @@ var filterRequests = function(pageStore, details) { //console.debug('messaging.js/contentscript-end.js: processing %d requests', requests.length); - var hostnameFromURI = µb.URI.hostnameFromURI; - var redirectEngine = µb.redirectEngine; - var punycodeURL = vAPI.punycodeURL; + var hostnameFromURI = µb.URI.hostnameFromURI, + redirectEngine = µb.redirectEngine, + punycodeURL = vAPI.punycodeURL; // Create evaluation context - var context = pageStore.createContextFromFrameHostname(details.pageHostname); - - var request, r; - var i = requests.length; + var context = pageStore.createContextFromFrameHostname(details.pageHostname), + request, r, + i = requests.length; while ( i-- ) { request = requests[i]; context.requestURL = punycodeURL(request.url); context.requestHostname = hostnameFromURI(context.requestURL); context.requestType = tagNameToRequestTypeMap[request.tag]; r = pageStore.filterRequest(context); - if ( typeof r !== 'string' || r.charAt(1) !== 'b' ) { + if ( typeof r !== 'string' || r.charCodeAt(1) !== 98 /* 'b' */ ) { continue; } // Redirected? (We do not hide redirected resources.) diff --git a/src/js/pagestore.js b/src/js/pagestore.js index 8f3f661b5..6c0c67cd4 100644 --- a/src/js/pagestore.js +++ b/src/js/pagestore.js @@ -499,22 +499,14 @@ PageStore.prototype.toggleNetFilteringSwitch = function(url, scope, state) { /******************************************************************************/ -PageStore.prototype.logLargeMedia = (function() { - var injectScript = function() { - this.largeMediaTimer = null; - µb.scriptlets.injectDeep( - this.tabId, - 'load-large-media-interactive' - ); - µb.contextMenu.update(this.tabId); - }; - return function() { - this.largeMediaCount += 1; - if ( this.largeMediaTimer === null ) { - this.largeMediaTimer = vAPI.setTimeout(injectScript.bind(this), 500); - } - }; -})(); +PageStore.prototype.injectLargeMediaElementScriptlet = function() { + this.largeMediaTimer = null; + µb.scriptlets.injectDeep( + this.tabId, + 'load-large-media-interactive' + ); + µb.contextMenu.update(this.tabId); +}; PageStore.prototype.temporarilyAllowLargeMediaElements = function() { this.largeMediaCount = 0; @@ -617,7 +609,7 @@ PageStore.prototype.filterRequest = function(context) { // We want to short-term cache filtering results of collapsible types, // because they are likely to be reused, from network request handler and // from content script handler. - if ( 'image sub_frame object'.indexOf(requestType) === -1 ) { + if ( 'image media object sub_frame'.indexOf(requestType) === -1 ) { return this.filterRequestNoCache(context); } @@ -628,17 +620,12 @@ PageStore.prototype.filterRequest = function(context) { var entry = this.netFilteringCache.lookup(context); if ( entry !== undefined ) { - //console.debug('cache HIT: PageStore.filterRequest("%s")', context.requestURL); return entry.result; } - var result = ''; - // Dynamic URL filtering. - if ( result === '' ) { - µb.sessionURLFiltering.evaluateZ(context.rootHostname, context.requestURL, requestType); - result = µb.sessionURLFiltering.toFilterString(); - } + µb.sessionURLFiltering.evaluateZ(context.rootHostname, context.requestURL, requestType); + var result = µb.sessionURLFiltering.toFilterString(); // Dynamic hostname/type filtering. if ( result === '' && µb.userSettings.advancedUserEnabled ) { @@ -648,14 +635,13 @@ PageStore.prototype.filterRequest = function(context) { } } - // Static filtering has lowest precedence. - if ( result === '' || result.charAt(1) === 'n' ) { + // Static filtering: lowest filtering precedence. + if ( result === '' || result.charCodeAt(1) === 110 /* 'n' */ ) { if ( µb.staticNetFilteringEngine.matchString(context) !== undefined ) { result = µb.staticNetFilteringEngine.toResultString(µb.logger.isEnabled()); } } - //console.debug('cache MISS: PageStore.filterRequest("%s")', context.requestURL); this.netFilteringCache.add(context, result); return result; @@ -663,6 +649,32 @@ PageStore.prototype.filterRequest = function(context) { /******************************************************************************/ +// The caller is responsible to check whether filtering is enabled or not. + +PageStore.prototype.filterLargeMediaElement = function(size) { + if ( Date.now() < this.allowLargeMediaElementsUntil ) { + return; + } + if ( µb.hnSwitches.evaluateZ('no-large-media', this.tabHostname) !== true ) { + return; + } + if ( (size >>> 10) < µb.userSettings.largeMediaSize ) { + return; + } + + this.largeMediaCount += 1; + if ( this.largeMediaTimer === null ) { + this.largeMediaTimer = vAPI.setTimeout( + this.injectLargeMediaElementScriptlet.bind(this), + 500 + ); + } + + return µb.hnSwitches.toResultString(); +}; + +/******************************************************************************/ + PageStore.prototype.filterRequestNoCache = function(context) { if ( this.getNetFilteringSwitch() === false ) { return ''; @@ -697,7 +709,7 @@ PageStore.prototype.filterRequestNoCache = function(context) { } // Static filtering has lowest precedence. - if ( result === '' || result.charAt(1) === 'n' ) { + if ( result === '' || result.charCodeAt(1) === 110 /* 'n' */ ) { if ( µb.staticNetFilteringEngine.matchString(context) !== undefined ) { result = µb.staticNetFilteringEngine.toResultString(µb.logger.isEnabled()); } diff --git a/src/js/traffic.js b/src/js/traffic.js index b3a296fe6..1c67e0de5 100644 --- a/src/js/traffic.js +++ b/src/js/traffic.js @@ -521,40 +521,29 @@ var processCSP = function(details, pageStore, context) { /******************************************************************************/ // https://github.com/gorhill/uBlock/issues/1163 -// "Block elements by size" +// "Block elements by size" var foilLargeMediaElement = function(details) { var µb = µBlock; - var tabId = details.tabId; - var pageStore = µb.pageStoreFromTabId(tabId); - if ( pageStore === null ) { - return; - } - if ( pageStore.getNetFilteringSwitch() !== true ) { - return; - } - if ( Date.now() < pageStore.allowLargeMediaElementsUntil ) { - return; - } - if ( µb.hnSwitches.evaluateZ('no-large-media', pageStore.tabHostname) !== true ) { - return; - } + var i = headerIndexFromName('content-length', details.responseHeaders); - if ( i === -1 ) { - return; - } - var contentLength = parseInt(details.responseHeaders[i].value, 10) || 0; - if ( (contentLength >>> 10) < µb.userSettings.largeMediaSize ) { + if ( i === -1 ) { return; } + + var tabId = details.tabId, + pageStore = µb.pageStoreFromTabId(tabId); + if ( pageStore === null || pageStore.getNetFilteringSwitch() === false ) { return; } - pageStore.logLargeMedia(); + var size = parseInt(details.responseHeaders[i].value, 10) || 0, + result = pageStore.filterLargeMediaElement(size); + if ( result === undefined ) { return; } if ( µb.logger.isEnabled() ) { µb.logger.writeOne( tabId, 'net', - µb.hnSwitches.toResultString(), + result, details.type, details.url, pageStore.tabHostname, diff --git a/src/js/ublock.js b/src/js/ublock.js index 0d1b44ee0..d68a12929 100644 --- a/src/js/ublock.js +++ b/src/js/ublock.js @@ -455,13 +455,13 @@ var matchBucket = function(url, hostname, bucket, start) { /******************************************************************************/ µBlock.isBlockResult = function(result) { - return typeof result === 'string' && result.charAt(1) === 'b'; + return typeof result === 'string' && result.charCodeAt(1) === 98 /* 'b' */; }; /******************************************************************************/ µBlock.isAllowResult = function(result) { - return typeof result !== 'string' || result.charAt(1) !== 'b'; + return typeof result !== 'string' || result.charCodeAt(1) !== 98 /* 'b' */; }; /******************************************************************************/