Skip to content

Commit

Permalink
fix: rewrite netrequest manager to be stateless.
Browse files Browse the repository at this point in the history
  • Loading branch information
svrnm committed Sep 27, 2022
1 parent 41ccec2 commit 037bc2e
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 144 deletions.
31 changes: 11 additions & 20 deletions src/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,7 @@ try {
scope.chrome.storage.session.set({ badgeData: { timer, tabs } })
})

const netRequestManager = new NetRequestManager(scope.chrome.declarativeNetRequest, scope.chrome.tabs.query, logger, ({ list, tabs, index }) => {
scope.chrome.storage.session.set({ netRequestManagerData: { list, tabs, index } })
})
const netRequestManager = new NetRequestManager(scope.chrome.declarativeNetRequest, logger)

const liveModeAlarm = new LiveModeAlarm(scope.chrome.alarms, logger, badge, ({ startTime }) => {
scope.chrome.storage.session.set({ liveModeAlarmData: { startTime } })
Expand All @@ -44,11 +42,6 @@ try {
badgeData: {
timer: -1, tabs: []
},
netRequestManagerData: {
list: {},
tabs: {},
index: 1
},
liveModeAlarmData: {
startTime: -1
},
Expand All @@ -57,7 +50,6 @@ try {
}
}, ({ badgeData, netRequestManagerData, liveModeAlarmData, hotKeyGroupData }) => {
badge.load(badgeData.tabs, badgeData.timer)
netRequestManager.load(netRequestManagerData.list, netRequestManagerData.tabs, netRequestManagerData.index)
liveModeAlarm.load(liveModeAlarmData.startTime)
enabledHotkeyGroup = hotKeyGroupData.enabledHotkeyGroup
})
Expand All @@ -82,11 +74,6 @@ try {
badge.updateDemoCounter(0, tab.id)
})

scope.chrome.tabs.onRemoved.addListener(function (tab) {
logger('debug', 'Tab closed', tab.id).write()
netRequestManager.removeTab(tab.id)
})

/*
* The following replaces the declarative content scripts, which require
* high host permissions.
Expand All @@ -98,8 +85,6 @@ try {
scope.chrome.tabs.get(tabId, (tab) => {
if (tab.url) {
logger('debug', 'Trying to inject for', tabId, tab.url).write()
netRequestManager.updateTab(tabId, tab.url)
logger('debug', 'Saved ...').write()
scope.chrome.scripting.executeScript({
target: { tabId, allFrames: true },
files: ['js/monkey.js'],
Expand All @@ -115,7 +100,13 @@ try {
})

scope.chrome.tabs.onRemoved.addListener(function (tabId) {
logger('debug', 'Tab closed, cleaning up badge & netRequestManager', tabId).write()
badge.removeTab(tabId)
netRequestManager.removeTab(tabId)
})

scope.chrome.tabs.onRemoved.addListener(function (tab) {
// TODO: netRequestManager & badge cleanup
})

scope.chrome.tabs.onActivated.addListener(function (tab) {
Expand All @@ -128,11 +119,11 @@ try {
if (typeof request.count === 'number' && typeof sender.tab === 'object' && typeof sender.tab.id === 'number') {
badge.updateDemoCounter(request.count, sender.tab.id)
}
if (request.task && request.task === 'addUrl' && typeof request.url === 'object') {
netRequestManager.add(request.url)
if (request.task && request.task === 'addUrl' && typeof request.description === 'object') {
netRequestManager.add(request.description, sender.tab.id)
}
if (request.task && request.task === 'removeUrl' && typeof request.id === 'string') {
netRequestManager.remove(request.id)
if (request.task && request.task === 'removeUrl' && typeof request.description === 'object') {
netRequestManager.remove(request.description, sender.tab.id)
}
if (request.task && request.task === 'clearUrls') {
netRequestManager.clear()
Expand Down
12 changes: 7 additions & 5 deletions src/commands/InterceptWebRequest.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,19 +46,21 @@ class InterceptWebRequest extends Command {

apply(target, key = 'value') {
target.add({
id: this.id,
url: this.search,
action: this.action,
type: this.type,
options: this.options,
includeRules: this.includeRules,
excludeRules: this.excludeRules
options: this.options
})

return {
target,
apply: () => {
target.remove(this.id)
target.remove({
url: this.search,
action: this.action,
type: this.type,
options: this.options
})
return true
}
}
Expand Down
188 changes: 73 additions & 115 deletions src/models/NetRequestManager.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,3 @@
/**
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import MatchRule from './MatchRule'

/**
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -27,14 +12,9 @@ import MatchRule from './MatchRule'
* limitations under the License.
*/
class NetRequestManager {
constructor(declarativeNetRequest, tabsQuery, logger, onSave) {
constructor(declarativeNetRequest, logger, onSave) {
this.declarativeNetRequest = declarativeNetRequest
this.tabsQuery = tabsQuery
this.logger = logger
this.list = {}
this.tabs = {}
this.index = 1
this.onSave = onSave
}

load(list, tabs, index) {
Expand All @@ -54,13 +34,6 @@ class NetRequestManager {
enable() {
this.logger('debug', 'Enable net request manager').write()
this.clear()
this.tabsQuery({}, (tabs) => {
tabs.forEach(tab => {
if (tab.url) {
this.updateTab(tab.id, tab.url)
}
})
})
}

disable() {
Expand All @@ -75,112 +48,97 @@ class NetRequestManager {
return type.split(',')
}

_getTabIds(includeRules, excludeRules) {
return Object.keys(this.tabs).reduce((accumulator, id) => {
// console.log(includeRules, excludeRules, this.tabs[id])
if (new MatchRule(includeRules, excludeRules).test(this.tabs[id])) {
accumulator.push(parseInt(id))
add(description, tabId) {
this.declarativeNetRequest.getSessionRules(rules => {
const resourceTypes = this._getResourceType(description.type)
const existingRule = rules.find(({ action, condition }) => {
return action.type === description.action &&
condition.resourceTypes.join(',') === resourceTypes.join(',') &&
condition.urlFilter === description.url &&
(description.action !== 'redirect' || action.redirect.url === description.options.redirect)
})
if (existingRule) {
this.logger('debug', 'Use existing rule for tab', tabId, 'and rule ', description).write()
existingRule.condition.tabIds.push(tabId)
this.declarativeNetRequest.updateSessionRules({
addRules: [existingRule],
removeRuleIds: [existingRule.id] // remove existing rule and then have it re-added
})
} else {
this.logger('debug', 'Add a new rule for tab', tabId, 'and rule ', description).write()
const rule = {
id: rules.length + 1,
priority: 1,
action: {
type: description.action
},
condition: {
resourceTypes,
urlFilter: description.url,
tabIds: [tabId]
}
}
if (description.action === 'redirect') {
rule.action.redirect = {
url: description.options.redirect
}
}
this.declarativeNetRequest.updateSessionRules({
addRules: [rule]
})
}
return accumulator
}, [])
})
}

add(description) {
this.logger('debug', 'Add web hook', description.id).write()

const id = this.list[description.id] ? this.list[description.id].rule.id : this.index++

const rule = {
id,
priority: 1,
action: {
type: description.action
},
condition: {
resourceTypes: this._getResourceType(description.type),
urlFilter: description.url,
tabIds: this._getTabIds(description.includeRules, description.excludeRules)
}
}
if (description.action === 'redirect') {
rule.action.redirect = {
url: description.options.redirect
}
}
// console.log(description, rule)

this.list[description.id] = {
rule,
includeRules: description.includeRules,
excludeRules: description.excludeRules
}

// tab list must not be empty
if (rule.condition.tabIds.length > 0) {
this.declarativeNetRequest.updateSessionRules({
addRules: [rule],
removeRuleIds: [rule.id] // noop?
remove(description, tabId) {
this.declarativeNetRequest.getSessionRules(rules => {
const resourceTypes = this._getResourceType(description.type)
this.logger('debug', 'Remove web hook from tab', tabId, ':', description).write()
const existingRule = rules.find(({ action, condition }) => {
return action.type === description.action &&
condition.resourceTypes === resourceTypes &&
condition.urlFilter === description.url &&
(description.action !== 'redirect' || action.redirect.url === description.options.redirect)
})
}

this.save()
}

remove(id) {
if (this.list[id]) {
this.logger('debug', 'Remove web hook', id).write()
const { rule } = this.list[id]
this.declarativeNetRequest.updateDynamicRules(
{
removeRuleIds: [rule.id]
if (existingRule) {
existingRule.condition.tabIds = existingRule.condition.tabIds.filter(id => id !== tabId)
if (existingRule.condition.tabIds.length > 0) {
this.declarativeNetRequest.updateSessionRules({
addRules: [existingRule],
removeRuleIds: [existingRule.id] // remove existing rule and then have it re-added
})
} else {
this.declarativeNetRequest.updateSessionRules({
removeRuleIds: [existingRule.id]
})
}
)
delete this.list[id]
this.save()
}
}
})
}

removeTab(tabId) {
delete this.tabs[tabId]
}

updateTab(tabId, url) {
this.logger('debug', `Tab ${tabId} has new url ${url}, check for updates.`).write()
this.tabs[tabId] = url
Object.keys(this.list).forEach(id => {
const { rule, includeRules, excludeRules } = this.list[id]
// console.log(rule, includeRules, excludeRules)
// check if new url matches the include/exclude rules
if (new MatchRule(includeRules, excludeRules).test(url)) {
// URL matches: the tab will be added to the rule
if (!rule.condition.tabIds.includes(tabId)) {
rule.condition.tabIds.push(tabId)
this.declarativeNetRequest.updateSessionRules({
addRules: [rule],
removeRuleIds: [rule.id]
})
this.declarativeNetRequest.getSessionRules(rules => {
const newRules = rules.reduce((result, current) => {
current.condition.tabIds = current.condition.tabIds.filter(id => id !== tabId)
if (current.condition.tabIds.length > 0) {
result.push(current)
}
} else {
// URL does not match: the tab will be removed from the rule
rule.condition.tabIds = rule.condition.tabIds.filter(id => id !== tabId)
this.declarativeNetRequest.updateSessionRules({
addRules: rule.condition.tabIds.length > 0 ? [rule] : [],
removeRuleIds: [rule.id]
})
}
return result
}, [])
this.declarativeNetRequest.updateSessionRules({
addRules: newRules,
removeRuleIds: rules.map(rule => rule.id)
})
})
this.save()
}

clear() {
this.logger('debug', 'Clear all web hooks').write()
this.list = {}
this.declarativeNetRequest.getSessionRules(rules => {
this.declarativeNetRequest.updateSessionRules({
removeRuleIds: rules.map(rule => rule.id)
})
})
this.save()
}
}

Expand Down
8 changes: 4 additions & 4 deletions src/models/UrlManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,22 @@ class UrlManager {
this.enabled = enabled
}

add (url) {
add (description) {
if (this.enabled) {
this.scope.chrome.runtime.sendMessage({
receiver: 'background',
task: 'addUrl',
url
description
})
}
}

remove (id) {
remove (description) {
if (this.enabled) {
this.scope.chrome.runtime.sendMessage({
receiver: 'background',
task: 'removeUrl',
id
description
})
}
}
Expand Down

0 comments on commit 037bc2e

Please sign in to comment.