uBlock/platform/firefox/vapi-webrequest.js

146 lines
5.2 KiB
JavaScript
Raw Normal View History

2017-09-02 12:11:33 +02:00
/*******************************************************************************
uBlock Origin - a browser extension to block requests.
Copyright (C) 2017-present Raymond Hill
2017-09-02 12:11:33 +02:00
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';
/******************************************************************************/
(( ) => {
// https://github.com/uBlockOrigin/uBlock-issues/issues/407
if ( vAPI.webextFlavor.soup.has('firefox') === false ) { return; }
2017-09-02 12:11:33 +02:00
// https://github.com/gorhill/uBlock/issues/2950
// Firefox 56 does not normalize URLs to ASCII, uBO must do this itself.
2017-09-02 12:11:33 +02:00
// https://bugzilla.mozilla.org/show_bug.cgi?id=945240
const evalMustPunycode = ( ) => {
return vAPI.webextFlavor.soup.has('firefox') &&
vAPI.webextFlavor.major < 57;
2018-04-04 18:42:01 +02:00
};
let mustPunycode = evalMustPunycode();
// The real actual webextFlavor value may not be set in stone, so listen
// for possible future changes.
window.addEventListener('webextFlavor', ( ) => {
2018-04-04 18:42:01 +02:00
mustPunycode = evalMustPunycode();
}, { once: true });
2017-09-02 12:11:33 +02:00
const punycode = self.punycode;
const reAsciiHostname = /^https?:\/\/[0-9a-z_.:@-]+[/?#]/;
const parsedURL = new URL('about:blank');
2017-09-02 12:11:33 +02:00
// Related issues:
// - https://github.com/gorhill/uBlock/issues/1327
// - https://github.com/uBlockOrigin/uBlock-issues/issues/128
// - https://bugzilla.mozilla.org/show_bug.cgi?id=1503721
2017-09-02 12:11:33 +02:00
// Extend base class to normalize as per platform.
2017-09-02 12:11:33 +02:00
vAPI.Net = class extends vAPI.Net {
constructor() {
super();
this.pendingRequests = [];
2017-09-02 12:11:33 +02:00
}
normalizeDetails(details) {
if ( mustPunycode && !reAsciiHostname.test(details.url) ) {
parsedURL.href = details.url;
details.url = details.url.replace(
parsedURL.hostname,
punycode.toASCII(parsedURL.hostname)
);
}
2017-09-02 12:11:33 +02:00
const 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;
}
// https://github.com/uBlockOrigin/uBlock-issues/issues/345
// Re-categorize an embedded object as a `sub_frame` if its
// content type is that of a HTML document.
if ( type === 'object' && Array.isArray(details.responseHeaders) ) {
for ( const header of details.responseHeaders ) {
if ( header.name.toLowerCase() === 'content-type' ) {
if ( header.value.startsWith('text/html') ) {
details.type = 'sub_frame';
}
break;
}
}
}
}
denormalizeTypes(types) {
if ( types.length === 0 ) {
return Array.from(this.validTypes);
2017-09-02 12:11:33 +02:00
}
const out = new Set();
for ( const type of types ) {
if ( this.validTypes.has(type) ) {
out.add(type);
}
if ( type === 'image' && this.validTypes.has('imageset') ) {
out.add('imageset');
}
if ( type === 'sub_frame' ) {
out.add('object');
}
2017-09-02 12:11:33 +02:00
}
return Array.from(out);
2017-09-02 12:11:33 +02:00
}
suspendOneRequest(details) {
const pending = {
details: Object.assign({}, details),
resolve: undefined,
promise: undefined
};
pending.promise = new Promise(function(resolve) {
pending.resolve = resolve;
});
this.pendingRequests.push(pending);
return pending.promise;
}
unsuspendAllRequests(resolver) {
const pendingRequests = this.pendingRequests;
this.pendingRequests = [];
for ( const entry of pendingRequests ) {
entry.resolve(resolver(entry.details));
}
}
canSuspend() {
return true;
}
};
})();
/******************************************************************************/