Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions packages/browser-core/src/tools/utils/urlPolyfill.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,36 @@ describe('normalize url', () => {
// let's check for both.
expect(['file:///my/path', 'file://foo.com/my/path']).toContain(normalizeUrl('file://foo.com/my/path'))
})

describe('with a <base href> differing from the current path', () => {
// The browser resolves document-relative request URLs against the document base URI, not the
// page location. normalizeUrl must match that so the recorded URL pairs with its
// PerformanceResourceTiming entry.
let base: HTMLBaseElement

beforeEach(() => {
history.pushState({}, '', '/deep/route')
base = document.createElement('base')
base.href = '/'
document.head.appendChild(base)
})

afterEach(() => {
base.remove()
})

it('should resolve document-relative paths against the base URI', () => {
expect(normalizeUrl('api/foo')).toEqual(`${location.origin}/api/foo`)
})

it('should still resolve root-relative paths against the origin', () => {
expect(normalizeUrl('/api/foo')).toEqual(`${location.origin}/api/foo`)
})

it('should keep absolute urls unchanged', () => {
expect(normalizeUrl('https://foo.com/my/path')).toEqual('https://foo.com/my/path')
})
})
})

describe('isValidUrl', () => {
Expand Down
12 changes: 10 additions & 2 deletions packages/js-core/src/util/urlPolyfill.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
import type { GlobalObject } from './globalObject'
import { globalObject } from './globalObject'

/** Resolves a URL against the current page location, returning a normalized absolute URL string. */
/**
* Resolves a URL, returning a normalized absolute URL string.
*
* Document-relative inputs are resolved against `document.baseURI` (the `<base href>`, defaulting to
* the document location) to match how the browser resolves relative request URLs β€” so the URL
* recorded for a fetch/XHR matches the one actually requested. Falls back to `location.href` in
* environments without a document (workers, SSR). Absolute and root-relative inputs ignore the base
* and are unaffected.
*/
export function normalizeUrl(url: string) {
return buildUrl(url, globalObject.location?.href).href
return buildUrl(url, globalObject.document?.baseURI ?? globalObject.location?.href).href
}

/** Returns true if the given string is a valid URL. */
Expand Down
Loading