Rill v0.13 Reference

Standard library · The web

web/url

Imported as import "web/url" as url, its names are then url.…. Every signature below is the one the checker infers.

URLs taken apart and put together (RFC 3986): the scheme, who, the host, the port, the path, the query, the fragment; a query as pairs; a relative reference resolved against a base; percent-encoding both ways.

A Url is a record; text writes it back, and a part that was not there is empty (port is -1). Nothing is decoded on the way in — the path and query are as they were written — so decode what you look at.

u = url.parse("https://user@example.com:8443/a/b?x=1&y=two#top") |> unwrap_or(url.Url("", "", "", -1, "", "", ""))
u.host                                                  # => example.com
u.port                                                  # => 8443
u.path                                                  # => /a/b
url.query_pairs("x=1&y=two%20words")                   # => Cons((x, 1), Cons((y, two words), Nil))
url.resolve("https://example.com/a/b/c", "../d?q")      # => https://example.com/a/d?q
url.encode("a b&c")                                     # => a%20b%26c

Types

Url

  • Url(scheme: Str, user: Str, host: Str, port: Int, path: Str, query: Str, fragment: Str)

Functions

fn parse(s: Str) -> Option(Url)

A URL with a scheme and //, or None. A path-only reference is not a URL; resolve it against one.

url.parse("http://h/p?q#f")   # => Some(url.Url(http, , h, -1, /p, q, f))
url.parse("/just/a/path")     # => None

fn text(u: Url) -> Str

url.text(url.Url("https", "me", "h.io", 8080, "/x", "a=1", "top"))   # => https://me@h.io:8080/x?a=1#top

fn port_of(u: Url) -> Int

The port, or the scheme's usual one: 80, 443, 21, 22, 25.

url.port_of(url.parse("https://h/") |> unwrap_or(url.Url("", "", "", -1, "", "", "")))        # => 443
url.port_of(url.parse("http://h:81/") |> unwrap_or(url.Url("", "", "", -1, "", "", "")))     # => 81

fn origin(u: Url) -> Str

The scheme, host and port alone: https://example.com:8443.

url.origin(url.parse("https://example.com:8443/a?b") |> unwrap_or(url.Url("", "", "", -1, "", "", "")))   # => https://example.com:8443

fn query_pairs(query: Str) -> List((Str, Str))

a=1&b=two%20words as decoded pairs; a key without = has the value "".

url.query_pairs("a=1&b=two%20words&flag")   # => Cons((a, 1), Cons((b, two words), Cons((flag, ), Nil)))

fn query_text(pairs: List((Str, Str))) -> Str

The pairs as a query, each side encoded.

url.query_text(Cons(("q", "a b"), Cons(("n", "1"), Nil)))   # => q=a%20b&n=1

fn query_get(query: Str, name: Str) -> Option(Str)

The first value under name, decoded.

url.query_get("a=1&b=2&a=3", "a")   # => Some(1)
url.query_get("a=1", "z")         # => None

fn encode(s: Str) -> Str

Percent-encoding of everything but the unreserved characters — letters, digits, - . _ ~ — so the result is safe anywhere in a URL.

url.encode("a b/c~d")   # => a%20b%2Fc~d

fn decode(s: Str) -> Str

%xx back to bytes and + to a space, as a form sends them; a % not followed by two hex digits is kept as it is.

url.decode("a%20b+c")   # => a b c
url.decode("100%")      # => 100%

fn resolve(base: Str, reference: Str) -> Str

reference seen from base, as a browser follows a link: absolute references stand; //host/x keeps the scheme; /x keeps the host; x, ./x and ../x are joined to the base's path with the dots resolved; ?q and #f alone replace only that part.

url.resolve("https://example.com/a/b/c", "../d")          # => https://example.com/a/d
url.resolve("https://example.com/a/b/c", "/x")            # => https://example.com/x
url.resolve("https://example.com/a/b/c", "//other/y")     # => https://other/y
url.resolve("https://example.com/a/b/c", "?q=1")          # => https://example.com/a/b/c?q=1
url.resolve("https://example.com/a", "http://else/")      # => http://else/

Tests

  • test_parse_the_parts
  • test_what_is_not_a_url
  • test_query_and_encoding
  • test_resolve_like_a_browser