Duplicate XF.getLocalLoadTime may return incorrect values

Kirby

Well-known member
Licensed customer
Affected version
2.3.13
JavaScript:
getLocalLoadTime: () =>
{
    if (XF._localLoadTime)
    {
        return XF._localLoadTime
    }

    const loadCacheEl = document.querySelector('#_xfClientLoadTime')

    const loadCache = loadCacheEl.value.split(',')
    if (loadCache.length === 2 && parseInt(loadCache[1]) === XF.config.time.now)
    {
        XF._localLoadTime = parseInt(loadCache[0])

        return XF._localLoadTime
    }

    const navigationTiming = window.performance.getEntriesByType('navigation')[0]
    if (!navigationTiming)
    {
        XF._localLoadTime = Math.floor(new Date().getTime() / 1000) - 1
        loadCacheEl.value = XF._localLoadTime + ',' + XF.config.time.now

        return XF._localLoadTime
    }

    // avg between request and response is likely close to server start
    const loadTime = (navigationTiming.requestStart + navigationTiming.responseStart) / 2
    XF._localLoadTime = Math.floor((window.performance.timeOrigin + loadTime) / 1000)
    loadCacheEl.value = XF._localLoadTime + ',' + XF.config.time.now

    return XF._localLoadTime
}

This code blindly trusts the navigation entry timing data if it does exist.
Unfortunatley this data may be incomplete (or nonsense) leading to incorrect load time calculation.

The code also blindly takes the cached value from form field _xfClientLoadTime, if this is newer than current navigation smth. certainly isn't (or wasn't) correct.

Suggested Fix
JavaScript:
getLocalLoadTime: () =>
{
    if (XF._localLoadTime)
    {
        return XF._localLoadTime
    }

    const loadCacheEl = document.querySelector('#_xfClientLoadTime')

    const navigationTiming = window.performance.getEntriesByType('navigation')[0]
    const hasUsableNavigationTiming = navigationTiming
        && Number.isFinite(navigationTiming.requestStart)
        && Number.isFinite(navigationTiming.responseStart)
        && navigationTiming.requestStart > 0
        && navigationTiming.responseStart > 0
        && navigationTiming.responseStart >= navigationTiming.requestStart

    const navigationLoadTime = hasUsableNavigationTiming
        ? Math.floor((window.performance.timeOrigin + (navigationTiming.requestStart + navigationTiming.responseStart) / 2) / 1000)
        : null

    const loadCache = loadCacheEl.value.split(',')
    if (loadCache.length === 2 && parseInt(loadCache[1]) === XF.config.time.now)
    {
        const cachedLoadTime = parseInt(loadCache[0])

        if (Number.isFinite(cachedLoadTime)
            && (navigationLoadTime === null || cachedLoadTime <= navigationLoadTime + 2)
        )
        {
            XF._localLoadTime = cachedLoadTime

            return XF._localLoadTime
        }

        // a matching cache entry means this document was restored rather than freshly
        // parsed, so the navigation may be much later than the render it would have to be
        // paired with. assuming no clock skew at least keeps the pair consistent, which is
        // the smaller error once the client clock is known to be unreliable
        XF._localLoadTime = XF.config.time.now
        loadCacheEl.value = XF._localLoadTime + ',' + XF.config.time.now

        return XF._localLoadTime
    }

    if (navigationLoadTime === null)
    {
            XF._localLoadTime = Math.floor(Date.now() / 1000) - 1
            loadCacheEl.value = XF._localLoadTime + ',' + XF.config.time.now

            return XF._localLoadTime
    }

    XF._localLoadTime = navigationLoadTime
    loadCacheEl.value = XF._localLoadTime + ',' + XF.config.time.now

    return XF._localLoadTime
}
 
Thinking more about this issue:

The code uses window.performance.timeOrigin which relies on the document monothonic clock; this is not guaranteed to tick when the browser is in background / sleeping:


https://bugzilla.mozilla.org/show_bug.cgi?id=1710762 makes this even worse.
 
Automated triage: Duplicate

Thank you for reporting this issue. This is part of the same problem as "XF.DynamicDate may show wrong output": the client's estimate of the server's time comes from the load time this function returns, and nothing checks or corrects it afterwards. We'll track this in that thread and take your suggestions here into account.

Duplicate of: https://xenforo.com/community/threads/240186/

This is an automated assessment. A member of staff may review and update it.
 
Back
Top Bottom