Memra

URI, URL, and relative references

◈ 5 cards

Identification versus location; the scheme/authority/path/query/fragment decomposition; hierarchical versus opaque; and how a relative reference resolves against a base.

Identify, then locate

A URI (Uniform Resource Identifier) is a string that identifies a resource. That is its entire job: naming. urn:isbn:0-596-00187-6 identifies one particular book and gives you no way whatsoever to obtain it. A URL (Uniform Resource Locator) is a URI that additionally tells a client how to retrieve a representation of the resource — which protocol to speak, which host to speak it to, and which path to ask for. Every URL is a URI; not every URI is a URL.

A resource is whatever the identifier names, and you never actually receive one. What crosses the wire is a representation of it: bytes in some format, in some language, at some moment. One resource can have many representations, which is why the response headers of Module 4.5 matter as much as the body.

Java wires the identify/locate split straight into two classes. java.net.URI parses, compares and manipulates identifiers, and can never open a connection. java.net.URL can retrieve, because it is backed by a protocol handler for its scheme — which is also why new URL("urn:isbn:0-596-00187-6") throws: no handler, no URL.

The pieces

protocol://userInfo@host:port/path?query#fragment

Two vocabulary translations you will make constantly. The RFCs say scheme; Java's getter is getProtocol(). The RFCs say fragment identifier; Java calls it the ref and returns it from getRef(). The userInfo, host and port together form the authority — the part that answers who resolves this. Only the protocol and the host really carry weight: an absent port means the scheme's default, and the query and fragment are frequently absent altogether. The fragment is special in one more way — it is never sent to the server. It tells the client which part of the retrieved representation to show.

Hierarchical and opaque

Strip the scheme off and what remains is the scheme-specific part. When it begins with // the reference is hierarchical: it decomposes into authority, path and query, and the slash-separated path segments mean something. When it does not — mailto:sam@example.org, tel:+1-800-555-0100, urn:isbn:… — it is opaque, and the only pieces available are the scheme, the scheme-specific part and the fragment. URI.isOpaque() reports which kind you are holding. Relative resolution is meaningful only on hierarchical references, because only they have a path to walk.

Relative references

A relative reference omits the leading pieces and inherits them from the document it appears in. Four shapes cover nearly everything a page contains: a bare filename replaces the last segment of the base path; a segment plus a filename descends from it; a reference starting with / throws the base path away and starts at the document root, keeping the authority; and a reference that is only #fragment names the same document. Leading .. segments walk up before the remainder is appended, and the result is normalised.

Relative references are not typing economy. They are what lets a whole document tree move to another host, or be served over a second protocol, without a single internal link breaking.

Worked example — four links on one page

You are parsing http://data.example.org:8080/comp348/week3.html?topic=urls#refs. Resolution uses the base without its query and fragment, so the base path is /comp348/week3.html and its last segment is dropped before merging:

week4.html          ->  http://data.example.org:8080/comp348/week4.html
notes/lab.html      ->  http://data.example.org:8080/comp348/notes/lab.html
/about/             ->  http://data.example.org:8080/about/
../images/logo.png  ->  http://data.example.org:8080/images/logo.png
#refs               ->  http://data.example.org:8080/comp348/week3.html#refs

Notice what survives every row: the port. 8080 is part of the authority, so a relative link on a page served from port 8080 stays on port 8080 — and a root-relative link keeps it too. That is one of several rules you would have to re-derive, correctly, every time, if you resolved links with string concatenation.

piecein the exampleURL getterschemehttpgetProtocol()hostdata.example.orggetHost()port8080getPort()path/comp348/week3.htmlgetPath()querytopic=urlsgetQuery()fragmentrefsgetRef()Authority = userInfo + host + port.
The same reference seen three ways: the name of the piece, its text in this example, and the accessor that hands it back. Java renames two of them — the scheme is the protocol, the fragment identifier is the ref — so you translate every time you move between an RFC and the javadoc.
NORMAL ~/memra/learn/comp-348/uri-url-relative-references utf-8 LF