1uri_string(3) Erlang Module Definition uri_string(3)
2
3
4
6 uri_string - URI processing functions.
7
9 This module contains functions for parsing and handling URIs (RFC 3986)
10 and form-urlencoded query strings (HTML 5.2).
11
12 Parsing and serializing non-UTF-8 form-urlencoded query strings are
13 also supported (HTML 5.0).
14
15 A URI is an identifier consisting of a sequence of characters matching
16 the syntax rule named URI in RFC 3986.
17
18 The generic URI syntax consists of a hierarchical sequence of compo‐
19 nents referred to as the scheme, authority, path, query, and fragment:
20
21 URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
22 hier-part = "//" authority path-abempty
23 / path-absolute
24 / path-rootless
25 / path-empty
26 scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
27 authority = [ userinfo "@" ] host [ ":" port ]
28 userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
29
30 reserved = gen-delims / sub-delims
31 gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
32 sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
33 / "*" / "+" / "," / ";" / "="
34
35 unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
36
37
38
39 The interpretation of a URI depends only on the characters used and not
40 on how those characters are represented in a network protocol.
41
42 The functions implemented by this module cover the following use cases:
43
44 * Parsing URIs into its components and returing a map
45 parse/1
46
47 * Recomposing a map of URI components into a URI string
48 recompose/1
49
50 * Changing inbound binary and percent-encoding of URIs
51 transcode/2
52
53 * Transforming URIs into a normalized form
54 normalize/1
55 normalize/2
56
57 * Composing form-urlencoded query strings from a list of key-value
58 pairs
59 compose_query/1
60 compose_query/2
61
62 * Dissecting form-urlencoded query strings into a list of key-value
63 pairs
64 dissect_query/1
65
66 There are four different encodings present during the handling of URIs:
67
68 * Inbound binary encoding in binaries
69
70 * Inbound percent-encoding in lists and binaries
71
72 * Outbound binary encoding in binaries
73
74 * Outbound percent-encoding in lists and binaries
75
76 Functions with uri_string() argument accept lists, binaries and mixed
77 lists (lists with binary elements) as input type. All of the functions
78 but transcode/2 expects input as lists of unicode codepoints, UTF-8
79 encoded binaries and UTF-8 percent-encoded URI parts ("%C3%B6" corre‐
80 sponds to the unicode character "ö").
81
82 Unless otherwise specified the return value type and encoding are the
83 same as the input type and encoding. That is, binary input returns
84 binary output, list input returns a list output but mixed input returns
85 list output.
86
87 In case of lists there is only percent-encoding. In binaries, however,
88 both binary encoding and percent-encoding shall be considered.
89 transcode/2 provides the means to convert between the supported encod‐
90 ings, it takes a uri_string() and a list of options specifying inbound
91 and outbound encodings.
92
93 RFC 3986 does not mandate any specific character encoding and it is
94 usually defined by the protocol or surrounding text. This library takes
95 the same assumption, binary and percent-encoding are handled as one
96 configuration unit, they cannot be set to different values.
97
99 error() = {error, atom(), term()}
100
101 Error tuple indicating the type of error. Possible values of the
102 second component:
103
104 * invalid_character
105
106 * invalid_encoding
107
108 * invalid_input
109
110 * invalid_map
111
112 * invalid_percent_encoding
113
114 * invalid_scheme
115
116 * invalid_uri
117
118 * invalid_utf8
119
120 * missing_value
121
122 The third component is a term providing additional information
123 about the cause of the error.
124
125 uri_map() =
126 #{fragment => unicode:chardata(),
127 host => unicode:chardata(),
128 path => unicode:chardata(),
129 port => integer() >= 0 | undefined,
130 query => unicode:chardata(),
131 scheme => unicode:chardata(),
132 userinfo => unicode:chardata()} |
133 #{}
134
135 Map holding the main components of a URI.
136
137 uri_string() = iodata()
138
139 List of unicode codepoints, a UTF-8 encoded binary, or a mix of
140 the two, representing an RFC 3986 compliant URI (percent-encoded
141 form). A URI is a sequence of characters from a very limited
142 set: the letters of the basic Latin alphabet, digits, and a few
143 special characters.
144
146 compose_query(QueryList) -> QueryString
147
148 Types:
149
150 QueryList = [{unicode:chardata(), unicode:chardata() | true}]
151 QueryString = uri_string() | error()
152
153 Composes a form-urlencoded QueryString based on a QueryList, a
154 list of non-percent-encoded key-value pairs. Form-urlencoding is
155 defined in section 4.10.21.6 of the HTML 5.2 specification and
156 in section 4.10.22.6 of the HTML 5.0 specification for non-UTF-8
157 encodings.
158
159 See also the opposite operation dissect_query/1.
160
161 Example:
162
163 1> uri_string:compose_query([{"foo bar","1"},{"city","örebro"}]).
164 "foo+bar=1&city=%C3%B6rebro"
165 2> uri_string:compose_query([{<<"foo bar">>,<<"1">>},
166 2> {<<"city">>,<<"örebro"/utf8>>}]).
167 <<"foo+bar=1&city=%C3%B6rebro">>
168
169
170 compose_query(QueryList, Options) -> QueryString
171
172 Types:
173
174 QueryList = [{unicode:chardata(), unicode:chardata() | true}]
175 Options = [{encoding, atom()}]
176 QueryString = uri_string() | error()
177
178 Same as compose_query/1 but with an additional Options parame‐
179 ter, that controls the encoding ("charset") used by the encoding
180 algorithm. There are two supported encodings: utf8 (or unicode)
181 and latin1.
182
183 Each character in the entry's name and value that cannot be
184 expressed using the selected character encoding, is replaced by
185 a string consisting of a U+0026 AMPERSAND character (&), a "#"
186 (U+0023) character, one or more ASCII digits representing the
187 Unicode code point of the character in base ten, and finally a
188 ";" (U+003B) character.
189
190 Bytes that are out of the range 0x2A, 0x2D, 0x2E, 0x30 to 0x39,
191 0x41 to 0x5A, 0x5F, 0x61 to 0x7A, are percent-encoded (U+0025
192 PERCENT SIGN character (%) followed by uppercase ASCII hex dig‐
193 its representing the hexadecimal value of the byte).
194
195 See also the opposite operation dissect_query/1.
196
197 Example:
198
199 1> uri_string:compose_query([{"foo bar","1"},{"city","örebro"}],
200 1> [{encoding, latin1}]).
201 "foo+bar=1&city=%F6rebro"
202 2> uri_string:compose_query([{<<"foo bar">>,<<"1">>},
203 2> {<<"city">>,<<"東京"/utf8>>}], [{encoding, latin1}]).
204 <<"foo+bar=1&city=%26%2326481%3B%26%2320140%3B">>
205
206
207 dissect_query(QueryString) -> QueryList
208
209 Types:
210
211 QueryString = uri_string()
212 QueryList =
213 [{unicode:chardata(), unicode:chardata() | true}] |
214 error()
215
216 Dissects an urlencoded QueryString and returns a QueryList, a
217 list of non-percent-encoded key-value pairs. Form-urlencoding is
218 defined in section 4.10.21.6 of the HTML 5.2 specification and
219 in section 4.10.22.6 of the HTML 5.0 specification for non-UTF-8
220 encodings.
221
222 See also the opposite operation compose_query/1.
223
224 Example:
225
226 1> uri_string:dissect_query("foo+bar=1&city=%C3%B6rebro").
227 [{"foo bar","1"},{"city","örebro"}]
228 2> uri_string:dissect_query(<<"foo+bar=1&city=%26%2326481%3B%26%2320140%3B">>).
229 [{<<"foo bar">>,<<"1">>},
230 {<<"city">>,<<230,157,177,228,186,172>>}]
231
232
233 normalize(URI) -> NormalizedURI
234
235 Types:
236
237 URI = uri_string() | uri_map()
238 NormalizedURI = uri_string() | error()
239
240 Transforms an URI into a normalized form using Syntax-Based Nor‐
241 malization as defined by RFC 3986.
242
243 This function implements case normalization, percent-encoding
244 normalization, path segment normalization and scheme based nor‐
245 malization for HTTP(S) with basic support for FTP, SSH, SFTP and
246 TFTP.
247
248 Example:
249
250 1> uri_string:normalize("/a/b/c/./../../g").
251 "/a/g"
252 2> uri_string:normalize(<<"mid/content=5/../6">>).
253 <<"mid/6">>
254 3> uri_string:normalize("http://localhost:80").
255 "https://localhost/"
256 4> uri_string:normalize(#{scheme => "http",port => 80,path => "/a/b/c/./../../g",
257 4> host => "localhost-örebro"}).
258 "http://localhost-%C3%B6rebro/a/g"
259
260
261 normalize(URI, Options) -> NormalizedURI
262
263 Types:
264
265 URI = uri_string() | uri_map()
266 Options = [return_map]
267 NormalizedURI = uri_string() | uri_map() | error()
268
269 Same as normalize/1 but with an additional Options parameter,
270 that controls whether the normalized URI shall be returned as an
271 uri_map(). There is one supported option: return_map.
272
273 Example:
274
275 1> uri_string:normalize("/a/b/c/./../../g", [return_map]).
276 #{path => "/a/g"}
277 2> uri_string:normalize(<<"mid/content=5/../6">>, [return_map]).
278 #{path => <<"mid/6">>}
279 3> uri_string:normalize("http://localhost:80", [return_map]).
280 #{scheme => "http",path => "/",host => "localhost"}
281 4> uri_string:normalize(#{scheme => "http",port => 80,path => "/a/b/c/./../../g",
282 4> host => "localhost-örebro"}, [return_map]).
283 #{scheme => "http",path => "/a/g",host => "localhost-örebro"}
284
285
286 parse(URIString) -> URIMap
287
288 Types:
289
290 URIString = uri_string()
291 URIMap = uri_map() | error()
292
293 Parses an RFC 3986 compliant uri_string() into a uri_map(), that
294 holds the parsed components of the URI. If parsing fails, an
295 error tuple is returned.
296
297 See also the opposite operation recompose/1.
298
299 Example:
300
301 1> uri_string:parse("foo://user@example.com:8042/over/there?name=ferret#nose").
302 #{fragment => "nose",host => "example.com",
303 path => "/over/there",port => 8042,query => "name=ferret",
304 scheme => foo,userinfo => "user"}
305 2> uri_string:parse(<<"foo://user@example.com:8042/over/there?name=ferret">>).
306 #{host => <<"example.com">>,path => <<"/over/there">>,
307 port => 8042,query => <<"name=ferret">>,scheme => <<"foo">>,
308 userinfo => <<"user">>}
309
310
311 recompose(URIMap) -> URIString
312
313 Types:
314
315 URIMap = uri_map()
316 URIString = uri_string() | error()
317
318 Creates an RFC 3986 compliant URIString (percent-encoded), based
319 on the components of URIMap. If the URIMap is invalid, an error
320 tuple is returned.
321
322 See also the opposite operation parse/1.
323
324 Example:
325
326 1> URIMap = #{fragment => "nose", host => "example.com", path => "/over/there",
327 1> port => 8042, query => "name=ferret", scheme => "foo", userinfo => "user"}.
328 #{fragment => "top",host => "example.com",
329 path => "/over/there",port => 8042,query => "?name=ferret",
330 scheme => foo,userinfo => "user"}
331
332 2> uri_string:recompose(URIMap).
333 "foo://example.com:8042/over/there?name=ferret#nose"
334
335 resolve(RefURI, BaseURI) -> TargetURI
336
337 Types:
338
339 RefURI = BaseURI = uri_string() | uri_map()
340 TargetURI = uri_string() | error()
341
342 Convert a RefURI reference that might be relative to a given
343 base URI into the parsed components of the reference's target,
344 which can then be recomposed to form the target URI.
345
346 Example:
347
348 1> uri_string:resolve("/abs/ol/ute", "http://localhost/a/b/c?q").
349 "http://localhost/abs/ol/ute"
350 2> uri_string:resolve("../relative", "http://localhost/a/b/c?q").
351 "http://localhost/a/relative"
352 3> uri_string:resolve("http://localhost/full", "http://localhost/a/b/c?q").
353 "http://localhost/full"
354 4> uri_string:resolve(#{path => "path", query => "xyz"}, "http://localhost/a/b/c?q").
355 "http://localhost/a/b/path?xyz"
356
357
358 resolve(RefURI, BaseURI, Options) -> TargetURI
359
360 Types:
361
362 RefURI = BaseURI = uri_string() | uri_map()
363 Options = [return_map]
364 TargetURI = uri_string() | uri_map() | error()
365
366 Same as resolve/2 but with an additional Options parameter, that
367 controls whether the target URI shall be returned as an
368 uri_map(). There is one supported option: return_map.
369
370 Example:
371
372 1> uri_string:resolve("/abs/ol/ute", "http://localhost/a/b/c?q", [return_map]).
373 #{host => "localhost",path => "/abs/ol/ute",scheme => "http"}
374 2> uri_string:resolve(#{path => "/abs/ol/ute"}, #{scheme => "http",
375 2> host => "localhost", path => "/a/b/c?q"}, [return_map]).
376 #{host => "localhost",path => "/abs/ol/ute",scheme => "http"}
377
378
379 transcode(URIString, Options) -> Result
380
381 Types:
382
383 URIString = uri_string()
384 Options =
385 [{in_encoding, unicode:encoding()} |
386 {out_encoding, unicode:encoding()}]
387 Result = uri_string() | error()
388
389 Transcodes an RFC 3986 compliant URIString, where Options is a
390 list of tagged tuples, specifying the inbound (in_encoding) and
391 outbound (out_encoding) encodings. in_encoding and out_encoding
392 specifies both binary encoding and percent-encoding for the
393 input and output data. Mixed encoding, where binary encoding is
394 not the same as percent-encoding, is not supported. If an argu‐
395 ment is invalid, an error tuple is returned.
396
397 Example:
398
399 1> uri_string:transcode(<<"foo%00%00%00%F6bar"/utf32>>,
400 1> [{in_encoding, utf32},{out_encoding, utf8}]).
401 <<"foo%C3%B6bar"/utf8>>
402 2> uri_string:transcode("foo%F6bar", [{in_encoding, latin1},
403 2> {out_encoding, utf8}]).
404 "foo%C3%B6bar"
405
406
407
408
409Ericsson AB stdlib 3.12.1 uri_string(3)