Skip to content
AZ Tools

Relative URL Resolver (RFC 3986)

Resolve a relative reference against a base URI by RFC 3986, with the dot-segment trace and the browser’s answer beside it.

References worth trying, against the base above

Target URI

http://a/b/c/y

The browser's own resolver (WHATWG URL)

http://a/b/c/y

Agrees with the RFC 3986 result.

Which branch of section 5.2.2 ran

R.path is relative — merged with the base path

Target components (section 5.3)

schemehttp
authoritya
path/b/c/y
query—
fragment—

remove_dot_segments, step by step (section 5.2.4)

RuleInput bufferOutput buffer
—/b/c/g;x=1/../y""
E/c/g;x=1/../y/b
E/g;x=1/../y/b/c
E/../y/b/c/g;x=1
C/y/b/c
E""/b/c/y
—""/b/c/y

Rules A–E are the specification’s own labels; the last row is the returned output buffer.

RFC 3986 section 5.2, implemented step for step. The browser is shown beside it because a library that follows WHATWG will not always agree.

How to use

  1. Enter a base URI and a relative reference. The target appears with the browser’s result beside it.
  2. Press one of the example references to load a case from the specification’s own suite.
  3. Read the dot-segment trace when an answer surprises you — it shows which rule fired at each step.
  4. Turn strict mode off to see what a parser that allows the same-scheme loophole would produce instead.

About this tool

Show

Give it a base URI and a relative reference and it produces the target URI the way RFC 3986 section 5.2 says to, then shows the browser's own answer next to it and says whether the two agree. Most of the time they do; where they do not, the difference is real and documented, and knowing which one your library follows is the difference between a working link and a 404. The specification's own test suite has forty-two cases and two of them disagree with the WHATWG URL parser every browser and Node ship: a reference of //g resolves to http://g by the RFC and to http://g/ in a browser, because WHATWG normalises an empty path to a slash; and http:g against an http base resolves to http:g strictly, while the browser applies the backward-compatibility loophole and gives http://a/b/c/g. The strict toggle here is exactly that loophole, so you can see both. The part worth watching is the dot-segment trace. Section 5.2.4 removes . and .. with a two-buffer loop, and the rules only treat them as dot-segments when they are complete path segments — so g. and ..g are ordinary names that survive, while g;x=1/../y resolves to y and takes the matrix parameter with it. The trace prints the input and output buffer after every step, labelled with the specification's own rules A to E, which makes the surprising answers checkable rather than something to take on trust. Query and fragment are separated from the path before any of this runs, which is why g?y/../x keeps its /../ intact.

Frequently asked questions

Why does the browser disagree with the RFC on //g?

RFC 3986 resolves it to http://g, with an empty path. The WHATWG URL Standard, which is what browsers and Node implement, normalises an empty path on a special scheme to /, so you get http://g/. Both are deliberate. It matters when you compare URLs as strings or use one as a cache key, because the two forms are not equal even though they address the same resource.

What is the strict option for?

Section 5.2.2 offers a non-strict variant for backward compatibility with older partial-URI rules: if the reference has a scheme identical to the base’s, ignore it and treat the reference as relative. That turns http:g into http://a/b/c/g instead of leaving it as http:g. The RFC allows it and advises against relying on it; browsers do it. The toggle lets you see which behaviour your case depends on.

Why did g;x=1/../y lose the ;x=1?

Because .. removes the whole preceding segment, and g;x=1 is one segment — the semicolon has no special meaning in the generic syntax. So the path becomes /b/c/y. Matrix parameters written that way are fragile for exactly this reason; a dot-segment anywhere after them takes them with it.

Why is g?y/../x not affected by the dot-segments in it?

Because the reference is split into path, query and fragment before dot-segments are removed, and /../ there is inside the query. Section 5.4.2 calls this out specifically, noting that some parsers get it wrong by merging the whole reference first — a bug that rarely shows up because queries seldom contain slashes.

Does this normalise the result?

No, beyond what resolution itself requires. Case of the scheme and host, percent-encoding, the default port and an empty path are all left as section 5.2 leaves them, because normalisation is section 6 and a separate decision. If you need URLs that compare equal, normalise them deliberately rather than relying on a resolver to do it.

Related tools