std/uri

Source   Edit  

This module implements URI parsing as specified by RFC 3986.

A Uniform Resource Identifier (URI) provides a simple and extensible means for identifying a resource. A URI can be further classified as a locator, a name, or both. The term "Uniform Resource Locator" (URL) refers to the subset of URIs.

Warning: URI parsers in this module do not perform security validation.

Basic usage

Combine URIs

Example:

import std/uri
let host = parseUri("https://nim-lang.org")
assert $host == "https://nim-lang.org"
assert $(host / "/blog.html") == "https://nim-lang.org/blog.html"
assert $(host / "blog2.html") == "https://nim-lang.org/blog2.html"

Access URI item

Example:

import std/uri
let res = parseUri("sftp://127.0.0.1:4343")
assert isAbsolute(res)
assert res.port == "4343"

Data URI Base64

Example:

import std/uri
assert getDataUri("Hello World", "text/plain") == "data:text/plain;charset=utf-8;base64,SGVsbG8gV29ybGQ="
assert getDataUri("Nim", "text/plain") == "data:text/plain;charset=utf-8;base64,Tmlt"

Types

Uri = object
  scheme*, username*, password*: string
  hostname*, port*, path*, query*, anchor*: string
  opaque*: bool
  isIpv6*: bool
Source   Edit  
UriParseError = object of ValueError
Source   Edit  
Url = distinct string
Source   Edit  

Procs

func `$`(u: Uri): string {....raises: [], tags: [], forbids: [].}
Returns the string representation of the specified URI object.

Example:

assert $parseUri("https://nim-lang.org") == "https://nim-lang.org"
Source   Edit  
func `/`(x: Uri; path: string): Uri {....raises: [], tags: [], forbids: [].}

Concatenates the path specified to the specified URIs path.

Contrary to the combine func you do not have to worry about the slashes at the beginning and end of the path and URIs path respectively.

See also:

Example:

let foo = parseUri("https://nim-lang.org/foo/bar") / "/baz"
assert foo.path == "/foo/bar/baz"
let bar = parseUri("https://nim-lang.org/foo/bar") / "baz"
assert bar.path == "/foo/bar/baz"
let qux = parseUri("https://nim-lang.org/foo/bar/") / "baz"
assert qux.path == "/foo/bar/baz"
Source   Edit  
func `?`(u: Uri; query: openArray[(string, string)]): Uri {....raises: [],
    tags: [], forbids: [].}
Concatenates the query parameters to the specified URI object.

Example:

let foo = parseUri("https://example.com") / "foo" ? {"bar": "qux"}
assert $foo == "https://example.com/foo?bar=qux"
Source   Edit  
func combine(base: Uri; reference: Uri): Uri {....raises: [], tags: [], forbids: [].}

Combines a base URI with a reference URI.

This uses the algorithm specified in section 5.2.2 of RFC 3986.

This means that the slashes inside the base URIs path as well as reference URIs path affect the resulting URI.

See also:

Example:

let foo = combine(parseUri("https://nim-lang.org/foo/bar"), parseUri("/baz"))
assert foo.path == "/baz"
let bar = combine(parseUri("https://nim-lang.org/foo/bar"), parseUri("baz"))
assert bar.path == "/foo/baz"
let qux = combine(parseUri("https://nim-lang.org/foo/bar/"), parseUri("baz"))
assert qux.path == "/foo/bar/baz"
Source   Edit  
func combine(uris: varargs[Uri]): Uri {....raises: [], tags: [], forbids: [].}

Combines multiple URIs together.

See also:

Example:

let foo = combine(parseUri("https://nim-lang.org/"), parseUri("docs/"),
    parseUri("manual.html"))
assert foo.hostname == "nim-lang.org"
assert foo.path == "/docs/manual.html"
Source   Edit  
func decodeUrl(s: string; decodePlus = true): string {....raises: [], tags: [],
    forbids: [].}

Decodes a URL according to RFC3986.

This means that any %xx (where xx denotes a hexadecimal value) are converted to the character with ordinal number xx, and every other character is carried over. If xx is not a valid hexadecimal value, it is left intact.

As a special rule, when the value of decodePlus is true, + characters are converted to a space.

See also:

Example:

assert decodeUrl("https%3A%2F%2Fnim-lang.org") == "https://nim-lang.org"
assert decodeUrl("https%3A%2F%2Fnim-lang.org%2Fthis+is+a+test") == "https://nim-lang.org/this is a test"
assert decodeUrl("https%3A%2F%2Fnim-lang.org%2Fthis%20is%20a%20test",
    false) == "https://nim-lang.org/this is a test"
assert decodeUrl("abc%xyz") == "abc%xyz"
Source   Edit  
func encodeQuery(query: openArray[(string, string)]; usePlus = true;
                 omitEq = true; sep = '&'): string {....raises: [], tags: [],
    forbids: [].}

Encodes a set of (key, value) parameters into a URL query string.

Every (key, value) pair is URL-encoded and written as key=value. If the value is an empty string then the = is omitted, unless omitEq is false. The pairs are joined together by the sep character.

The usePlus parameter is passed down to the encodeUrl function that is used for the URL encoding of the string values.

See also:

Example:

assert encodeQuery({: }) == ""
assert encodeQuery({"a": "1", "b": "2"}) == "a=1&b=2"
assert encodeQuery({"a": "1", "b": ""}) == "a=1&b"
assert encodeQuery({"a": "1", "b": ""}, omitEq = false, sep = ';') == "a=1;b="
Source   Edit  
func encodeUrl(s: string; usePlus = true): string {....raises: [], tags: [],
    forbids: [].}

Encodes a URL according to RFC3986.

This means that characters in the set {'a'..'z', 'A'..'Z', '0'..'9', '-', '.', '_', '~'} are carried over to the result. All other characters are encoded as %xx where xx denotes its hexadecimal value.

As a special rule, when the value of usePlus is true, spaces are encoded as + instead of %20.

See also:

Example:

assert encodeUrl("https://nim-lang.org") == "https%3A%2F%2Fnim-lang.org"
assert encodeUrl("https://nim-lang.org/this is a test") == "https%3A%2F%2Fnim-lang.org%2Fthis+is+a+test"
assert encodeUrl("https://nim-lang.org/this is a test", false) == "https%3A%2F%2Fnim-lang.org%2Fthis%20is%20a%20test"
Source   Edit  
proc getDataUri(data, mime: string; encoding = "utf-8"): string {....raises: [],
    tags: [], forbids: [].}

Convenience proc for base64.encode returns a standard Base64 Data URI (RFC-2397)

See also:

Example:

static: assert getDataUri("Nim", "text/plain") == "data:text/plain;charset=utf-8;base64,Tmlt"
Source   Edit  
func initUri(isIpv6 = false): Uri {....raises: [], tags: [], forbids: [].}

Initializes a URI with scheme, username, password, hostname, port, path, query, anchor and isIpv6.

See also:

  • Uri type for available fields in the URI type

Example:

var uri2 = initUri(isIpv6 = true)
uri2.scheme = "tcp"
uri2.hostname = "2001:0db8:85a3:0000:0000:8a2e:0370:7334"
uri2.port = "8080"
assert $uri2 == "tcp://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:8080"
Source   Edit  
func isAbsolute(uri: Uri): bool {....raises: [], tags: [], forbids: [].}
Returns true if URI is absolute, false otherwise.

Example:

assert parseUri("https://nim-lang.org").isAbsolute
assert not parseUri("nim-lang").isAbsolute
Source   Edit  
func parseUri(uri: string): Uri {....raises: [], tags: [], forbids: [].}

Parses a URI and returns it.

See also:

  • Uri type for available fields in the URI type

Example:

let res = parseUri("ftp://Username:Password@Hostname")
assert res.username == "Username"
assert res.password == "Password"
assert res.scheme == "ftp"
Source   Edit  
func parseUri(uri: string; result: var Uri) {....raises: [], tags: [], forbids: [].}

Parses a URI. The result variable will be cleared before.

See also:

Example:

var res = initUri()
parseUri("https://nim-lang.org/docs/manual.html", res)
assert res.scheme == "https"
assert res.hostname == "nim-lang.org"
assert res.path == "/docs/manual.html"
Source   Edit  
proc uriParseError(msg: string) {.noreturn, ...raises: [UriParseError], tags: [],
                                  forbids: [].}
Raises a UriParseError exception with message msg. Source   Edit  

Iterators

iterator decodeQuery(data: string; sep = '&'): tuple[key, value: string] {.
    ...raises: [], tags: [], forbids: [].}
Reads and decodes the query string data and yields the (key, value) pairs the data consists of. If compiled with -d:nimLegacyParseQueryStrict, a UriParseError is raised when there is an unencoded = character in a decoded value, which was the behavior in Nim < 1.5.1.

Example:

import std/sequtils
assert toSeq(decodeQuery("foo=1&bar=2=3")) == @[("foo", "1"), ("bar", "2=3")]
assert toSeq(decodeQuery("foo=1;bar=2=3", ';')) == @[("foo", "1"), ("bar", "2=3")]
assert toSeq(decodeQuery("&a&=b&=&&")) == @[("", ""), ("a", ""), ("", "b"), ("", ""), ("", "")]
Source   Edit