Skip to content

🐛 Relative XHR/fetch resource events lose trace_id with a <base href> #4944

Description

@odonckers

Describe the bug

Product: rum.

Same-origin XHR/fetch resource events are missing _dd.trace_id, _dd.span_id, method and status_code whenever the app uses a <base href> that differs from the current path and issues document-relative request URLs (e.g. api/foo instead of /api/foo). The backend span is created fine and the request carries traceparent, but the RUM resource never links to it, so @type:resource @_dd.trace_id:* comes back empty and RUM ↔ APM correlation is broken.

The cause is in normalizeUrl (packages/js-core/src/util/urlPolyfill.ts), which records the request URL for XHR/fetch resources:

export function normalizeUrl(url: string) {
  return buildUrl(url, globalObject.location?.href).href
}

It resolves relative URLs against location.href, but the browser resolves relative request URLs against the document base URI (<base href>). So the URL recorded for the resource doesn't match the PerformanceResourceTiming.name the browser actually requested, and getMatchingRequest never pairs them. traceparent is still injected because allowedTracingUrls matches on origin, which the mis-resolved URL keeps — which is why it looks like propagation works until you check the RUM side.

With <base href="/"> on route /deep/route, a request to api/foo:

URL
Actual request / PerformanceResourceTiming.name https://host/api/foo
Recorded by normalizeUrl (base https://host/deep/route) https://host/deep/api/foo

To Reproduce

  1. Serve a SPA at / with <base href="/"> and init RUM with allowedTracingUrls: [window.location.origin] and trackResources: true.
  2. Navigate to a route deeper than the base, e.g. /deep/route.
  3. Issue a document-relative request: new XMLHttpRequest().open('GET', 'api/foo') or fetch('api/foo').
  4. Check the resulting resource event.

The request carries traceparent, but the resource event has no _dd.trace_id, _dd.span_id, method or status_code. Switching the app to a root-relative URL (/api/foo) makes all four appear, since root-relative URLs are base-independent.

Seen on @datadog/browser-rum 7.7.0 in Chrome. In production this was 0 of ~13,600 same-origin XHR resource events carrying a trace id over 24h; cross-origin (absolute URL) requests were fine.

Expected behavior

The resource event for a document-relative request should match its PerformanceResourceTiming entry and carry method, status_code, _dd.trace_id and _dd.span_id, the same as it does for root-relative requests.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions