1
0
mirror of https://github.com/gorhill/uBlock.git synced 2024-11-07 03:12:33 +01:00

add workaround for Firefox's inability to redirect xhr to data: URI

This commit is contained in:
Raymond Hill 2018-03-31 18:47:56 -04:00
parent 9bc029b72c
commit 5c15f685f1
No known key found for this signature in database
GPG Key ID: 25E1490B761470C2

View File

@ -43,7 +43,7 @@ vAPI.net.registerListeners = function() {
// https://github.com/gorhill/uBlock/issues/2950 // https://github.com/gorhill/uBlock/issues/2950
// Firefox 55 does not normalize URLs to ASCII, uBO must do this itself. // Firefox 55 does not normalize URLs to ASCII, uBO must do this itself.
// https://bugzilla.mozilla.org/show_bug.cgi?id=945240 // https://bugzilla.mozilla.org/show_bug.cgi?id=945240
var mustPunycode = false; let mustPunycode = false;
(function() { (function() {
if ( if (
typeof browser === 'object' && typeof browser === 'object' &&
@ -58,10 +58,10 @@ vAPI.net.registerListeners = function() {
} }
})(); })();
var wrApi = browser.webRequest; let wrApi = browser.webRequest;
// legacy Chromium understands only these network request types. // legacy Chromium understands only these network request types.
var validTypes = new Set([ let validTypes = new Set([
'image', 'image',
'main_frame', 'main_frame',
'object', 'object',
@ -80,14 +80,14 @@ vAPI.net.registerListeners = function() {
} }
} }
var denormalizeTypes = function(aa) { let denormalizeTypes = function(aa) {
if ( aa.length === 0 ) { if ( aa.length === 0 ) {
return Array.from(validTypes); return Array.from(validTypes);
} }
var out = new Set(), let out = new Set(),
i = aa.length; i = aa.length;
while ( i-- ) { while ( i-- ) {
var type = aa[i]; let type = aa[i];
if ( validTypes.has(type) ) { if ( validTypes.has(type) ) {
out.add(type); out.add(type);
} }
@ -98,12 +98,12 @@ vAPI.net.registerListeners = function() {
return Array.from(out); return Array.from(out);
}; };
var punycode = self.punycode; let punycode = self.punycode;
var reAsciiHostname = /^https?:\/\/[0-9a-z_.:@-]+[/?#]/; let reAsciiHostname = /^https?:\/\/[0-9a-z_.:@-]+[/?#]/;
var reNetworkURI = /^(?:ftps?|https?|wss?)/; let reNetworkURI = /^(?:ftps?|https?|wss?)/;
var parsedURL = new URL('about:blank'); let parsedURL = new URL('about:blank');
var normalizeRequestDetails = function(details) { let normalizeRequestDetails = function(details) {
if ( if (
details.tabId === vAPI.noTabId && details.tabId === vAPI.noTabId &&
reNetworkURI.test(details.documentUrl) reNetworkURI.test(details.documentUrl)
@ -119,7 +119,7 @@ vAPI.net.registerListeners = function() {
); );
} }
var type = details.type; let type = details.type;
// https://github.com/gorhill/uBlock/issues/1493 // https://github.com/gorhill/uBlock/issues/1493
// Chromium 49+/WebExtensions support a new request type: `ping`, // Chromium 49+/WebExtensions support a new request type: `ping`,
@ -135,10 +135,85 @@ vAPI.net.registerListeners = function() {
} }
}; };
var onBeforeRequestClient = this.onBeforeRequest.callback; // This is to work around Firefox's inability to redirect xmlhttprequest
var onBeforeRequest = function(details) { // to data: URI.
let pseudoRedirector = {
filters: new Map(),
reDataURI: /^data:\w+\/\w+;base64,/,
dec: null,
init: function() {
this.dec = new Uint8Array(128);
let s = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
for ( let i = 0, n = s.length; i < n; i++ ) {
this.dec[s.charCodeAt(i)] = i;
}
},
start: function(requestId, redirectUrl) {
if ( this.dec === null ) { this.init(); }
let match = this.reDataURI.exec(redirectUrl);
if ( match === null ) { return redirectUrl; }
let s = redirectUrl.slice(match[0].length).replace(/=*$/, '');
let f = browser.webRequest.filterResponseData(requestId);
f.onstop = this.done;
f.onerror = this.disconnect;
this.filters.set(f, s);
},
done: function() {
let pr = pseudoRedirector;
let bufIn = pr.filters.get(this);
if ( bufIn === undefined ) { return pr.disconnect(this); }
let dec = pr.dec;
let sizeIn = bufIn.length;
let iIn = 0;
let sizeOut = sizeIn * 6 >>> 3;
let bufOut = new Uint8Array(sizeOut);
let iOut = 0;
let n = sizeIn & ~3;
while ( iIn < n ) {
let b0 = dec[bufIn.charCodeAt(iIn++)];
let b1 = dec[bufIn.charCodeAt(iIn++)];
let b2 = dec[bufIn.charCodeAt(iIn++)];
let b3 = dec[bufIn.charCodeAt(iIn++)];
bufOut[iOut++] = (b0 << 2) & 0xFC | (b1 >>> 4);
bufOut[iOut++] = (b1 << 4) & 0xF0 | (b2 >>> 2);
bufOut[iOut++] = (b2 << 6) & 0xC0 | b3;
}
if ( n < sizeIn ) {
let b0 = dec[bufIn.charCodeAt(iIn++)];
let b1 = dec[bufIn.charCodeAt(iIn++)];
if ( (sizeIn & 3) === 2 ) {
let b2 = dec[bufIn.charCodeAt(iIn++)];
bufOut[iOut++] = (b0 << 2) & 0xFC | (b1 >>> 4);
bufOut[iOut++] = (b1 << 4) & 0xF0 | (b2 >>> 2);
} else {
bufOut[iOut++] = (b0 << 2) & 0xFC | (b1 >>> 4);
}
}
this.write(bufOut);
pr.disconnect(this);
},
disconnect: function(f) {
let pr = pseudoRedirector;
pr.filters.delete(f);
f.disconnect();
}
};
let onBeforeRequestClient = this.onBeforeRequest.callback;
let onBeforeRequest = function(details) {
normalizeRequestDetails(details); normalizeRequestDetails(details);
return onBeforeRequestClient(details); let r = onBeforeRequestClient(details);
if (
r !== undefined &&
r.redirectUrl !== undefined &&
details.type === 'xmlhttprequest'
) {
r.redirectUrl = pseudoRedirector.start(
details.requestId,
r.redirectUrl
);
}
return r;
}; };
if ( onBeforeRequest ) { if ( onBeforeRequest ) {
@ -175,10 +250,10 @@ vAPI.net.registerListeners = function() {
); );
} }
var onHeadersReceivedClient = this.onHeadersReceived.callback, let onHeadersReceivedClient = this.onHeadersReceived.callback,
onHeadersReceivedClientTypes = this.onHeadersReceived.types.slice(0), onHeadersReceivedClientTypes = this.onHeadersReceived.types.slice(0),
onHeadersReceivedTypes = denormalizeTypes(onHeadersReceivedClientTypes); onHeadersReceivedTypes = denormalizeTypes(onHeadersReceivedClientTypes);
var onHeadersReceived = function(details) { let onHeadersReceived = function(details) {
normalizeRequestDetails(details); normalizeRequestDetails(details);
if ( if (
onHeadersReceivedClientTypes.length !== 0 && onHeadersReceivedClientTypes.length !== 0 &&