fix tracker: testing memory clearing on iframe src change

fix tracker: testing memory clearing on iframe src change
This commit is contained in:
nick-delirium 2024-09-02 15:14:03 +02:00
parent 9203951ec8
commit dfc18d6d0e
No known key found for this signature in database
GPG key ID: 93ABD695DF5FDBA0

View file

@ -1,4 +1,4 @@
import { createMutationObserver, ngSafeBrowserMethod } from '../../utils.js'
import { createMutationObserver } from '../../utils.js'
import {
RemoveNodeAttribute,
SetNodeAttributeURLBased,
@ -77,13 +77,11 @@ export default abstract class Observer {
// mutations order is sequential
const target = mutation.target
const type = mutation.type
if (!isObservable(target)) {
continue
}
if (type === 'childList') {
for (let i = 0; i < mutation.removedNodes.length; i++) {
// Should be the same as bindTree(mutation.removedNodes[i]), but logic needs to be be untied
if (isObservable(mutation.removedNodes[i])) {
this.bindNode(mutation.removedNodes[i])
}
@ -105,6 +103,9 @@ export default abstract class Observer {
if (name === null) {
continue
}
if (target instanceof HTMLIFrameElement && name === 'src') {
this.handleIframeSrcChange(target)
}
let attr = this.attributesMap.get(id)
if (attr === undefined) {
this.attributesMap.set(id, (attr = new Set()))
@ -114,13 +115,13 @@ export default abstract class Observer {
}
if (type === 'characterData') {
this.textSet.add(id)
continue
}
}
this.commitNodes()
}) as MutationCallback,
)
}
private clear(): void {
this.commited.length = 0
this.recents.clear()
@ -129,10 +130,49 @@ export default abstract class Observer {
this.textSet.clear()
}
/**
* Unbinds the removed nodes in case of iframe src change.
*/
private handleIframeSrcChange(iframe: HTMLIFrameElement): void {
const oldContentDocument = iframe.contentDocument
if (oldContentDocument) {
const id = this.app.nodes.getID(oldContentDocument)
if (id !== undefined) {
const walker = document.createTreeWalker(
oldContentDocument,
NodeFilter.SHOW_ELEMENT + NodeFilter.SHOW_TEXT,
{
acceptNode: (node) =>
isIgnored(node) || this.app.nodes.getID(node) === undefined
? NodeFilter.FILTER_REJECT
: NodeFilter.FILTER_ACCEPT,
},
// @ts-ignore
false,
)
let removed = 0
const totalBeforeRemove = this.app.nodes.getNodeCount()
while (walker.nextNode()) {
if (!iframe.contentDocument.contains(walker.currentNode)) {
removed += 1
this.app.nodes.unregisterNode(walker.currentNode)
}
}
const removedPercent = Math.floor((removed / totalBeforeRemove) * 100)
if (removedPercent > 30) {
this.app.send(UnbindNodes(removedPercent))
}
}
}
}
private sendNodeAttribute(id: number, node: Element, name: string, value: string | null): void {
if (isSVGElement(node)) {
if (name.substr(0, 6) === 'xlink:') {
name = name.substr(6)
if (name.substring(0, 6) === 'xlink:') {
name = name.substring(6)
}
if (value === null) {
this.app.send(RemoveNodeAttribute(id, name))
@ -152,7 +192,7 @@ export default abstract class Observer {
name === 'integrity' ||
name === 'crossorigin' ||
name === 'autocomplete' ||
name.substr(0, 2) === 'on'
name.substring(0, 2) === 'on'
) {
return
}
@ -357,6 +397,7 @@ export default abstract class Observer {
}
return true
}
private commitNode(id: number): boolean {
const node = this.app.nodes.getNode(id)
if (node === undefined) {
@ -368,6 +409,7 @@ export default abstract class Observer {
}
return (this.commited[id] = this._commitNode(id, node))
}
private commitNodes(isStart = false): void {
let node
this.recents.forEach((type, id) => {