class

URI

Inherits Reference / Object

This class represents a URI reference as defined by RFC 3986: Uniform Resource Identifier (URI): Generic Syntax.

This class provides constructors for creating URI instances from their components or by parsing their string forms and methods for accessing the various components of an instance.

NOTE: To use URI, you must explicitly import it with require "uri"

Basic example:

require "uri"

uri = URI.parse "http://foo.com/posts?id=30&limit=5#time=1305298413"
# => #<URI:0x1003f1e40 @scheme="http", @host="foo.com", @port=nil, @path="/posts", @query="id=30&limit=5", ... >
uri.scheme # => "http"
uri.host   # => "foo.com"
uri.query  # => "id=30&limit=5"
uri.to_s   # => "http://foo.com/posts?id=30&limit=5#time=1305298413"

Resolution and Relativization

Resolution is the process of resolving one URI against another, base URI. The resulting URI is constructed from components of both URIs in the manner specified by RFC 3986 section 5.2, taking components from the base URI for those not specified in the original. For hierarchical URIs, the path of the original is resolved against the path of the base and then normalized. See #resolve for examples.

Relativization is the inverse of resolution as that it procures an URI that resolves to the original when resolved against the base.

For normalized URIs, the following is true:

a.relativize(a.resolve(b)) # => b
a.resolve(a.relativize(b)) # => b

This operation is often useful when constructing a document containing URIs that must be made relative to the base URI of the document wherever possible.

URL Encoding

This class provides a number of methods for encoding and decoding strings using URL Encoding (also known as Percent Encoding) as defined in RFC 3986 as well as x-www-form-urlencoded.

Each method has two variants, one returns a string, the other writes directly to an IO.

  • .decode(string : String, *, plus_to_space : Bool = false) : String: Decodes a URL-encoded string.
  • .decode(string : String, io : IO, *, plus_to_space : Bool = false) : Nil: Decodes a URL-encoded string to an IO.
  • .encode_path(string : String) : String: URL-encodes a string.
  • .encode_path(string : String, io : IO) : Nil: URL-encodes a string to an IO.
  • .encode_path_segment(string : String) : String: URL-encodes a string, escaping /.
  • .encode_path_segment(string : String, io : IO) : Nil: URL-encodes a string to an IO, escaping /.
  • .decode_www_form(string : String, *, plus_to_space : Bool = true) : String: Decodes an x-www-form-urlencoded string component.
  • .decode_www_form(string : String, io : IO, *, plus_to_space : Bool = true) : Nil: Decodes an x-www-form-urlencoded string component to an IO.
  • .encode_www_form(string : String, *, space_to_plus : Bool = true) : String: Encodes a string as a x-www-form-urlencoded component.
  • .encode_www_form(string : String, io : IO, *, space_to_plus : Bool = true) : Nil: Encodes a string as a x-www-form-urlencoded component to an IO.

.encode_www_form encodes white space ( ) as +, while .encode_path and .encode_path_segment encode it as %20. The decode methods differ regarding the handling of + characters, respectively.

NOTE: URI::Params provides a higher-level API for handling x-www-form-urlencoded serialized data.

Constructors

Deserializes a URI from YAML, represented as a string.

require "uri/yaml"

uri = URI.from_yaml(%("http://crystal-lang.org")) # => #<URI:0x1068a7e40 @scheme="http", @host="crystal-lang.org", ... >
uri.scheme                                        # => "http"
uri.host                                          # => "crystal-lang.org"
Source
new(parser : JSON::PullParser)

Deserializes a URI from JSON, represented as a string.

require "uri/json"

uri = URI.from_json(%("http://crystal-lang.org")) # => #<URI:0x1068a7e40 @scheme="http", @host="crystal-lang.org", ... >
uri.scheme                                        # => "http"
uri.host                                          # => "crystal-lang.org"
Source
new(scheme : Nil | String = nil, host = nil, port : Int32 | Nil = nil, path : String = "", query : String | Params | Nil = nil, user : Nil | String = nil, password : Nil | String = nil, fragment : Nil | String = nil)
Source
parse(raw_url : String) : URI

Parses the given raw_url into an URI. The raw_url may be relative or absolute.

require "uri"

uri = URI.parse("http://crystal-lang.org") # => #<URI:0x1068a7e40 @scheme="http", @host="crystal-lang.org", ... >
uri.scheme                                 # => "http"
uri.host                                   # => "crystal-lang.org"
Source

Class methods

decode(string : String, io : IO, *, plus_to_space : Bool = false) : Nil

URL-decodes a string and writes the result to io.

See .decode(string : String, *, plus_to_space : Bool = false) : String for details.

Source
decode(string : String, *, plus_to_space : Bool = false) : String

URL-decodes string.

require "uri"

URI.decode("hello%20world!")                                 # => "hello world!"
URI.decode("put:%20it+%D0%B9")                               # => "put: it+й"
URI.decode("http://example.com/Crystal%20is%20awesome%20=)") # => "http://example.com/Crystal is awesome =)"

By default, + is decoded literally. If plus_to_space is true, + is decoded as space character (0x20). Percent-encoded values such as %20 and %2B are always decoded as characters with the respective codepoint.

require "uri"

URI.decode("peter+%2B+paul")                      # => "peter+++paul"
URI.decode("peter+%2B+paul", plus_to_space: true) # => "peter + paul"
  • .encode is the reverse operation.
  • .decode_www_form encodes plus to space by default.
Source
decode(string : String, io : IO, *, plus_to_space : Bool = false, &) : Nil

URL-decodes string and writes the result to io.

The block is called for each percent-encoded ASCII character and determines whether the value is to be decoded. When the return value is falsey, the character is decoded. Non-ASCII characters are always decoded.

By default, + is decoded literally. If plus_to_space is true, + is decoded as space character (0x20).

This method enables some customization, but typical use cases can be implemented by either .decode(string : String, *, plus_to_space : Bool = false) : String or .decode_www_form(string : String, *, plus_to_space : Bool = true) : String.

Source
decode_www_form(string : String, io : IO, *, plus_to_space : Bool = true) : Nil

URL-decodes string as x-www-form-urlencoded and writes the result to io.

See self.decode_www_form(string : String, *, plus_to_space : Bool = true) : String for details.

Source
decode_www_form(string : String, *, plus_to_space : Bool = true) : String

URL-decodes string as x-www-form-urlencoded.

require "uri"

URI.decode_www_form("hello%20world!")                           # => "hello world!"
URI.decode_www_form("put:%20it+%D0%B9")                         # => "put: it й"
URI.decode_www_form("http://example.com/Crystal+is+awesome+=)") # => "http://example.com/Crystal is awesome =)"

By default, + is decoded as space character (0x20). If plus_to_space is false, + is decoded literally as +. Percent-encoded values such as %20 and %2B are always decoded as characters with the respective codepoint.

require "uri"

URI.decode_www_form("peter+%2B+paul")                       # => "peter + paul"
URI.decode_www_form("peter+%2B+paul", plus_to_space: false) # => "peter+++paul"
  • .encode_www_form is the reverse operation.
  • .decode encodes plus literally by default.
Source
default_port(scheme : String) : Int32 | Nil

Returns the default port for the given scheme if known, otherwise returns nil.

require "uri"

URI.default_port "http"  # => 80
URI.default_port "ponzi" # => nil
Source
encode(string : String, io : IO, *, space_to_plus : Bool = false) : Nil

URL-encodes string and writes the result to io.

See .encode(string : String, *, space_to_plus : Bool = false) : String for details.

Source
encode(string : String, *, space_to_plus : Bool = false) : String

URL-encodes string.

Reserved and unreserved characters are not escaped, so this only modifies some special characters as well as non-ASCII characters. .reserved? and .unreserved? provide more details on these character classes.

require "uri"

URI.encode("hello world!")                             # => "hello%20world!"
URI.encode("put: it+й")                                # => "put:%20it+%D0%B9"
URI.encode("http://example.com/Crystal is awesome =)") # => "http://example.com/Crystal%20is%20awesome%20=)"

By default, the space character (0x20) is encoded as %20 and + is encoded literally. If space_to_plus is true, space character is encoded as + and + is encoded as %2B:

require "uri"

URI.encode("peter + paul")                      # => "peter%20+%20paul"
URI.encode("peter + paul", space_to_plus: true) # => "peter+%2B+paul"
  • .decode is the reverse operation.
  • .encode_www_form also escapes reserved characters.
Source
encode(string : String, io : IO, space_to_plus : Bool = false, &) : Nil

URL-encodes string and writes the result to an IO.

The block is called for each ascii character (codepoint less than 0x80) and determines whether the value is to be encoded. When the return value is falsey, the character is encoded. Non-ASCII characters are always encoded.

By default, the space character (0x20) is encoded as %20 and + is encoded literally. If space_to_plus is true, space character is encoded as + and + is encoded as %2B.

This method enables some customization, but typical use cases can be implemented by either .encode_path(string : String) : String, .encode_path_segment(string : String) : String or .encode_www_form(string : String, *, space_to_plus : Bool = true) : String.

Source
encode_path(io : IO, string : String) : Nil

Encodes string so it can be safely placed as a potentially multi-segmented URI path, replacing special characters with URI escape sequences as needed.

Unreserved characters such as ASCII letters, digits, and the characters _.-~ are not encoded, as well as the character / which represent a segment separator in hierarchical paths (RFC 3986 §3.3).

require "uri"

URI.encode_path("foo/bar/baz")  # => "foo/bar/baz"
URI.encode_path("hello world!") # => "hello%20world%21"
URI.encode_path("put: it+й")    # => "put%3A%20it%2B%D0%B9"
  • .decode is the reverse operation.
  • .encode_path_segment encodes a single path segment, escaping /.
Source
encode_path(string : String) : String

Encodes string so it can be safely placed as a potentially multi-segmented URI path, replacing special characters with URI escape sequences as needed.

Unreserved characters such as ASCII letters, digits, and the characters _.-~ are not encoded, as well as the character / which represent a segment separator in hierarchical paths (RFC 3986 §3.3).

require "uri"

URI.encode_path("foo/bar/baz")  # => "foo/bar/baz"
URI.encode_path("hello world!") # => "hello%20world%21"
URI.encode_path("put: it+й")    # => "put%3A%20it%2B%D0%B9"
  • .decode is the reverse operation.
  • .encode_path_segment encodes a single path segment, escaping /.
Source
encode_path_segment(io : IO, string : String) : Nil

Encodes string so it can be safely placed inside a URI path segment, replacing special characters (including /) with URI escape sequences as needed.

Unreserved characters such as ASCII letters, digits, and the characters _.-~ are not encoded (see .unreserved?).

require "uri"

URI.encode_path_segment("foo;bar;baz")  # => "foo%3Bbar%3Bbaz"
URI.encode_path_segment("foo/bar/baz")  # => "foo%2Fbar%2Fbaz"
URI.encode_path_segment("foo,bar,baz")  # => "foo%2Cbar%2Cbaz"
URI.encode_path_segment("hello world!") # => "hello%20world%21"
URI.encode_path_segment("put: it+й")    # => "put%3A%20it%2B%D0%B9"
  • .decode is the reverse operation.
  • .encode_path encodes a path consisting of multiple segments, not escaping /.
  • .encode_www_form escapes space character as +.
Source
encode_path_segment(string : String) : String

Encodes string so it can be safely placed inside a URI path segment, replacing special characters (including /) with URI escape sequences as needed.

Unreserved characters such as ASCII letters, digits, and the characters _.-~ are not encoded (see .unreserved?).

require "uri"

URI.encode_path_segment("foo;bar;baz")  # => "foo%3Bbar%3Bbaz"
URI.encode_path_segment("foo/bar/baz")  # => "foo%2Fbar%2Fbaz"
URI.encode_path_segment("foo,bar,baz")  # => "foo%2Cbar%2Cbaz"
URI.encode_path_segment("hello world!") # => "hello%20world%21"
URI.encode_path_segment("put: it+й")    # => "put%3A%20it%2B%D0%B9"
  • .decode is the reverse operation.
  • .encode_path encodes a path consisting of multiple segments, not escaping /.
  • .encode_www_form escapes space character as +.
Source
encode_www_form(string : String, io : IO, *, space_to_plus : Bool = true) : Nil

URL-encodes string as x-www-form-urlencoded and writes the result to io.

See .encode_www_form(string : String, *, space_to_plus : Bool = true) for details.

Source
encode_www_form(string : String, *, space_to_plus : Bool = true) : String

URL-encodes string as x-www-form-urlencoded.

Reserved characters are escaped, unreserved characters are not. .reserved? and .unreserved? provide more details on these character classes.

require "uri"

URI.encode_www_form("hello world!")                             # => "hello+world%21"
URI.encode_www_form("put: it+й")                                # => "put%3A+it%2B%D0%B9"
URI.encode_www_form("http://example.com/Crystal is awesome =)") # => "http%3A%2F%2Fexample.com%2FCrystal+is+awesome+%3D%29"

The encoded string returned from this method can be used as name or value components for a application/x-www-form-urlencoded format serialization. URI::Params provides a higher-level API for this use case.

By default, the space character (0x20) is encoded as + and + is encoded as %2B. If space_to_plus is false, space character is encoded as %20 and '+' is encoded literally.

require "uri"

URI.encode_www_form("peter + paul")                       # => "peter+%2B+paul"
URI.encode_www_form("peter + paul", space_to_plus: false) # => "peter%20%2B%20paul"
  • .decode_www_form is the reverse operation.
  • .encode_path escapes space character as %20.
Source
from_json_object_key?(key : String) : URI | Nil

Deserializes the given JSON key into a URI

NOTE: require "uri/json" is required to opt-in to this feature.

Source
reserved?(byte) : Bool

Returns whether given byte is reserved character defined in RFC 3986 §2.2.

Reserved characters are ':', '/', '?', '#', '[', ']', '@', '!', '$', '&', "'", '(', ')', '*', '+', ',', ';' and '='.

Source
set_default_port(scheme : String, port : Int32 | Nil) : Nil

Registers the default port for the given scheme.

If port is nil, the existing default port for the scheme, if any, will be unregistered.

require "uri"

URI.set_default_port "ponzi", 9999
Source
unreserved?(byte) : Bool

Returns whether given byte is unreserved character defined in RFC 3986 §2.3.

Unreserved characters are ASCII letters, ASCII digits, _, ., - and ~.

Source
unwrap_ipv6(host) : String

Unwraps IPv6 address wrapped in square brackets.

Everything that is not wrapped in square brackets is returned unchanged.

URI.unwrap_ipv6("[::1]")       # => "::1"
URI.unwrap_ipv6("127.0.0.1")   # => "127.0.0.1"
URI.unwrap_ipv6("example.com") # => "example.com"
Source

Instance methods

==(other : self)

Returns true if this reference is the same as other. Invokes same?.

absolute?

Returns true if URI has a scheme specified.

Source
authority(io : IO) : Nil

Returns the authority component of this URI. It is formatted as user:pass@host:port with missing parts being omitted.

If the URI does not have any authority information, the result is nil.

uri = URI.parse "http://user:pass@example.com:80/path?query"
uri.authority # => "user:pass@example.com:80"

uri = URI.parse("/relative")
uri.authority # => nil
Source
authority

Returns the authority component of this URI. It is formatted as user:pass@host:port with missing parts being omitted.

If the URI does not have any authority information, the result is nil.

uri = URI.parse "http://user:pass@example.com:80/path?query"
uri.authority # => "user:pass@example.com:80"

uri = URI.parse("/relative")
uri.authority # => nil
Source
fragment

Returns the fragment component of the URI.

require "uri"

URI.parse("http://foo.com/bar#section1").fragment # => "section1"
Source
fragment=(fragment : String | Nil)

Sets the fragment component of the URI.

Source
hash(hasher)

See Object#hash(hasher)

host

Returns the host component of the URI.

require "uri"

URI.parse("http://foo.com").host # => "foo.com"
Source
host=(host : String | Nil)

Sets the host component of the URI.

Source
hostname

Returns the host part of the URI and unwrap brackets for IPv6 addresses.

require "uri"

URI.parse("http://[::1]/bar").hostname # => "::1"
URI.parse("http://[::1]/bar").host     # => "[::1]"
Source
normalize

Returns a normalized copy of this URI.

See #normalize! for details.

Source
normalize!

Normalizes this URI instance.

The following normalizations are applied to the individual components (if available):

  • scheme is lowercased.
  • host is lowercased.
  • port is removed if it is the .default_port? of the scheme.
  • path is resolved to a minimal, semantic equivalent representation removing dot segments /. and /...
uri = URI.parse("HTTP://example.COM:80/./foo/../bar/")
uri.normalize!
uri # => "http://example.com/bar/"
Source
opaque?

Returns true if this URI is opaque.

A URI is considered opaque if it has a scheme but no hierarchical part, i.e. no host and the first character of path is not a slash (/).

Source
password

Returns the password component of the URI.

require "uri"

URI.parse("http://admin:password@foo.com").password # => "password"
Source
password=(password : String | Nil)

Sets the password component of the URI.

Source
path

Returns the path component of the URI.

require "uri"

URI.parse("http://foo.com/bar").path # => "/bar"
Source
path=(path : String)

Sets the path component of the URI.

Source
port

Returns the port component of the URI.

require "uri"

URI.parse("http://foo.com:5432").port # => 5432
Source
port=(port : Int32 | Nil)

Sets the port component of the URI.

Source
query

Returns the query component of the URI.

require "uri"

URI.parse("http://foo.com/bar?q=1").query # => "q=1"
Source
query=(query : String | Nil)

Sets the query component of the URI.

Source
query_params

Returns a URI::Params of the URI#query.

require "uri"

uri = URI.parse "http://foo.com?id=30&limit=5#time=1305298413"
uri.query_params # => URI::Params{"id" => ["30"], "limit" => ["5"]}
Source
query_params=(params : URI::Params)

Sets query to stringified params.

require "uri"

uri = URI.new
uri.query_params = URI::Params.parse("foo=bar&foo=baz")
uri.to_s # => "?foo=bar&foo=baz"
Source
relative?

Returns true if URI does not have a scheme specified.

Source
relativize(uri : URI | String) : URI

Relativizes uri against this URI.

An exact copy of uri is returned if

  • this URI or uri are opaque?, or
  • the scheme and authority (host, port, user, password) components are not identical.

Otherwise a new relative hierarchical URI is constructed with query and fragment components from uri and with a path component that describes a minimum-difference relative path from #path to uri's path.

URI.parse("http://foo.com/bar/baz").relativize("http://foo.com/quux")         # => "../quux"
URI.parse("http://foo.com/bar/baz").relativize("http://foo.com/bar/quux")     # => "quux"
URI.parse("http://foo.com/bar/baz").relativize("http://quux.com")             # => "http://quux.com"
URI.parse("http://foo.com/bar/baz").relativize("http://foo.com/bar/baz#quux") # => "#quux"

This method is the inverse operation to #resolve (see [Resolution and Relativization](#Resolution and Relativization)).

Source
request_target

Returns the concatenation of path and query as it would be used as a request target in an HTTP request.

If path is empty in an hierarchical URI, "/" is used.

require "uri"

uri = URI.parse "http://example.com/posts?id=30&limit=5#time=1305298413"
uri.request_target # => "/posts?id=30&limit=5"

uri = URI.new(path: "", query: "foo=bar")
uri.request_target # => "/?foo=bar"
Source
resolve(uri : URI | String) : URI

Resolves uri against this URI.

If uri is absolute?, or if this URI is opaque?, then an exact copy of uri is returned.

Otherwise the URI is resolved according to the specifications in RFC 3986 section 5.2.

URI.parse("http://foo.com/bar/baz").resolve("../quux")         # => "http://foo.com/quux"
URI.parse("http://foo.com/bar/baz").resolve("/quux")           # => "http://foo.com/quux"
URI.parse("http://foo.com/bar/baz").resolve("http://quux.com") # => "http://quux.com"
URI.parse("http://foo.com/bar/baz").resolve("#quux")           # => "http://foo.com/bar/baz#quux"

This method is the inverse operation to #relativize (see [Resolution and Relativization](#Resolution and Relativization)).

Source
scheme

Returns the scheme component of the URI.

require "uri"

URI.parse("http://foo.com").scheme           # => "http"
URI.parse("mailto:alice@example.com").scheme # => "mailto"
Source
scheme=(scheme : String | Nil)

Sets the scheme component of the URI.

Source
to_json(builder : JSON::Builder)

Serializes this URI to JSON, represented as a string.

require "uri/json"

URI.parse("http://example.com").to_json # => %("http://example.com")
Source
to_s(io : IO) : Nil

Appends a short String representation of this object which includes its class name and its object address.

class Person
  def initialize(@name : String, @age : Int32)
  end
end

Person.new("John", 32).to_s # => #<Person:0x10a199f20>
Source
to_yaml(yaml : YAML::Nodes::Builder)

Serializes this URI to YAML, represented as a string.

require "uri/yaml"

URI.parse("http://example.com").to_yaml # => "--- http://example.com\n"
Source
update_query_params

Yields the value of #query_params commits any modifications of the URI::Params instance to self. Returns the modified URI::Params

require "uri"
uri = URI.parse("http://foo.com?id=30&limit=5#time=1305298413")
uri.update_query_params { |params| params.delete_all("limit") } # => URI::Params{"id" => ["30"]}

puts uri.to_s # => "http://foo.com?id=30#time=1305298413"
Source
user

Returns the user component of the URI.

require "uri"

URI.parse("http://admin:password@foo.com").user # => "admin"
Source
user=(user : String | Nil)

Sets the user component of the URI.

Source
userinfo

Returns the user-information component containing the provided username and password.

require "uri"

uri = URI.parse "http://admin:password@foo.com"
uri.userinfo # => "admin:password"

The return value is URL encoded (see #encode_www_form).

Source

Nested types