std/url

URLs: their parts, writing them back, resolving one relative to another, normalizing them, international domain names, and file:// URLs of paths. It passes on std/encoding, so url_encode and the form functions come with it.

import "std/url"

Url u = parse_url("HTTPS://Example.com:443/a/./b/../c?q=1#top")?
print(u.scheme, u.host, u.port, u.path, u.query)   // https example.com -1 /a/c q=1
print(url_text(u))                                 // https://example.com/a/c?q=1#top
print(resolve_url("http://a/b/c/d;p?q", "../g")?)  // http://a/b/g
print(domain_to_ascii("bücher.de")?)               // xn--bcher-kva.de
Function Result
parse_url(text) a Result[Url], an ERROR of kind "invalid_url" saying what is wrong
url_text(u) the text of a Url
url_query(u) the FormField items of its query
resolve_url(base, reference) reference resolved against base, as a link in a page there (RFC 3986, 5.2)
normalize_url(text) the URL read and written again, with %XX of letters, digits, and - . _ ~ as the characters and the others in uppercase
default_port(scheme) 80 for http, 443 for https, and so on, or -1
domain_to_ascii(domain), domain_to_unicode(domain) a domain with its labels in punycode after xn--, and back
punycode_encode(text), punycode_decode(text) punycode (RFC 3492): "bücher" is "bcher-kva"
file_url(path) the file:// URL of a path, made absolute from the current folder
file_url_path(url) the path of a file:// URL

A Url has a scheme, username, password, host, port, path, query, and fragment. port is -1 when the URL gives none or gives the default port of its scheme; has_host tells file:///x, whose host is empty, from mailto:x, which has none, and has_query and has_fragment tell an empty query or fragment from none.

Reading follows RFC 3986 and, where they differ in practice, the URL standard that browsers follow: the schemes http, https, ws, wss, ftp, and file take \ as /, always have a path, and leave out their default port, and the others need a host; schemes and hosts are made lowercase, a host outside ASCII is written in punycode, dot segments are resolved, and characters a part cannot hold, such as spaces and those outside ASCII, are percent-encoded. Spaces around the URL and tabs and line breaks inside it are left out. A reference with the scheme of a special base and no host, as http:g, is relative to it, as browsers take it.

file_url and file_url_path take system: "windows" or system: "posix" for the paths of another system: on Windows, C:\Users\ana is file:///C:/Users/ana and \server\share\x is file://server/share/x; elsewhere a URL with a host other than localhost names no local file and is an ERROR.