fix(tracker): svg-<img> load in firefox - fix false error detection

This commit is contained in:
Alex Kaminskii 2022-09-19 11:42:20 +02:00
parent 4f8e000de3
commit c7fc3124db
2 changed files with 34 additions and 24 deletions

View file

@ -1,5 +1,5 @@
import type App from '../app/index.js'
import { timestamp, isURL } from '../utils.js'
import { timestamp, isURL, IS_FIREFOX, MAX_STR_LEN } from '../utils.js'
import { ResourceTiming, SetNodeAttributeURLBased, SetNodeAttribute } from '../app/messages.gen.js'
import { hasTag } from '../app/guards.js'
@ -10,7 +10,7 @@ function resolveURL(url: string, location: Location = document.location) {
} else if (
url.startsWith('http://') ||
url.startsWith('https://') ||
url.startsWith('data:') // any other possible value here?
url.startsWith('data:') // any other possible value here? https://bugzilla.mozilla.org/show_bug.cgi?id=1758035
) {
return url
} else {
@ -18,6 +18,11 @@ function resolveURL(url: string, location: Location = document.location) {
}
}
// https://bugzilla.mozilla.org/show_bug.cgi?id=1607081
function isSVGInFireFox(url: string) {
return IS_FIREFOX && (url.startsWith('data:image/svg+xml') || url.match(/.svg$|/i))
}
const PLACEHOLDER_SRC = 'https://static.openreplay.com/tracker/placeholder.jpeg'
export default function (app: App): void {
@ -45,33 +50,34 @@ export default function (app: App): void {
}
const sendSrc = function (id: number, img: HTMLImageElement): void {
const src = img.src
app.send(SetNodeAttributeURLBased(id, 'src', src, app.getBaseHref()))
if (img.src.length > MAX_STR_LEN) {
sendPlaceholder(id, img)
}
app.send(SetNodeAttributeURLBased(id, 'src', img.src, app.getBaseHref()))
}
const sendImgAttrs = app.safe(function (this: HTMLImageElement): void {
const id = app.nodes.getID(this)
const sendImgError = app.safe(function (img: HTMLImageElement): void {
const resolvedSrc = resolveURL(img.src || '') // Src type is null sometimes. - is it true?
if (isURL(resolvedSrc)) {
app.send(ResourceTiming(timestamp(), 0, 0, 0, 0, 0, resolvedSrc, 'img'))
}
})
const sendImgAttrs = app.safe(function (img: HTMLImageElement): void {
const id = app.nodes.getID(img)
if (id === undefined) {
return
}
const { src, complete, naturalWidth, naturalHeight } = this
if (!complete) {
if (!img.complete) {
return
}
const resolvedSrc = resolveURL(src || '') // Src type is null sometimes. - is it true?
if (naturalWidth === 0 && naturalHeight === 0) {
if (isURL(resolvedSrc)) {
app.send(ResourceTiming(timestamp(), 0, 0, 0, 0, 0, resolvedSrc, 'img'))
}
} else if (
resolvedSrc.length >= 1e5 ||
app.sanitizer.isHidden(id) ||
app.sanitizer.isObscured(id)
) {
sendPlaceholder(id, this)
if (img.naturalHeight === 0 && img.naturalWidth === 0 && !isSVGInFireFox(img.src)) {
sendImgError(img)
} else if (app.sanitizer.isHidden(id) || app.sanitizer.isObscured(id)) {
sendPlaceholder(id, img)
} else {
sendSrc(id, this)
sendSrcset(id, this)
sendSrc(id, img)
sendSrcset(id, img)
}
})
@ -101,9 +107,9 @@ export default function (app: App): void {
if (!hasTag(node, 'IMG')) {
return
}
app.nodes.attachNodeListener(node, 'error', sendImgAttrs.bind(node))
app.nodes.attachNodeListener(node, 'load', sendImgAttrs.bind(node))
sendImgAttrs.call(node)
app.nodes.attachNodeListener(node, 'error', () => sendImgError(node))
app.nodes.attachNodeListener(node, 'load', () => sendImgAttrs(node))
sendImgAttrs(node)
observer.observe(node, { attributes: true, attributeFilter: ['src', 'srcset'] })
})
}

View file

@ -2,6 +2,10 @@ const DEPRECATED_ATTRS = { htmlmasked: 'hidden', masked: 'obscured' }
export const IN_BROWSER = !(typeof window === 'undefined')
export const IS_FIREFOX = IN_BROWSER && navigator.userAgent.match(/firefox|fxios/i)
export const MAX_STR_LEN = 1e5
const navigationStart: number | false =
(IN_BROWSER && performance.timing.navigationStart) || performance.timeOrigin
// performance.now() is buggy in some browsers