diff options
author | toasted-nutbread <toasted-nutbread@users.noreply.github.com> | 2020-12-18 17:18:00 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-12-18 17:18:00 -0500 |
commit | 2fa9b915159d0bc43687e032d5f7f53197ef0611 (patch) | |
tree | 9dfa01d93311704087493dcf458e126fe0f2288c /ext/bg/js | |
parent | 05d4049f16715194842cf8cdf62345478288ee71 (diff) |
Add support for using declarativeNetRequest (#1127)
Diffstat (limited to 'ext/bg/js')
-rw-r--r-- | ext/bg/js/backend.js | 1 | ||||
-rw-r--r-- | ext/bg/js/request-builder.js | 133 |
2 files changed, 134 insertions, 0 deletions
diff --git a/ext/bg/js/backend.js b/ext/bg/js/backend.js index 322d9400..205c06b1 100644 --- a/ext/bg/js/backend.js +++ b/ext/bg/js/backend.js @@ -187,6 +187,7 @@ class Backend { yomichan.on('log', this._onLog.bind(this)); + await this._requestBuilder.prepare(); await this._environment.prepare(); this._clipboardReader.browser = this._environment.getInfo().browser; diff --git a/ext/bg/js/request-builder.js b/ext/bg/js/request-builder.js index e4380734..9c469056 100644 --- a/ext/bg/js/request-builder.js +++ b/ext/bg/js/request-builder.js @@ -19,9 +19,22 @@ class RequestBuilder { constructor() { this._extraHeadersSupported = null; this._onBeforeSendHeadersExtraInfoSpec = ['blocking', 'requestHeaders', 'extraHeaders']; + this._textEncoder = new TextEncoder(); + this._ruleIds = new Set(); + } + + async prepare() { + try { + await this._clearDynamicRules(); + } catch (e) { + // NOP + } } async fetchAnonymous(url, init) { + if (isObject(chrome.declarativeNetRequest)) { + return await this._fetchAnonymousDeclarative(url, init); + } const originURL = this._getOriginURL(url); const modifications = [ ['cookie', null], @@ -130,4 +143,124 @@ class RequestBuilder { } } } + + async _clearDynamicRules() { + if (!isObject(chrome.declarativeNetRequest)) { return; } + + const rules = this._getDynamicRules(); + + if (rules.length === 0) { return; } + + const removeRuleIds = []; + for (const {id} of rules) { + removeRuleIds.push(id); + } + + await this._updateDynamicRules({removeRuleIds}); + } + + async _fetchAnonymousDeclarative(url, init) { + const id = this._getNewRuleId(); + const originUrl = this._getOriginURL(url); + url = encodeURI(decodeURI(url)); + + this._ruleIds.add(id); + try { + const addRules = [{ + id, + priority: 1, + condition: { + urlFilter: `|${this._escapeDnrUrl(url)}|`, + resourceTypes: ['xmlhttprequest'] + }, + action: { + type: 'modifyHeaders', + requestHeaders: [ + { + operation: 'remove', + header: 'Cookie' + }, + { + operation: 'set', + header: 'Origin', + value: originUrl + } + ], + responseHeaders: [ + { + operation: 'remove', + header: 'Set-Cookie' + } + ] + } + }]; + + await this._updateDynamicRules({addRules}); + try { + return await fetch(url, init); + } finally { + await this._tryUpdateDynamicRules({removeRuleIds: [id]}); + } + } finally { + this._ruleIds.delete(id); + } + } + + _getDynamicRules() { + return new Promise((resolve, reject) => { + chrome.declarativeNetRequest.getDynamicRules((result) => { + const e = chrome.runtime.lastError; + if (e) { + reject(new Error(e.message)); + } else { + resolve(result); + } + }); + }); + } + + _updateDynamicRules(options) { + return new Promise((resolve, reject) => { + chrome.declarativeNetRequest.updateDynamicRules(options, () => { + const e = chrome.runtime.lastError; + if (e) { + reject(new Error(e.message)); + } else { + resolve(); + } + }); + }); + } + + async _tryUpdateDynamicRules(options) { + try { + await this._updateDynamicRules(options); + return true; + } catch (e) { + return false; + } + } + + _getNewRuleId() { + let id = 1; + while (this._ruleIds.has(id)) { + const pre = id; + ++id; + if (id === pre) { throw new Error('Could not generate an id'); } + } + return id; + } + + _escapeDnrUrl(url) { + return url.replace(/[|*^]/g, (char) => this._urlEncodeUtf8(char)); + } + + _urlEncodeUtf8(text) { + const array = this._textEncoder.encode(text); + let result = ''; + for (const byte of array) { + result += `%${byte.toString(16).toUpperCase().padStart(2, '0')}`; + } + return result; + } } |