Skip to content

Resolve relative references against the base URL in the URL constructor - #59839

Open
spokodev wants to merge 1 commit into
react:mainfrom
spokodev:fix-url-relative-base
Open

spokodev wants to merge 1 commit into
react:mainfrom
spokodev:fix-url-relative-base

Conversation

@spokodev

@spokodev spokodev commented Nov 6, 2026

Copy link
Copy Markdown

Summary:

new URL(url, base) appends url to base instead of resolving it, so many relative references give a different URL than Node's URL:

new URL('/api/users', 'https://example.com/v1/').href;
// main: https://example.com/v1/api/users
// Node: https://example.com/api/users

new URL('image.png', 'https://cdn.example.com/assets/index.json').href;
// main: https://cdn.example.com/assets/index.json/image.png
// Node: https://cdn.example.com/assets/image.png

new URL('?page=2', 'https://example.com/list?page=1').href;
// main: https://example.com/list?page=1/?page=2
// Node: https://example.com/list?page=2

new URL('//cdn.example.com/x.js', 'https://example.com/').href;
// main: //cdn.example.com/x.js
// Node: https://cdn.example.com/x.js

This change resolves the reference against the base as in RFC 3986 section 5.2: a path that starts with / replaces the base path, any other path replaces the last segment of the base path, . and .. segments are removed, and an empty path keeps the base path and query. A reference that starts with // is resolved too, instead of being returned as is. Calls without a base, and URLs that validateBaseUrl accepts other than ones starting with //, take the same branch as before.

The test in URL-itest.js that was commented out as requiring a complex implementation (/en-US/docs against https://developer.mozilla.org/fr-FR/toto) is enabled. #45055 worked on base URLs and relative paths before and was closed as stale.

This follows RFC 3986, not the full WHATWG URL parser, so some differences from Node's URL remain and are not changed here: validateBaseUrl still rejects a base with credentials (https://user:pw@host/) or a custom scheme (myapp://); references with an empty host such as // or ///x differ; http:g is treated as absolute, as in RFC 3986, where Node resolves it against an http base; and Node also treats percent-encoded dot segments (%2e%2e/hi) as .. and a backslash as /, and removes tabs and leading spaces, which this change does not.

Changelog:

[GENERAL] [FIXED] - Resolve relative references against the base URL in the URL constructor

Test Plan:

  • yarn fantom packages/react-native/Libraries/Blob/__tests__/URL-itest.js: 5 passed. With URL.js from main, 3 fail: the re-enabled MDN case and the two new tests.
  • The new tests cover the 41 normal and abnormal examples from RFC 3986 section 5.4, with base http://a.com/b/c/d;p?q because validateBaseUrl rejects the RFC's http://a/..., and expected values from Node's URL; and //cdn.example.com/x.js against https://example.com/.
  • Compared with Node's URL on 20,000 generated relative references (segments such as ., .., g and a;b, with queries, fragments and //host) against 10 base URLs: main differs in 16,910, this branch in 2,470, of which 1,651 have a base with credentials and 819 an empty host. In this generated sample, no reference that matched Node on main differs after the change.
  • yarn flow-check (Found 0 errors), yarn lint, and prettier --check on the two files pass.

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Nov 6, 2026
@facebook-github-tools facebook-github-tools Bot added the Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team. label Nov 6, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant