Imrpove no-xhr-if scriptlet · gorhill/uBlock@bf591d9 (original) (raw)
`@@ -1935,21 +1935,55 @@ builtinScriptlets.push({
`
1935
1935
`});
`
1936
1936
`function noXhrIf(
`
1937
1937
`propsToMatch = '',
`
1938
``
`-
randomize = ''
`
``
1938
`+
directive = ''
`
1939
1939
`) {
`
1940
1940
`if ( typeof propsToMatch !== 'string' ) { return; }
`
1941
1941
`const xhrInstances = new WeakMap();
`
1942
1942
`const propNeedles = parsePropertiesToMatch(propsToMatch, 'url');
`
1943
1943
`const log = propNeedles.size === 0 ? console.log.bind(console) : undefined;
`
``
1944
`+
const warOrigin = scriptletGlobals.get('warOrigin');
`
``
1945
`+
const generateRandomString = len => {
`
``
1946
`+
let s = '';
`
``
1947
`+
do { s += Math.random().toString(36).slice(2); }
`
``
1948
`+
while ( s.length < 10 );
`
``
1949
`+
return s.slice(0, len);
`
``
1950
`+
};
`
``
1951
`+
const generateContent = async directive => {
`
``
1952
`+
if ( directive === 'true' ) {
`
``
1953
`+
return generateRandomString(10);
`
``
1954
`+
}
`
``
1955
`+
if ( directive.startsWith('war:') ) {
`
``
1956
`+
if ( warOrigin === undefined ) { return ''; }
`
``
1957
`+
const warName = directive.slice(4);
`
``
1958
`+
const fullpath = [ warOrigin, '/', warName ];
`
``
1959
`+
const warSecret = scriptletGlobals.get('warSecret') || '';
`
``
1960
`+
if ( warSecret !== '' ) {
`
``
1961
`+
fullpath.push('?secret=', warSecret);
`
``
1962
`+
}
`
``
1963
`+
return new Promise(resolve => {
`
``
1964
`+
const warXHR = new XMLHttpRequest();
`
``
1965
`+
warXHR.responseType = 'text';
`
``
1966
`+
warXHR.onloadend = ev => {
`
``
1967
`+
resolve(ev.target.responseText || '');
`
``
1968
`+
};
`
``
1969
`+
warXHR.open('GET', fullpath.join(''));
`
``
1970
`+
warXHR.send();
`
``
1971
`+
});
`
``
1972
`+
}
`
``
1973
`+
return '';
`
``
1974
`+
};
`
1944
1975
`self.XMLHttpRequest = class extends self.XMLHttpRequest {
`
1945
1976
`open(method, url, ...args) {
`
1946
1977
`if ( log !== undefined ) {
`
1947
1978
`` log(uBO: xhr.open(${method}, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mi>u</mi><mi>r</mi><mi>l</mi></mrow><mo separator="true">,</mo></mrow><annotation encoding="application/x-tex">{url}, </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord"><span class="mord mathnormal">u</span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span></span><span class="mpunct">,</span></span></span></span>{args.join(', ')}));
``
1948
``
`-
} else {
`
1949
``
`-
const haystack = { method, url };
`
1950
``
`-
if ( matchObjectProperties(propNeedles, haystack) ) {
`
1951
``
`-
xhrInstances.set(this, haystack);
`
1952
``
`-
}
`
``
1979
`+
return super.open(method, url, ...args);
`
``
1980
`+
}
`
``
1981
`+
if ( warOrigin !== undefined && url.startsWith(warOrigin) ) {
`
``
1982
`+
return super.open(method, url, ...args);
`
``
1983
`+
}
`
``
1984
`+
const haystack = { method, url };
`
``
1985
`+
if ( matchObjectProperties(propNeedles, haystack) ) {
`
``
1986
`+
xhrInstances.set(this, haystack);
`
1953
1987
`}
`
1954
1988
`return super.open(method, url, ...args);
`
1955
1989
`}
`
`@@ -1958,50 +1992,66 @@ function noXhrIf(
`
1958
1992
`if ( haystack === undefined ) {
`
1959
1993
`return super.send(...args);
`
1960
1994
`}
`
1961
``
`-
Object.defineProperties(this, {
`
1962
``
`-
readyState: { value: 4 },
`
1963
``
`-
responseURL: { value: haystack.url },
`
1964
``
`-
status: { value: 200 },
`
1965
``
`-
statusText: { value: 'OK' },
`
``
1995
`+
let promise = Promise.resolve({
`
``
1996
`+
xhr: this,
`
``
1997
`+
directive,
`
``
1998
`+
props: {
`
``
1999
`+
readyState: { value: 4 },
`
``
2000
`+
response: { value: '' },
`
``
2001
`+
responseText: { value: '' },
`
``
2002
`+
responseXML: { value: null },
`
``
2003
`+
responseURL: { value: haystack.url },
`
``
2004
`+
status: { value: 200 },
`
``
2005
`+
statusText: { value: 'OK' },
`
``
2006
`+
},
`
1966
2007
`});
`
1967
``
`-
let response = '';
`
1968
``
`-
let responseText = '';
`
1969
``
`-
let responseXML = null;
`
1970
2008
`switch ( this.responseType ) {
`
1971
2009
`case 'arraybuffer':
`
1972
``
`-
response = new ArrayBuffer(0);
`
``
2010
`+
promise = promise.then(details => {
`
``
2011
`+
details.props.response.value = new ArrayBuffer(0);
`
``
2012
`+
return details;
`
``
2013
`+
});
`
1973
2014
`break;
`
1974
2015
`case 'blob':
`
1975
``
`-
response = new Blob([]);
`
``
2016
`+
promise = promise.then(details => {
`
``
2017
`+
details.props.response.value = new Blob([]);
`
``
2018
`+
return details;
`
``
2019
`+
});
`
1976
2020
`break;
`
1977
2021
`case 'document': {
`
1978
``
`-
const parser = new DOMParser();
`
1979
``
`-
const doc = parser.parseFromString('', 'text/html');
`
1980
``
`-
response = doc;
`
1981
``
`-
responseXML = doc;
`
``
2022
`+
promise = promise.then(details => {
`
``
2023
`+
const parser = new DOMParser();
`
``
2024
`+
const doc = parser.parseFromString('', 'text/html');
`
``
2025
`+
details.props.response.value = doc;
`
``
2026
`+
details.props.responseXML.value = doc;
`
``
2027
`+
return details;
`
``
2028
`+
});
`
1982
2029
`break;
`
1983
2030
`}
`
1984
2031
`case 'json':
`
1985
``
`-
response = {};
`
1986
``
`-
responseText = '{}';
`
``
2032
`+
promise = promise.then(details => {
`
``
2033
`+
details.props.response.value = {};
`
``
2034
`+
details.props.responseText.value = '{}';
`
``
2035
`+
return details;
`
``
2036
`+
});
`
1987
2037
`break;
`
1988
2038
`default:
`
1989
``
`-
if ( randomize !== 'true' ) { break; }
`
1990
``
`-
do {
`
1991
``
`-
response += Math.random().toString(36).slice(-2);
`
1992
``
`-
} while ( response.length < 10 );
`
1993
``
`-
response = response.slice(-10);
`
1994
``
`-
responseText = response;
`
``
2039
`+
if ( directive === '' ) { break; }
`
``
2040
`+
promise = promise.then(details => {
`
``
2041
`+
return generateContent(details.directive).then(text => {
`
``
2042
`+
details.props.response.value = text;
`
``
2043
`+
details.props.responseText.value = text;
`
``
2044
`+
return details;
`
``
2045
`+
});
`
``
2046
`+
});
`
1995
2047
`break;
`
1996
2048
`}
`
1997
``
`-
Object.defineProperties(this, {
`
1998
``
`-
response: { value: response },
`
1999
``
`-
responseText: { value: responseText },
`
2000
``
`-
responseXML: { value: responseXML },
`
``
2049
`+
promise.then(details => {
`
``
2050
`+
Object.defineProperties(details.xhr, details.props);
`
``
2051
`+
details.xhr.dispatchEvent(new Event('readystatechange'));
`
``
2052
`+
details.xhr.dispatchEvent(new Event('load'));
`
``
2053
`+
details.xhr.dispatchEvent(new Event('loadend'));
`
2001
2054
`});
`
2002
``
`-
this.dispatchEvent(new Event('readystatechange'));
`
2003
``
`-
this.dispatchEvent(new Event('load'));
`
2004
``
`-
this.dispatchEvent(new Event('loadend'));
`
2005
2055
`}
`
2006
2056
`};
`
2007
2057
`}
`