From c7fc3124dbfa546b0d6fee96917365ec60ed219d Mon Sep 17 00:00:00 2001 From: Alex Kaminskii Date: Mon, 19 Sep 2022 11:42:20 +0200 Subject: [PATCH] fix(tracker): svg- load in firefox - fix false error detection --- tracker/tracker/src/main/modules/img.ts | 54 ++++++++++++++----------- tracker/tracker/src/main/utils.ts | 4 ++ 2 files changed, 34 insertions(+), 24 deletions(-) diff --git a/tracker/tracker/src/main/modules/img.ts b/tracker/tracker/src/main/modules/img.ts index aa1701738..b2c699167 100644 --- a/tracker/tracker/src/main/modules/img.ts +++ b/tracker/tracker/src/main/modules/img.ts @@ -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'] }) }) } diff --git a/tracker/tracker/src/main/utils.ts b/tracker/tracker/src/main/utils.ts index 9856f407c..0bbe09e33 100644 --- a/tracker/tracker/src/main/utils.ts +++ b/tracker/tracker/src/main/utils.ts @@ -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