From a0c595d02dbd9f57373ebba797b77895ae51db20 Mon Sep 17 00:00:00 2001 From: gorhill Date: Sat, 2 Sep 2017 06:11:33 -0400 Subject: [PATCH] fix #2950 --- platform/chromium/vapi-background.js | 289 ------------------------- platform/chromium/vapi-webrequest.js | 313 +++++++++++++++++++++++++++ platform/webext/vapi-webrequest.js | 184 ++++++++++++++++ src/background.html | 1 + tools/make-webext.sh | 1 + 5 files changed, 499 insertions(+), 289 deletions(-) create mode 100644 platform/chromium/vapi-webrequest.js create mode 100644 platform/webext/vapi-webrequest.js diff --git a/platform/chromium/vapi-background.js b/platform/chromium/vapi-background.js index 20acf3454..0bcc58de8 100644 --- a/platform/chromium/vapi-background.js +++ b/platform/chromium/vapi-background.js @@ -930,295 +930,6 @@ vAPI.messaging.broadcast = function(message) { /******************************************************************************/ /******************************************************************************/ -vAPI.net = {}; - -/******************************************************************************/ - -vAPI.net.registerListeners = function() { - var µb = µBlock, - µburi = µb.URI, - wrApi = chrome.webRequest; - - // https://bugs.chromium.org/p/chromium/issues/detail?id=410382 - // Between Chromium 38-48, plug-ins' network requests were reported as - // type "other" instead of "object". - var is_v38_48 = /\bChrom[a-z]+\/(?:3[89]|4[0-8])\.[\d.]+\b/.test(navigator.userAgent); - - // legacy Chromium understands only these network request types. - var validTypes = { - main_frame: true, - sub_frame: true, - stylesheet: true, - script: true, - image: true, - object: true, - xmlhttprequest: true, - other: true - }; - // modern Chromium/WebExtensions: more types available. - if ( wrApi.ResourceType ) { - (function() { - for ( var typeKey in wrApi.ResourceType ) { - if ( wrApi.ResourceType.hasOwnProperty(typeKey) ) { - validTypes[wrApi.ResourceType[typeKey]] = true; - } - } - })(); - } - - var extToTypeMap = new Map([ - ['eot','font'],['otf','font'],['svg','font'],['ttf','font'],['woff','font'],['woff2','font'], - ['mp3','media'],['mp4','media'],['webm','media'], - ['gif','image'],['ico','image'],['jpeg','image'],['jpg','image'],['png','image'],['webp','image'] - ]); - - var denormalizeTypes = function(aa) { - if ( aa.length === 0 ) { - return Object.keys(validTypes); - } - var out = []; - var i = aa.length, - type, - needOther = true; - while ( i-- ) { - type = aa[i]; - if ( validTypes[type] ) { - out.push(type); - } - if ( type === 'other' ) { - needOther = false; - } - } - if ( needOther ) { - out.push('other'); - } - return out; - }; - - var headerValue = function(headers, name) { - var i = headers.length; - while ( i-- ) { - if ( headers[i].name.toLowerCase() === name ) { - return headers[i].value.trim(); - } - } - return ''; - }; - - var normalizeRequestDetails = function(details) { - details.tabId = details.tabId.toString(); - - var type = details.type; - - // https://github.com/gorhill/uBlock/issues/1493 - // Chromium 49+/WebExtensions support a new request type: `ping`, - // which is fired as a result of using `navigator.sendBeacon`. - if ( type === 'ping' ) { - details.type = 'beacon'; - return; - } - - if ( type === 'imageset' ) { - details.type = 'image'; - return; - } - - // The rest of the function code is to normalize type - if ( type !== 'other' ) { - return; - } - - // Try to map known "extension" part of URL to request type. - var path = µburi.pathFromURI(details.url), - pos = path.indexOf('.', path.length - 6); - if ( pos !== -1 && (type = extToTypeMap.get(path.slice(pos + 1))) ) { - details.type = type; - return; - } - - // Try to extract type from response headers if present. - if ( details.responseHeaders ) { - type = headerValue(details.responseHeaders, 'content-type'); - if ( type.startsWith('font/') ) { - details.type = 'font'; - return; - } - if ( type.startsWith('image/') ) { - details.type = 'image'; - return; - } - if ( type.startsWith('audio/') || type.startsWith('video/') ) { - details.type = 'media'; - return; - } - } - - // https://github.com/chrisaljoudi/uBlock/issues/862 - // If no transposition possible, transpose to `object` as per - // Chromium bug 410382 - // https://code.google.com/p/chromium/issues/detail?id=410382 - if ( is_v38_48 ) { - details.type = 'object'; - } - }; - - // https://bugs.chromium.org/p/chromium/issues/detail?id=129353 - // https://github.com/gorhill/uBlock/issues/1497 - // Expose websocket-based network requests to uBO's filtering engine, - // logger, etc. - // Counterpart of following block of code is found in "vapi-client.js" -- - // search for "https://github.com/gorhill/uBlock/issues/1497". - // - // Once uBO 1.11.1 and uBO-Extra 2.12 are widespread, the image-based - // handling code can be removed. - var onBeforeWebsocketRequest = function(details) { - if ( (details.type !== 'image') && - (details.method !== 'HEAD' || details.type !== 'xmlhttprequest') - ) { - return; - } - var requestURL = details.url, - matches = /[?&]u(?:rl)?=([^&]+)/.exec(requestURL); - if ( matches === null ) { return; } - details.type = 'websocket'; - details.url = decodeURIComponent(matches[1]); - var r = onBeforeRequestClient(details); - if ( r && r.cancel ) { return r; } - // Redirect to the provided URL, or a 1x1 data: URI if none provided. - matches = /[?&]r=([^&]+)/.exec(requestURL); - return { - redirectUrl: matches !== null ? - decodeURIComponent(matches[1]) : - 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==' - }; - }; - - var onBeforeRequestClient = this.onBeforeRequest.callback; - var onBeforeRequest = validTypes.websocket - // modern Chromium/WebExtensions: type 'websocket' is supported - ? function(details) { - normalizeRequestDetails(details); - return onBeforeRequestClient(details); - } - // legacy Chromium - : function(details) { - // https://github.com/gorhill/uBlock/issues/1497 - if ( details.url.endsWith('ubofix=f41665f3028c7fd10eecf573336216d3') ) { - var r = onBeforeWebsocketRequest(details); - if ( r !== undefined ) { return r; } - } - normalizeRequestDetails(details); - return onBeforeRequestClient(details); - }; - - // This is needed for Chromium 49-55. - var onBeforeSendHeaders = validTypes.csp_report - // modern Chromium/WebExtensions: type 'csp_report' is supported - ? null - // legacy Chromium - : function(details) { - if ( details.type !== 'ping' || details.method !== 'POST' ) { return; } - var type = headerValue(details.requestHeaders, 'content-type'); - if ( type === '' ) { return; } - if ( type.endsWith('/csp-report') ) { - details.type = 'csp_report'; - return onBeforeRequestClient(details); - } - }; - - var onHeadersReceivedClient = this.onHeadersReceived.callback, - onHeadersReceivedClientTypes = this.onHeadersReceived.types.slice(0), - onHeadersReceivedTypes = denormalizeTypes(onHeadersReceivedClientTypes); - var onHeadersReceived = validTypes.font - // modern Chromium/WebExtensions: type 'font' is supported - ? function(details) { - normalizeRequestDetails(details); - if ( - onHeadersReceivedClientTypes.length !== 0 && - onHeadersReceivedClientTypes.indexOf(details.type) === -1 - ) { - return; - } - return onHeadersReceivedClient(details); - } - // legacy Chromium - : function(details) { - normalizeRequestDetails(details); - // Hack to work around Chromium API limitations, where requests of - // type `font` are returned as `other`. For example, our normalization - // fail at transposing `other` into `font` for URLs which are outside - // what is expected. At least when headers are received we can check - // for content type `font/*`. Blocking at onHeadersReceived time is - // less worse than not blocking at all. Also, due to Chromium bug, - // `other` always becomes `object` when it can't be normalized into - // something else. Test case for "unfriendly" font URLs: - // https://www.google.com/fonts - if ( details.type === 'font' ) { - var r = onBeforeRequestClient(details); - if ( typeof r === 'object' && r.cancel === true ) { - return { cancel: true }; - } - } - if ( - onHeadersReceivedClientTypes.length !== 0 && - onHeadersReceivedClientTypes.indexOf(details.type) === -1 - ) { - return; - } - return onHeadersReceivedClient(details); - }; - - var urls, types; - - if ( onBeforeRequest ) { - urls = this.onBeforeRequest.urls || ['']; - types = this.onBeforeRequest.types || undefined; - if ( - (validTypes.websocket) && - (types === undefined || types.indexOf('websocket') !== -1) && - (urls.indexOf('') === -1) - ) { - if ( urls.indexOf('ws://*/*') === -1 ) { - urls.push('ws://*/*'); - } - if ( urls.indexOf('wss://*/*') === -1 ) { - urls.push('wss://*/*'); - } - } - wrApi.onBeforeRequest.addListener( - onBeforeRequest, - { urls: urls, types: types }, - this.onBeforeRequest.extra - ); - } - - // Chromium 48 and lower does not support `ping` type. - // Chromium 56 and higher does support `csp_report` stype. - if ( onBeforeSendHeaders ) { - wrApi.onBeforeSendHeaders.addListener( - onBeforeSendHeaders, - { - 'urls': [ '' ], - 'types': [ 'ping' ] - }, - [ 'blocking', 'requestHeaders' ] - ); - } - - if ( onHeadersReceived ) { - urls = this.onHeadersReceived.urls || ['']; - types = onHeadersReceivedTypes; - wrApi.onHeadersReceived.addListener( - onHeadersReceived, - { urls: urls, types: types }, - this.onHeadersReceived.extra - ); - } -}; - -/******************************************************************************/ -/******************************************************************************/ - // https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/contextMenus#Browser_compatibility // Firefox for Android does no support browser.contextMenus. diff --git a/platform/chromium/vapi-webrequest.js b/platform/chromium/vapi-webrequest.js new file mode 100644 index 000000000..ea9a5e139 --- /dev/null +++ b/platform/chromium/vapi-webrequest.js @@ -0,0 +1,313 @@ +/******************************************************************************* + + uBlock Origin - a browser extension to block requests. + Copyright (C) 2017 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 +*/ + +// For background page + +'use strict'; + +/******************************************************************************/ + +vAPI.net = {}; + +vAPI.net.registerListeners = function() { + + var µb = µBlock, + µburi = µb.URI, + wrApi = chrome.webRequest; + + // https://bugs.chromium.org/p/chromium/issues/detail?id=410382 + // Between Chromium 38-48, plug-ins' network requests were reported as + // type "other" instead of "object". + var is_v38_48 = /\bChrom[a-z]+\/(?:3[89]|4[0-8])\.[\d.]+\b/.test(navigator.userAgent); + + // legacy Chromium understands only these network request types. + var validTypes = { + main_frame: true, + sub_frame: true, + stylesheet: true, + script: true, + image: true, + object: true, + xmlhttprequest: true, + other: true + }; + // modern Chromium/WebExtensions: more types available. + if ( wrApi.ResourceType ) { + (function() { + for ( var typeKey in wrApi.ResourceType ) { + if ( wrApi.ResourceType.hasOwnProperty(typeKey) ) { + validTypes[wrApi.ResourceType[typeKey]] = true; + } + } + })(); + } + + var extToTypeMap = new Map([ + ['eot','font'],['otf','font'],['svg','font'],['ttf','font'],['woff','font'],['woff2','font'], + ['mp3','media'],['mp4','media'],['webm','media'], + ['gif','image'],['ico','image'],['jpeg','image'],['jpg','image'],['png','image'],['webp','image'] + ]); + + var denormalizeTypes = function(aa) { + if ( aa.length === 0 ) { + return Object.keys(validTypes); + } + var out = []; + var i = aa.length, + type, + needOther = true; + while ( i-- ) { + type = aa[i]; + if ( validTypes[type] ) { + out.push(type); + } + if ( type === 'other' ) { + needOther = false; + } + } + if ( needOther ) { + out.push('other'); + } + return out; + }; + + var headerValue = function(headers, name) { + var i = headers.length; + while ( i-- ) { + if ( headers[i].name.toLowerCase() === name ) { + return headers[i].value.trim(); + } + } + return ''; + }; + + var normalizeRequestDetails = function(details) { + details.tabId = details.tabId.toString(); + + var type = details.type; + + // https://github.com/gorhill/uBlock/issues/1493 + // Chromium 49+/WebExtensions support a new request type: `ping`, + // which is fired as a result of using `navigator.sendBeacon`. + if ( type === 'ping' ) { + details.type = 'beacon'; + return; + } + + if ( type === 'imageset' ) { + details.type = 'image'; + return; + } + + // The rest of the function code is to normalize type + if ( type !== 'other' ) { + return; + } + + // Try to map known "extension" part of URL to request type. + var path = µburi.pathFromURI(details.url), + pos = path.indexOf('.', path.length - 6); + if ( pos !== -1 && (type = extToTypeMap.get(path.slice(pos + 1))) ) { + details.type = type; + return; + } + + // Try to extract type from response headers if present. + if ( details.responseHeaders ) { + type = headerValue(details.responseHeaders, 'content-type'); + if ( type.startsWith('font/') ) { + details.type = 'font'; + return; + } + if ( type.startsWith('image/') ) { + details.type = 'image'; + return; + } + if ( type.startsWith('audio/') || type.startsWith('video/') ) { + details.type = 'media'; + return; + } + } + + // https://github.com/chrisaljoudi/uBlock/issues/862 + // If no transposition possible, transpose to `object` as per + // Chromium bug 410382 + // https://code.google.com/p/chromium/issues/detail?id=410382 + if ( is_v38_48 ) { + details.type = 'object'; + } + }; + + // https://bugs.chromium.org/p/chromium/issues/detail?id=129353 + // https://github.com/gorhill/uBlock/issues/1497 + // Expose websocket-based network requests to uBO's filtering engine, + // logger, etc. + // Counterpart of following block of code is found in "vapi-client.js" -- + // search for "https://github.com/gorhill/uBlock/issues/1497". + // + // Once uBO 1.11.1 and uBO-Extra 2.12 are widespread, the image-based + // handling code can be removed. + var onBeforeWebsocketRequest = function(details) { + if ( (details.type !== 'image') && + (details.method !== 'HEAD' || details.type !== 'xmlhttprequest') + ) { + return; + } + var requestURL = details.url, + matches = /[?&]u(?:rl)?=([^&]+)/.exec(requestURL); + if ( matches === null ) { return; } + details.type = 'websocket'; + details.url = decodeURIComponent(matches[1]); + var r = onBeforeRequestClient(details); + if ( r && r.cancel ) { return r; } + // Redirect to the provided URL, or a 1x1 data: URI if none provided. + matches = /[?&]r=([^&]+)/.exec(requestURL); + return { + redirectUrl: matches !== null ? + decodeURIComponent(matches[1]) : + 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==' + }; + }; + + var onBeforeRequestClient = this.onBeforeRequest.callback; + var onBeforeRequest = validTypes.websocket + // modern Chromium/WebExtensions: type 'websocket' is supported + ? function(details) { + normalizeRequestDetails(details); + return onBeforeRequestClient(details); + } + // legacy Chromium + : function(details) { + // https://github.com/gorhill/uBlock/issues/1497 + if ( details.url.endsWith('ubofix=f41665f3028c7fd10eecf573336216d3') ) { + var r = onBeforeWebsocketRequest(details); + if ( r !== undefined ) { return r; } + } + normalizeRequestDetails(details); + return onBeforeRequestClient(details); + }; + + // This is needed for Chromium 49-55. + var onBeforeSendHeaders = validTypes.csp_report + // modern Chromium/WebExtensions: type 'csp_report' is supported + ? null + // legacy Chromium + : function(details) { + if ( details.type !== 'ping' || details.method !== 'POST' ) { return; } + var type = headerValue(details.requestHeaders, 'content-type'); + if ( type === '' ) { return; } + if ( type.endsWith('/csp-report') ) { + details.type = 'csp_report'; + return onBeforeRequestClient(details); + } + }; + + var onHeadersReceivedClient = this.onHeadersReceived.callback, + onHeadersReceivedClientTypes = this.onHeadersReceived.types.slice(0), + onHeadersReceivedTypes = denormalizeTypes(onHeadersReceivedClientTypes); + var onHeadersReceived = validTypes.font + // modern Chromium/WebExtensions: type 'font' is supported + ? function(details) { + normalizeRequestDetails(details); + if ( + onHeadersReceivedClientTypes.length !== 0 && + onHeadersReceivedClientTypes.indexOf(details.type) === -1 + ) { + return; + } + return onHeadersReceivedClient(details); + } + // legacy Chromium + : function(details) { + normalizeRequestDetails(details); + // Hack to work around Chromium API limitations, where requests of + // type `font` are returned as `other`. For example, our normalization + // fail at transposing `other` into `font` for URLs which are outside + // what is expected. At least when headers are received we can check + // for content type `font/*`. Blocking at onHeadersReceived time is + // less worse than not blocking at all. Also, due to Chromium bug, + // `other` always becomes `object` when it can't be normalized into + // something else. Test case for "unfriendly" font URLs: + // https://www.google.com/fonts + if ( details.type === 'font' ) { + var r = onBeforeRequestClient(details); + if ( typeof r === 'object' && r.cancel === true ) { + return { cancel: true }; + } + } + if ( + onHeadersReceivedClientTypes.length !== 0 && + onHeadersReceivedClientTypes.indexOf(details.type) === -1 + ) { + return; + } + return onHeadersReceivedClient(details); + }; + + var urls, types; + + if ( onBeforeRequest ) { + urls = this.onBeforeRequest.urls || ['']; + types = this.onBeforeRequest.types || undefined; + if ( + (validTypes.websocket) && + (types === undefined || types.indexOf('websocket') !== -1) && + (urls.indexOf('') === -1) + ) { + if ( urls.indexOf('ws://*/*') === -1 ) { + urls.push('ws://*/*'); + } + if ( urls.indexOf('wss://*/*') === -1 ) { + urls.push('wss://*/*'); + } + } + wrApi.onBeforeRequest.addListener( + onBeforeRequest, + { urls: urls, types: types }, + this.onBeforeRequest.extra + ); + } + + // Chromium 48 and lower does not support `ping` type. + // Chromium 56 and higher does support `csp_report` stype. + if ( onBeforeSendHeaders ) { + wrApi.onBeforeSendHeaders.addListener( + onBeforeSendHeaders, + { + 'urls': [ '' ], + 'types': [ 'ping' ] + }, + [ 'blocking', 'requestHeaders' ] + ); + } + + if ( onHeadersReceived ) { + urls = this.onHeadersReceived.urls || ['']; + types = onHeadersReceivedTypes; + wrApi.onHeadersReceived.addListener( + onHeadersReceived, + { urls: urls, types: types }, + this.onHeadersReceived.extra + ); + } +}; + +/******************************************************************************/ diff --git a/platform/webext/vapi-webrequest.js b/platform/webext/vapi-webrequest.js new file mode 100644 index 000000000..06be7a335 --- /dev/null +++ b/platform/webext/vapi-webrequest.js @@ -0,0 +1,184 @@ +/******************************************************************************* + + uBlock Origin - a browser extension to block requests. + Copyright (C) 2017 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 +*/ + +// For background page + +'use strict'; + +/******************************************************************************/ + +vAPI.net = {}; + +vAPI.net.registerListeners = function() { + + // https://github.com/gorhill/uBlock/issues/2950 + // Firefox 55 does not normalize URLs to ASCII, uBO must do this itself. + // https://bugzilla.mozilla.org/show_bug.cgi?id=945240 + var belowFirefox56 = false; + (function() { + if ( + typeof browser === 'object' && + browser !== null && + browser.runtime instanceof Object && + typeof browser.runtime.getBrowserInfo === 'function' + ) { + browser.runtime.getBrowserInfo().then(info => { + belowFirefox56 = info.name === 'Firefox' && + /^5[0-5]\./.test(info.version); + }); + } + })(); + + var wrApi = browser.webRequest; + + // legacy Chromium understands only these network request types. + var validTypes = { + main_frame: true, + sub_frame: true, + stylesheet: true, + script: true, + image: true, + object: true, + xmlhttprequest: true, + other: true + }; + // modern Chromium/WebExtensions: more types available. + if ( wrApi.ResourceType ) { + (function() { + for ( var typeKey in wrApi.ResourceType ) { + if ( wrApi.ResourceType.hasOwnProperty(typeKey) ) { + validTypes[wrApi.ResourceType[typeKey]] = true; + } + } + })(); + } + + var denormalizeTypes = function(aa) { + if ( aa.length === 0 ) { + return Object.keys(validTypes); + } + var out = []; + var i = aa.length, + type, + needOther = true; + while ( i-- ) { + type = aa[i]; + if ( validTypes[type] ) { + out.push(type); + } + if ( type === 'other' ) { + needOther = false; + } + } + if ( needOther ) { + out.push('other'); + } + return out; + }; + + var punycode = self.punycode; + var reMustNormalizeHostname = /[^0-9a-z._-]/; + var parsedURL = new URL('about:blank'); + + var normalizeRequestDetails = function(details) { + details.tabId = details.tabId.toString(); + + if ( + belowFirefox56 === true && + reMustNormalizeHostname.test(details.url) === true + ) { + parsedURL.href = details.url; + details.url = details.url.replace( + parsedURL.hostname, + punycode.toASCII(parsedURL.hostname) + ); + } + + var type = details.type; + + // https://github.com/gorhill/uBlock/issues/1493 + // Chromium 49+/WebExtensions support a new request type: `ping`, + // which is fired as a result of using `navigator.sendBeacon`. + if ( type === 'ping' ) { + details.type = 'beacon'; + return; + } + + if ( type === 'imageset' ) { + details.type = 'image'; + return; + } + }; + + var onBeforeRequestClient = this.onBeforeRequest.callback; + var onBeforeRequest = function(details) { + normalizeRequestDetails(details); + return onBeforeRequestClient(details); + }; + + var onHeadersReceivedClient = this.onHeadersReceived.callback, + onHeadersReceivedClientTypes = this.onHeadersReceived.types.slice(0), + onHeadersReceivedTypes = denormalizeTypes(onHeadersReceivedClientTypes); + var onHeadersReceived = function(details) { + normalizeRequestDetails(details); + if ( + onHeadersReceivedClientTypes.length !== 0 && + onHeadersReceivedClientTypes.indexOf(details.type) === -1 + ) { + return; + } + return onHeadersReceivedClient(details); + }; + + if ( onBeforeRequest ) { + let urls = this.onBeforeRequest.urls || ['']; + let types = this.onBeforeRequest.types || undefined; + if ( + (validTypes.websocket) && + (types === undefined || types.indexOf('websocket') !== -1) && + (urls.indexOf('') === -1) + ) { + if ( urls.indexOf('ws://*/*') === -1 ) { + urls.push('ws://*/*'); + } + if ( urls.indexOf('wss://*/*') === -1 ) { + urls.push('wss://*/*'); + } + } + wrApi.onBeforeRequest.addListener( + onBeforeRequest, + { urls: urls, types: types }, + this.onBeforeRequest.extra + ); + } + + if ( onHeadersReceived ) { + let urls = this.onHeadersReceived.urls || ['']; + let types = onHeadersReceivedTypes; + wrApi.onHeadersReceived.addListener( + onHeadersReceived, + { urls: urls, types: types }, + this.onHeadersReceived.extra + ); + } +}; + +/******************************************************************************/ diff --git a/src/background.html b/src/background.html index 4ca1e39b7..31a0c8617 100644 --- a/src/background.html +++ b/src/background.html @@ -10,6 +10,7 @@ + diff --git a/tools/make-webext.sh b/tools/make-webext.sh index dc1c579a3..968e8cfa6 100755 --- a/tools/make-webext.sh +++ b/tools/make-webext.sh @@ -27,6 +27,7 @@ cp LICENSE.txt $DES/ cp platform/webext/manifest.json $DES/ cp platform/webext/options_ui.html $DES/ cp platform/webext/polyfill.js $DES/js/ +cp platform/webext/vapi-webrequest.js $DES/js/ cp platform/webext/vapi-cachestorage.js $DES/js/ cp platform/webext/vapi-usercss.js $DES/js/ rm $DES/js/options_ui.js