mirror of https://github.com/gorhill/uBlock.git
Remove now irrelevant scoping
This commit is contained in:
parent
64909c671f
commit
15450e3957
|
@ -32,278 +32,273 @@ import {
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
(( ) => {
|
// Canonical name-uncloaking feature.
|
||||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/407
|
let cnameUncloakEnabled = browser.dns instanceof Object;
|
||||||
if ( vAPI.webextFlavor.soup.has('firefox') === false ) { return; }
|
let cnameUncloakProxied = false;
|
||||||
|
|
||||||
// Canonical name-uncloaking feature.
|
// https://github.com/uBlockOrigin/uBlock-issues/issues/911
|
||||||
let cnameUncloakEnabled = browser.dns instanceof Object;
|
// We detect here whether network requests are proxied, and if so,
|
||||||
let cnameUncloakProxied = false;
|
// de-aliasing of hostnames will be disabled to avoid possible
|
||||||
|
// DNS leaks.
|
||||||
|
const proxyDetector = function(details) {
|
||||||
|
if ( details.proxyInfo instanceof Object ) {
|
||||||
|
cnameUncloakEnabled = false;
|
||||||
|
proxyDetectorTryCount = 0;
|
||||||
|
}
|
||||||
|
if ( proxyDetectorTryCount === 0 ) {
|
||||||
|
browser.webRequest.onHeadersReceived.removeListener(proxyDetector);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
proxyDetectorTryCount -= 1;
|
||||||
|
};
|
||||||
|
let proxyDetectorTryCount = 0;
|
||||||
|
|
||||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/911
|
// Related issues:
|
||||||
// We detect here whether network requests are proxied, and if so,
|
// - https://github.com/gorhill/uBlock/issues/1327
|
||||||
// de-aliasing of hostnames will be disabled to avoid possible
|
// - https://github.com/uBlockOrigin/uBlock-issues/issues/128
|
||||||
// DNS leaks.
|
// - https://bugzilla.mozilla.org/show_bug.cgi?id=1503721
|
||||||
const proxyDetector = function(details) {
|
|
||||||
if ( details.proxyInfo instanceof Object ) {
|
|
||||||
cnameUncloakEnabled = false;
|
|
||||||
proxyDetectorTryCount = 0;
|
|
||||||
}
|
|
||||||
if ( proxyDetectorTryCount === 0 ) {
|
|
||||||
browser.webRequest.onHeadersReceived.removeListener(proxyDetector);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
proxyDetectorTryCount -= 1;
|
|
||||||
};
|
|
||||||
let proxyDetectorTryCount = 0;
|
|
||||||
|
|
||||||
// Related issues:
|
// Extend base class to normalize as per platform.
|
||||||
// - https://github.com/gorhill/uBlock/issues/1327
|
|
||||||
// - https://github.com/uBlockOrigin/uBlock-issues/issues/128
|
|
||||||
// - https://bugzilla.mozilla.org/show_bug.cgi?id=1503721
|
|
||||||
|
|
||||||
// Extend base class to normalize as per platform.
|
vAPI.Net = class extends vAPI.Net {
|
||||||
|
constructor() {
|
||||||
vAPI.Net = class extends vAPI.Net {
|
super();
|
||||||
constructor() {
|
this.pendingRequests = [];
|
||||||
super();
|
this.canUncloakCnames = browser.dns instanceof Object;
|
||||||
this.pendingRequests = [];
|
this.cnames = new Map([ [ '', null ] ]);
|
||||||
this.canUncloakCnames = browser.dns instanceof Object;
|
this.cnameIgnoreList = null;
|
||||||
this.cnames = new Map([ [ '', null ] ]);
|
this.cnameIgnore1stParty = true;
|
||||||
this.cnameIgnoreList = null;
|
this.cnameIgnoreExceptions = true;
|
||||||
this.cnameIgnore1stParty = true;
|
this.cnameIgnoreRootDocument = true;
|
||||||
this.cnameIgnoreExceptions = true;
|
this.cnameMaxTTL = 120;
|
||||||
this.cnameIgnoreRootDocument = true;
|
this.cnameReplayFullURL = false;
|
||||||
this.cnameMaxTTL = 120;
|
this.cnameFlushTime = Date.now() + this.cnameMaxTTL * 60000;
|
||||||
this.cnameReplayFullURL = false;
|
}
|
||||||
this.cnameFlushTime = Date.now() + this.cnameMaxTTL * 60000;
|
setOptions(options) {
|
||||||
|
super.setOptions(options);
|
||||||
|
if ( 'cnameUncloakEnabled' in options ) {
|
||||||
|
cnameUncloakEnabled =
|
||||||
|
this.canUncloakCnames &&
|
||||||
|
options.cnameUncloakEnabled !== false;
|
||||||
}
|
}
|
||||||
setOptions(options) {
|
if ( 'cnameUncloakProxied' in options ) {
|
||||||
super.setOptions(options);
|
cnameUncloakProxied = options.cnameUncloakProxied === true;
|
||||||
if ( 'cnameUncloakEnabled' in options ) {
|
}
|
||||||
cnameUncloakEnabled =
|
if ( 'cnameIgnoreList' in options ) {
|
||||||
this.canUncloakCnames &&
|
this.cnameIgnoreList =
|
||||||
options.cnameUncloakEnabled !== false;
|
this.regexFromStrList(options.cnameIgnoreList);
|
||||||
}
|
}
|
||||||
if ( 'cnameUncloakProxied' in options ) {
|
if ( 'cnameIgnore1stParty' in options ) {
|
||||||
cnameUncloakProxied = options.cnameUncloakProxied === true;
|
this.cnameIgnore1stParty =
|
||||||
}
|
options.cnameIgnore1stParty !== false;
|
||||||
if ( 'cnameIgnoreList' in options ) {
|
}
|
||||||
this.cnameIgnoreList =
|
if ( 'cnameIgnoreExceptions' in options ) {
|
||||||
this.regexFromStrList(options.cnameIgnoreList);
|
this.cnameIgnoreExceptions =
|
||||||
}
|
options.cnameIgnoreExceptions !== false;
|
||||||
if ( 'cnameIgnore1stParty' in options ) {
|
}
|
||||||
this.cnameIgnore1stParty =
|
if ( 'cnameIgnoreRootDocument' in options ) {
|
||||||
options.cnameIgnore1stParty !== false;
|
this.cnameIgnoreRootDocument =
|
||||||
}
|
options.cnameIgnoreRootDocument !== false;
|
||||||
if ( 'cnameIgnoreExceptions' in options ) {
|
}
|
||||||
this.cnameIgnoreExceptions =
|
if ( 'cnameMaxTTL' in options ) {
|
||||||
options.cnameIgnoreExceptions !== false;
|
this.cnameMaxTTL = options.cnameMaxTTL || 120;
|
||||||
}
|
}
|
||||||
if ( 'cnameIgnoreRootDocument' in options ) {
|
if ( 'cnameReplayFullURL' in options ) {
|
||||||
this.cnameIgnoreRootDocument =
|
this.cnameReplayFullURL = options.cnameReplayFullURL === true;
|
||||||
options.cnameIgnoreRootDocument !== false;
|
}
|
||||||
}
|
this.cnames.clear(); this.cnames.set('', null);
|
||||||
if ( 'cnameMaxTTL' in options ) {
|
this.cnameFlushTime = Date.now() + this.cnameMaxTTL * 60000;
|
||||||
this.cnameMaxTTL = options.cnameMaxTTL || 120;
|
// https://github.com/uBlockOrigin/uBlock-issues/issues/911
|
||||||
}
|
// Install/remove proxy detector.
|
||||||
if ( 'cnameReplayFullURL' in options ) {
|
if ( vAPI.webextFlavor.major < 80 ) {
|
||||||
this.cnameReplayFullURL = options.cnameReplayFullURL === true;
|
const wrohr = browser.webRequest.onHeadersReceived;
|
||||||
}
|
if ( cnameUncloakEnabled === false || cnameUncloakProxied ) {
|
||||||
this.cnames.clear(); this.cnames.set('', null);
|
if ( wrohr.hasListener(proxyDetector) ) {
|
||||||
this.cnameFlushTime = Date.now() + this.cnameMaxTTL * 60000;
|
wrohr.removeListener(proxyDetector);
|
||||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/911
|
|
||||||
// Install/remove proxy detector.
|
|
||||||
if ( vAPI.webextFlavor.major < 80 ) {
|
|
||||||
const wrohr = browser.webRequest.onHeadersReceived;
|
|
||||||
if ( cnameUncloakEnabled === false || cnameUncloakProxied ) {
|
|
||||||
if ( wrohr.hasListener(proxyDetector) ) {
|
|
||||||
wrohr.removeListener(proxyDetector);
|
|
||||||
}
|
|
||||||
} else if ( wrohr.hasListener(proxyDetector) === false ) {
|
|
||||||
wrohr.addListener(
|
|
||||||
proxyDetector,
|
|
||||||
{ urls: [ '*://*/*' ] },
|
|
||||||
[ 'blocking' ]
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
proxyDetectorTryCount = 32;
|
} else if ( wrohr.hasListener(proxyDetector) === false ) {
|
||||||
}
|
wrohr.addListener(
|
||||||
}
|
proxyDetector,
|
||||||
normalizeDetails(details) {
|
{ urls: [ '*://*/*' ] },
|
||||||
const type = details.type;
|
[ 'blocking' ]
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
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');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Array.from(out);
|
|
||||||
}
|
|
||||||
canonicalNameFromHostname(hn) {
|
|
||||||
const cnRecord = this.cnames.get(hn);
|
|
||||||
if ( cnRecord !== undefined && cnRecord !== null ) {
|
|
||||||
return cnRecord.cname;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
processCanonicalName(hn, cnRecord, details) {
|
|
||||||
if ( cnRecord === null ) { return; }
|
|
||||||
if ( cnRecord.isRootDocument ) { return; }
|
|
||||||
const hnBeg = details.url.indexOf(hn);
|
|
||||||
if ( hnBeg === -1 ) { return; }
|
|
||||||
const oldURL = details.url;
|
|
||||||
let newURL = oldURL.slice(0, hnBeg) + cnRecord.cname;
|
|
||||||
const hnEnd = hnBeg + hn.length;
|
|
||||||
if ( this.cnameReplayFullURL ) {
|
|
||||||
newURL += oldURL.slice(hnEnd);
|
|
||||||
} else {
|
|
||||||
const pathBeg = oldURL.indexOf('/', hnEnd);
|
|
||||||
if ( pathBeg !== -1 ) {
|
|
||||||
newURL += oldURL.slice(hnEnd, pathBeg + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
details.url = newURL;
|
|
||||||
details.aliasURL = oldURL;
|
|
||||||
return super.onBeforeSuspendableRequest(details);
|
|
||||||
}
|
|
||||||
recordCanonicalName(hn, record, isRootDocument) {
|
|
||||||
if ( (this.cnames.size & 0b111111) === 0 ) {
|
|
||||||
const now = Date.now();
|
|
||||||
if ( now >= this.cnameFlushTime ) {
|
|
||||||
this.cnames.clear(); this.cnames.set('', null);
|
|
||||||
this.cnameFlushTime = now + this.cnameMaxTTL * 60000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let cname =
|
|
||||||
typeof record.canonicalName === 'string' &&
|
|
||||||
record.canonicalName !== hn
|
|
||||||
? record.canonicalName
|
|
||||||
: '';
|
|
||||||
if (
|
|
||||||
cname !== '' &&
|
|
||||||
this.cnameIgnore1stParty &&
|
|
||||||
domainFromHostname(cname) === domainFromHostname(hn)
|
|
||||||
) {
|
|
||||||
cname = '';
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
cname !== '' &&
|
|
||||||
this.cnameIgnoreList !== null &&
|
|
||||||
this.cnameIgnoreList.test(cname)
|
|
||||||
) {
|
|
||||||
cname = '';
|
|
||||||
}
|
|
||||||
const cnRecord = cname !== '' ? { cname, isRootDocument } : null;
|
|
||||||
this.cnames.set(hn, cnRecord);
|
|
||||||
return cnRecord;
|
|
||||||
}
|
|
||||||
regexFromStrList(list) {
|
|
||||||
if (
|
|
||||||
typeof list !== 'string' ||
|
|
||||||
list.length === 0 ||
|
|
||||||
list === 'unset' ||
|
|
||||||
browser.dns instanceof Object === false
|
|
||||||
) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if ( list === '*' ) {
|
|
||||||
return /^./;
|
|
||||||
}
|
|
||||||
return new RegExp(
|
|
||||||
'(?:^|\.)(?:' +
|
|
||||||
list.trim()
|
|
||||||
.split(/\s+/)
|
|
||||||
.map(a => a.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))
|
|
||||||
.join('|') +
|
|
||||||
')$'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
onBeforeSuspendableRequest(details) {
|
|
||||||
const r = super.onBeforeSuspendableRequest(details);
|
|
||||||
if ( cnameUncloakEnabled === false ) { return r; }
|
|
||||||
if ( r !== undefined ) {
|
|
||||||
if (
|
|
||||||
r.cancel === true ||
|
|
||||||
r.redirectUrl !== undefined ||
|
|
||||||
this.cnameIgnoreExceptions
|
|
||||||
) {
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const isRootDocument = details.type === 'main_frame' &&
|
|
||||||
this.cnameIgnoreRootDocument;
|
|
||||||
const hn = hostnameFromNetworkURL(details.url);
|
|
||||||
const cnRecord = this.cnames.get(hn);
|
|
||||||
if ( cnRecord !== undefined ) {
|
|
||||||
return this.processCanonicalName(hn, cnRecord, details);
|
|
||||||
}
|
|
||||||
return browser.dns.resolve(hn, [ 'canonical_name' ]).then(
|
|
||||||
rec => {
|
|
||||||
const cnRecord = this.recordCanonicalName(hn, rec, isRootDocument);
|
|
||||||
return this.processCanonicalName(hn, cnRecord, details);
|
|
||||||
},
|
|
||||||
( ) => {
|
|
||||||
this.cnames.set(hn, null);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
suspendOneRequest(details) {
|
|
||||||
const pending = {
|
|
||||||
details: Object.assign({}, details),
|
|
||||||
resolve: undefined,
|
|
||||||
promise: undefined
|
|
||||||
};
|
|
||||||
pending.promise = new Promise(resolve => {
|
|
||||||
pending.resolve = resolve;
|
|
||||||
});
|
|
||||||
this.pendingRequests.push(pending);
|
|
||||||
return pending.promise;
|
|
||||||
}
|
|
||||||
unsuspendAllRequests(discard = false) {
|
|
||||||
const pendingRequests = this.pendingRequests;
|
|
||||||
this.pendingRequests = [];
|
|
||||||
for ( const entry of pendingRequests ) {
|
|
||||||
entry.resolve(
|
|
||||||
discard !== true
|
|
||||||
? this.onBeforeSuspendableRequest(entry.details)
|
|
||||||
: undefined
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
proxyDetectorTryCount = 32;
|
||||||
}
|
}
|
||||||
static canSuspend() {
|
}
|
||||||
return true;
|
normalizeDetails(details) {
|
||||||
|
const type = details.type;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
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');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Array.from(out);
|
||||||
|
}
|
||||||
|
canonicalNameFromHostname(hn) {
|
||||||
|
const cnRecord = this.cnames.get(hn);
|
||||||
|
if ( cnRecord !== undefined && cnRecord !== null ) {
|
||||||
|
return cnRecord.cname;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
processCanonicalName(hn, cnRecord, details) {
|
||||||
|
if ( cnRecord === null ) { return; }
|
||||||
|
if ( cnRecord.isRootDocument ) { return; }
|
||||||
|
const hnBeg = details.url.indexOf(hn);
|
||||||
|
if ( hnBeg === -1 ) { return; }
|
||||||
|
const oldURL = details.url;
|
||||||
|
let newURL = oldURL.slice(0, hnBeg) + cnRecord.cname;
|
||||||
|
const hnEnd = hnBeg + hn.length;
|
||||||
|
if ( this.cnameReplayFullURL ) {
|
||||||
|
newURL += oldURL.slice(hnEnd);
|
||||||
|
} else {
|
||||||
|
const pathBeg = oldURL.indexOf('/', hnEnd);
|
||||||
|
if ( pathBeg !== -1 ) {
|
||||||
|
newURL += oldURL.slice(hnEnd, pathBeg + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
details.url = newURL;
|
||||||
|
details.aliasURL = oldURL;
|
||||||
|
return super.onBeforeSuspendableRequest(details);
|
||||||
|
}
|
||||||
|
recordCanonicalName(hn, record, isRootDocument) {
|
||||||
|
if ( (this.cnames.size & 0b111111) === 0 ) {
|
||||||
|
const now = Date.now();
|
||||||
|
if ( now >= this.cnameFlushTime ) {
|
||||||
|
this.cnames.clear(); this.cnames.set('', null);
|
||||||
|
this.cnameFlushTime = now + this.cnameMaxTTL * 60000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let cname =
|
||||||
|
typeof record.canonicalName === 'string' &&
|
||||||
|
record.canonicalName !== hn
|
||||||
|
? record.canonicalName
|
||||||
|
: '';
|
||||||
|
if (
|
||||||
|
cname !== '' &&
|
||||||
|
this.cnameIgnore1stParty &&
|
||||||
|
domainFromHostname(cname) === domainFromHostname(hn)
|
||||||
|
) {
|
||||||
|
cname = '';
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
cname !== '' &&
|
||||||
|
this.cnameIgnoreList !== null &&
|
||||||
|
this.cnameIgnoreList.test(cname)
|
||||||
|
) {
|
||||||
|
cname = '';
|
||||||
|
}
|
||||||
|
const cnRecord = cname !== '' ? { cname, isRootDocument } : null;
|
||||||
|
this.cnames.set(hn, cnRecord);
|
||||||
|
return cnRecord;
|
||||||
|
}
|
||||||
|
regexFromStrList(list) {
|
||||||
|
if (
|
||||||
|
typeof list !== 'string' ||
|
||||||
|
list.length === 0 ||
|
||||||
|
list === 'unset' ||
|
||||||
|
browser.dns instanceof Object === false
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if ( list === '*' ) {
|
||||||
|
return /^./;
|
||||||
|
}
|
||||||
|
return new RegExp(
|
||||||
|
'(?:^|\.)(?:' +
|
||||||
|
list.trim()
|
||||||
|
.split(/\s+/)
|
||||||
|
.map(a => a.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))
|
||||||
|
.join('|') +
|
||||||
|
')$'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
onBeforeSuspendableRequest(details) {
|
||||||
|
const r = super.onBeforeSuspendableRequest(details);
|
||||||
|
if ( cnameUncloakEnabled === false ) { return r; }
|
||||||
|
if ( r !== undefined ) {
|
||||||
|
if (
|
||||||
|
r.cancel === true ||
|
||||||
|
r.redirectUrl !== undefined ||
|
||||||
|
this.cnameIgnoreExceptions
|
||||||
|
) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const isRootDocument = details.type === 'main_frame' &&
|
||||||
|
this.cnameIgnoreRootDocument;
|
||||||
|
const hn = hostnameFromNetworkURL(details.url);
|
||||||
|
const cnRecord = this.cnames.get(hn);
|
||||||
|
if ( cnRecord !== undefined ) {
|
||||||
|
return this.processCanonicalName(hn, cnRecord, details);
|
||||||
|
}
|
||||||
|
return browser.dns.resolve(hn, [ 'canonical_name' ]).then(
|
||||||
|
rec => {
|
||||||
|
const cnRecord = this.recordCanonicalName(hn, rec, isRootDocument);
|
||||||
|
return this.processCanonicalName(hn, cnRecord, details);
|
||||||
|
},
|
||||||
|
( ) => {
|
||||||
|
this.cnames.set(hn, null);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
suspendOneRequest(details) {
|
||||||
|
const pending = {
|
||||||
|
details: Object.assign({}, details),
|
||||||
|
resolve: undefined,
|
||||||
|
promise: undefined
|
||||||
|
};
|
||||||
|
pending.promise = new Promise(resolve => {
|
||||||
|
pending.resolve = resolve;
|
||||||
|
});
|
||||||
|
this.pendingRequests.push(pending);
|
||||||
|
return pending.promise;
|
||||||
|
}
|
||||||
|
unsuspendAllRequests(discard = false) {
|
||||||
|
const pendingRequests = this.pendingRequests;
|
||||||
|
this.pendingRequests = [];
|
||||||
|
for ( const entry of pendingRequests ) {
|
||||||
|
entry.resolve(
|
||||||
|
discard !== true
|
||||||
|
? this.onBeforeSuspendableRequest(entry.details)
|
||||||
|
: undefined
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static canSuspend() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
Loading…
Reference in New Issue