|
60 | 60 | constructor() { |
61 | 61 | super(); |
62 | 62 | this.pendingRequests = []; |
| 63 | + this.cnames = new Map(); |
| 64 | + this.cnameAliasList = null; |
| 65 | + this.cnameIgnoreList = null; |
| 66 | + this.url = new URL(vAPI.getURL('/')); |
| 67 | + this.cnameMaxTTL = 60; |
| 68 | + this.cnameTimer = undefined; |
| 69 | + } |
| 70 | + setOptions(options) { |
| 71 | + super.setOptions(options); |
| 72 | + this.cnameAliasList = this.regexFromStrList(options.cnameAliasList); |
| 73 | + this.cnameIgnoreList = this.regexFromStrList(options.cnameIgnoreList); |
| 74 | + this.cnameIgnore1stParty = options.cnameIgnore1stParty === true; |
| 75 | + this.cnameMaxTTL = options.cnameMaxTTL || 120; |
| 76 | + this.cnames.clear(); |
63 | 77 | } |
64 | 78 | normalizeDetails(details) { |
65 | 79 | if ( mustPunycode && !reAsciiHostname.test(details.url) ) { |
|
109 | 123 | } |
110 | 124 | return Array.from(out); |
111 | 125 | } |
| 126 | + processCanonicalName(cname, details) { |
| 127 | + this.url.href = details.url; |
| 128 | + details.cnameOf = this.url.hostname; |
| 129 | + this.url.hostname = cname; |
| 130 | + details.url = this.url.href; |
| 131 | + return super.onBeforeSuspendableRequest(details); |
| 132 | + } |
| 133 | + recordCanonicalName(hn, record) { |
| 134 | + let cname = |
| 135 | + typeof record.canonicalName === 'string' && |
| 136 | + record.canonicalName !== hn |
| 137 | + ? record.canonicalName |
| 138 | + : ''; |
| 139 | + if ( |
| 140 | + cname !== '' && |
| 141 | + this.cnameIgnore1stParty && |
| 142 | + vAPI.domainFromHostname(cname) === vAPI.domainFromHostname(hn) |
| 143 | + ) { |
| 144 | + cname = ''; |
| 145 | + } |
| 146 | + if ( |
| 147 | + cname !== '' && |
| 148 | + this.cnameIgnoreList !== null && |
| 149 | + this.cnameIgnoreList.test(cname) |
| 150 | + ) { |
| 151 | + |
| 152 | + cname = ''; |
| 153 | + } |
| 154 | + this.cnames.set(hn, cname); |
| 155 | + if ( this.cnameTimer === undefined ) { |
| 156 | + this.cnameTimer = self.setTimeout( |
| 157 | + ( ) => { |
| 158 | + this.cnameTimer = undefined; |
| 159 | + this.cnames.clear(); |
| 160 | + }, |
| 161 | + this.cnameMaxTTL * 60000 |
| 162 | + ); |
| 163 | + } |
| 164 | + return cname; |
| 165 | + } |
| 166 | + regexFromStrList(list) { |
| 167 | + if ( |
| 168 | + typeof list !== 'string' || |
| 169 | + list.length === 0 || |
| 170 | + list === 'unset' |
| 171 | + ) { |
| 172 | + return null; |
| 173 | + } |
| 174 | + if ( list === '*' ) { |
| 175 | + return /^./; |
| 176 | + } |
| 177 | + return new RegExp( |
| 178 | + '(?:^|\.)(?:' + |
| 179 | + list.trim() |
| 180 | + .split(/\s+/) |
| 181 | + .map(a => a.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')) |
| 182 | + .join('|') + |
| 183 | + ')$' |
| 184 | + ); |
| 185 | + } |
| 186 | + onBeforeSuspendableRequest(details) { |
| 187 | + let r = super.onBeforeSuspendableRequest(details); |
| 188 | + if ( r !== undefined ) { return r; } |
| 189 | + if ( this.cnameAliasList === null ) { return; } |
| 190 | + const hn = vAPI.hostnameFromURI(details.url); |
| 191 | + let cname = this.cnames.get(hn); |
| 192 | + if ( cname === '' ) { return; } |
| 193 | + if ( cname !== undefined ) { |
| 194 | + return this.processCanonicalName(cname, details); |
| 195 | + } |
| 196 | + if ( this.cnameAliasList.test(hn) === false ) { |
| 197 | + this.cnames.set(hn, ''); |
| 198 | + return; |
| 199 | + } |
| 200 | + return browser.dns.resolve(hn, [ 'canonical_name' ]).then(rec => { |
| 201 | + const cname = this.recordCanonicalName(hn, rec); |
| 202 | + if ( cname === '' ) { return; } |
| 203 | + return this.processCanonicalName(cname, details); |
| 204 | + |
| 205 | + }); |
| 206 | + } |
112 | 207 | suspendOneRequest(details) { |
113 | 208 | const pending = { |
114 | 209 | details: Object.assign({}, details), |
|
121 | 216 | this.pendingRequests.push(pending); |
122 | 217 | return pending.promise; |
123 | 218 | } |
124 | | - unsuspendAllRequests(resolver) { |
| 219 | + unsuspendAllRequests() { |
125 | 220 | const pendingRequests = this.pendingRequests; |
126 | 221 | this.pendingRequests = []; |
127 | 222 | for ( const entry of pendingRequests ) { |
128 | | - entry.resolve(resolver(entry.details)); |
| 223 | + entry.resolve(this.onBeforeSuspendableRequest(entry.details)); |
129 | 224 | } |
130 | 225 | } |
131 | 226 | canSuspend() { |
|
0 commit comments