mirror of https://github.com/gorhill/uBlock.git
Improve `no-xhr-if` scriptlet
Now support AdGuard's `randomize` parameter. If `true`, the scriplet will generate a random 10-character string to be returned as the response. Reference: https://github.com/AdguardTeam/Scriptlets/blob/master/wiki/about-scriptlets.md#prevent-xhr AdGuard's `prevent-xhr` also support `length:n-m` form, but since I do not see it being used, for now it's not supported in uBO's `no-xhr-if`. Additionally, the scriptlet will now honor `responseType` and return the proper response type accordingly.
This commit is contained in:
parent
21fe1c2df8
commit
418087de9c
|
@ -1929,52 +1929,29 @@ builtinScriptlets.push({
|
||||||
],
|
],
|
||||||
fn: noXhrIf,
|
fn: noXhrIf,
|
||||||
dependencies: [
|
dependencies: [
|
||||||
'safe-self.fn',
|
'match-object-properties.fn',
|
||||||
|
'parse-properties-to-match.fn',
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
function noXhrIf(
|
function noXhrIf(
|
||||||
arg1 = ''
|
propsToMatch = '',
|
||||||
|
randomize = ''
|
||||||
) {
|
) {
|
||||||
if ( typeof arg1 !== 'string' ) { return; }
|
if ( typeof propsToMatch !== 'string' ) { return; }
|
||||||
const safe = safeSelf();
|
|
||||||
const xhrInstances = new WeakMap();
|
const xhrInstances = new WeakMap();
|
||||||
const needles = [];
|
const propNeedles = parsePropertiesToMatch(propsToMatch, 'url');
|
||||||
for ( const condition of arg1.split(/\s+/) ) {
|
const log = propNeedles.size === 0 ? console.log.bind(console) : undefined;
|
||||||
if ( condition === '' ) { continue; }
|
|
||||||
const pos = condition.indexOf(':');
|
|
||||||
let key, value;
|
|
||||||
if ( pos !== -1 ) {
|
|
||||||
key = condition.slice(0, pos);
|
|
||||||
value = condition.slice(pos + 1);
|
|
||||||
} else {
|
|
||||||
key = 'url';
|
|
||||||
value = condition;
|
|
||||||
}
|
|
||||||
needles.push({ key, re: safe.patternToRegex(value) });
|
|
||||||
}
|
|
||||||
const log = needles.length === 0 ? console.log.bind(console) : undefined;
|
|
||||||
self.XMLHttpRequest = class extends self.XMLHttpRequest {
|
self.XMLHttpRequest = class extends self.XMLHttpRequest {
|
||||||
open(...args) {
|
open(method, url, ...args) {
|
||||||
if ( log !== undefined ) {
|
if ( log !== undefined ) {
|
||||||
log(`uBO: xhr.open(${args.join(', ')})`);
|
log(`uBO: xhr.open(${method}, ${url}, ${args.join(', ')})`);
|
||||||
} else {
|
} else {
|
||||||
const argNames = [ 'method', 'url' ];
|
const haystack = { method, url };
|
||||||
const haystack = new Map();
|
if ( matchObjectProperties(propNeedles, haystack) ) {
|
||||||
for ( let i = 0; i < args.length && i < argNames.length; i++ ) {
|
xhrInstances.set(this, haystack);
|
||||||
haystack.set(argNames[i], args[i]);
|
|
||||||
}
|
|
||||||
if ( haystack.size !== 0 ) {
|
|
||||||
let matches = true;
|
|
||||||
for ( const { key, re } of needles ) {
|
|
||||||
matches = re.test(haystack.get(key) || '');
|
|
||||||
if ( matches === false ) { break; }
|
|
||||||
}
|
|
||||||
if ( matches ) {
|
|
||||||
xhrInstances.set(this, haystack);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return super.open(...args);
|
return super.open(method, url, ...args);
|
||||||
}
|
}
|
||||||
send(...args) {
|
send(...args) {
|
||||||
const haystack = xhrInstances.get(this);
|
const haystack = xhrInstances.get(this);
|
||||||
|
@ -1982,13 +1959,45 @@ function noXhrIf(
|
||||||
return super.send(...args);
|
return super.send(...args);
|
||||||
}
|
}
|
||||||
Object.defineProperties(this, {
|
Object.defineProperties(this, {
|
||||||
readyState: { value: 4, writable: false },
|
readyState: { value: 4 },
|
||||||
response: { value: '', writable: false },
|
responseURL: { value: haystack.url },
|
||||||
responseText: { value: '', writable: false },
|
status: { value: 200 },
|
||||||
responseURL: { value: haystack.get('url'), writable: false },
|
statusText: { value: 'OK' },
|
||||||
responseXML: { value: '', writable: false },
|
});
|
||||||
status: { value: 200, writable: false },
|
let response = '';
|
||||||
statusText: { value: 'OK', writable: false },
|
let responseText = '';
|
||||||
|
let responseXML = null;
|
||||||
|
switch ( this.responseType ) {
|
||||||
|
case 'arraybuffer':
|
||||||
|
response = new ArrayBuffer(0);
|
||||||
|
break;
|
||||||
|
case 'blob':
|
||||||
|
response = new Blob([]);
|
||||||
|
break;
|
||||||
|
case 'document': {
|
||||||
|
const parser = new DOMParser();
|
||||||
|
const doc = parser.parseFromString('', 'text/html');
|
||||||
|
response = doc;
|
||||||
|
responseXML = doc;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'json':
|
||||||
|
response = {};
|
||||||
|
responseText = '{}';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if ( randomize !== 'true' ) { break; }
|
||||||
|
do {
|
||||||
|
response += Math.random().toString(36).slice(-2);
|
||||||
|
} while ( response.length < 10 );
|
||||||
|
response = response.slice(-10);
|
||||||
|
responseText = response;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Object.defineProperties(this, {
|
||||||
|
response: { value: response },
|
||||||
|
responseText: { value: responseText },
|
||||||
|
responseXML: { value: responseXML },
|
||||||
});
|
});
|
||||||
this.dispatchEvent(new Event('readystatechange'));
|
this.dispatchEvent(new Event('readystatechange'));
|
||||||
this.dispatchEvent(new Event('load'));
|
this.dispatchEvent(new Event('load'));
|
||||||
|
|
Loading…
Reference in New Issue