Code review of DNS-related code

Related commit:
6acf97bf51
This commit is contained in:
Raymond Hill 2024-09-13 10:00:41 -04:00
parent 8fadfb2c5e
commit 73ee3ffe92
No known key found for this signature in database
GPG Key ID: 25E1490B761470C2
1 changed files with 44 additions and 28 deletions

View File

@ -27,10 +27,13 @@ import {
/******************************************************************************/ /******************************************************************************/
const dnsAPI = browser.dns; const dnsAPI = browser.dns;
const isPromise = o => o instanceof Promise; const isPromise = o => o instanceof Promise;
const isResolvedObject = o => o instanceof Object &&
o instanceof Promise === false;
const reIPv4 = /^\d+\.\d+\.\d+\.\d+$/ const reIPv4 = /^\d+\.\d+\.\d+\.\d+$/
/******************************************************************************/
// Related issues: // Related issues:
// - https://github.com/gorhill/uBlock/issues/1327 // - https://github.com/gorhill/uBlock/issues/1327
// - https://github.com/uBlockOrigin/uBlock-issues/issues/128 // - https://github.com/uBlockOrigin/uBlock-issues/issues/128
@ -87,12 +90,10 @@ vAPI.Net = class extends vAPI.Net {
normalizeDetails(details) { normalizeDetails(details) {
const type = details.type; const type = details.type;
if ( type === 'imageset' ) { if ( type === 'imageset' ) {
details.type = 'image'; details.type = 'image';
return; return;
} }
// https://github.com/uBlockOrigin/uBlock-issues/issues/345 // https://github.com/uBlockOrigin/uBlock-issues/issues/345
// Re-categorize an embedded object as a `sub_frame` if its // Re-categorize an embedded object as a `sub_frame` if its
// content type is that of a HTML document. // content type is that of a HTML document.
@ -130,8 +131,8 @@ vAPI.Net = class extends vAPI.Net {
canonicalNameFromHostname(hn) { canonicalNameFromHostname(hn) {
if ( hn === '' ) { return; } if ( hn === '' ) { return; }
const dnsEntry = this.dnsFromCache(hn); const dnsEntry = this.dnsFromCache(hn);
if ( isPromise(dnsEntry) ) { return; } if ( isResolvedObject(dnsEntry) === false ) { return; }
return dnsEntry?.cname; return dnsEntry.cname;
} }
regexFromStrList(list) { regexFromStrList(list) {
@ -152,7 +153,7 @@ vAPI.Net = class extends vAPI.Net {
onBeforeSuspendableRequest(details) { onBeforeSuspendableRequest(details) {
const hn = hostnameFromNetworkURL(details.url); const hn = hostnameFromNetworkURL(details.url);
const dnsEntry = this.dnsFromCache(hn); const dnsEntry = this.dnsFromCache(hn);
if ( dnsEntry?.ip ) { if ( isResolvedObject(dnsEntry) && dnsEntry.ip ) {
details.ip = dnsEntry.ip; details.ip = dnsEntry.ip;
} }
const r = super.onBeforeSuspendableRequest(details); const r = super.onBeforeSuspendableRequest(details);
@ -165,10 +166,8 @@ vAPI.Net = class extends vAPI.Net {
return r; return r;
} }
} }
if ( dnsEntry !== undefined ) { if ( isResolvedObject(dnsEntry) ) {
if ( isPromise(dnsEntry) === false ) { return this.onAfterDNSResolution(hn, details, dnsEntry);
return this.onAfterDNSResolution(hn, details, dnsEntry);
}
} }
if ( this.dnsShouldResolve(hn) === false ) { return; } if ( this.dnsShouldResolve(hn) === false ) { return; }
if ( details.proxyInfo?.proxyDNS ) { return; } if ( details.proxyInfo?.proxyDNS ) { return; }
@ -179,7 +178,7 @@ vAPI.Net = class extends vAPI.Net {
onAfterDNSResolution(hn, details, dnsEntry) { onAfterDNSResolution(hn, details, dnsEntry) {
if ( dnsEntry === undefined ) { if ( dnsEntry === undefined ) {
dnsEntry = this.dnsFromCache(hn); dnsEntry = this.dnsFromCache(hn);
if ( dnsEntry === undefined || isPromise(dnsEntry) ) { return; } if ( isResolvedObject(dnsEntry) === false ) { return; }
} }
let proceed = false; let proceed = false;
if ( dnsEntry.cname && this.cnameUncloakEnabled ) { if ( dnsEntry.cname && this.cnameUncloakEnabled ) {
@ -200,32 +199,51 @@ vAPI.Net = class extends vAPI.Net {
} }
dnsToCache(hn, record, details) { dnsToCache(hn, record, details) {
const i = this.dnsDict.get(hn); const dnsEntry = { hn, until: Date.now() + this.dnsEntryTTL };
if ( i === undefined ) { return; }
const dnsEntry = {
hn,
until: Date.now() + this.dnsEntryTTL,
};
if ( record ) { if ( record ) {
const cname = this.cnameFromRecord(hn, record, details); const cname = this.cnameFromRecord(hn, record, details);
if ( cname ) { dnsEntry.cname = cname; } if ( cname ) { dnsEntry.cname = cname; }
const ip = this.ipFromRecord(record); const ip = this.ipFromRecord(record);
if ( ip ) { dnsEntry.ip = ip; } if ( ip ) { dnsEntry.ip = ip; }
} }
this.dnsList[i] = dnsEntry; this.dnsSetCache(-1, hn, dnsEntry);
return dnsEntry; return dnsEntry;
} }
dnsFromCache(hn) { dnsFromCache(hn) {
const i = this.dnsDict.get(hn); const i = this.dnsDict.get(hn);
if ( i === undefined ) { return; } if ( i === undefined ) { return; }
if ( isPromise(i) ) { return i; }
const dnsEntry = this.dnsList[i]; const dnsEntry = this.dnsList[i];
if ( dnsEntry === null ) { return; } if ( dnsEntry !== null && dnsEntry.hn === hn ) {
if ( isPromise(dnsEntry) ) { return dnsEntry; } if ( dnsEntry.until >= Date.now() ) {
if ( dnsEntry.hn !== hn ) { return; } return dnsEntry;
if ( dnsEntry.until >= Date.now() ) { return dnsEntry; } }
this.dnsList[i] = null; }
this.dnsDict.delete(hn) this.dnsSetCache(i);
}
dnsSetCache(i, hn, after) {
if ( i < 0 ) {
const j = this.dnsDict.get(hn);
if ( typeof j === 'number' ) {
this.dnsList[j] = after;
return;
}
i = this.dnsWritePtr++;
this.dnsWritePtr %= this.dnsMaxCount;
}
const before = this.dnsList[i];
if ( before ) {
this.dnsDict.delete(before.hn);
}
if ( after ) {
this.dnsDict.set(hn, i);
this.dnsList[i] = after;
} else {
if ( hn ) { this.dnsDict.delete(hn); }
this.dnsList[i] = null;
}
} }
dnsShouldResolve(hn) { dnsShouldResolve(hn) {
@ -237,14 +255,12 @@ vAPI.Net = class extends vAPI.Net {
} }
dnsResolve(hn, details) { dnsResolve(hn, details) {
const i = this.dnsWritePtr++;
this.dnsWritePtr %= this.dnsMaxCount;
this.dnsDict.set(hn, i);
const promise = dnsAPI.resolve(hn, [ 'canonical_name' ]).then( const promise = dnsAPI.resolve(hn, [ 'canonical_name' ]).then(
rec => this.dnsToCache(hn, rec, details), rec => this.dnsToCache(hn, rec, details),
( ) => this.dnsToCache(hn) ( ) => this.dnsToCache(hn)
); );
return (this.dnsList[i] = promise); this.dnsDict.set(hn, promise);
return promise;
} }
cnameFromRecord(hn, record, details) { cnameFromRecord(hn, record, details) {