diff --git a/fuzzing/fuzz_uri_parse.c b/fuzzing/fuzz_uri_parse.c index 4faed62a1..b9425934e 100644 --- a/fuzzing/fuzz_uri_parse.c +++ b/fuzzing/fuzz_uri_parse.c @@ -31,7 +31,7 @@ LLVMFuzzerTestOneInput (const unsigned char *data, size_t size) /* ignore @size (g_uri_parse() doesn’t support it); ensure @data is nul-terminated */ nul_terminated_data = (unsigned char *) g_strndup ((const gchar *) data, size); test_with_flags ((const gchar *) nul_terminated_data, G_URI_FLAGS_NONE); - test_with_flags ((const gchar *) nul_terminated_data, G_URI_FLAGS_PARSE_STRICT); + test_with_flags ((const gchar *) nul_terminated_data, G_URI_FLAGS_PARSE_RELAXED); g_free (nul_terminated_data); return 0; diff --git a/gio/gnetworkaddress.c b/gio/gnetworkaddress.c index a93bafa36..b51d9c58d 100644 --- a/gio/gnetworkaddress.c +++ b/gio/gnetworkaddress.c @@ -546,7 +546,7 @@ g_network_address_parse_uri (const gchar *uri, gchar *hostname = NULL; gint port; - if (!g_uri_split_network (uri, G_URI_FLAGS_PARSE_STRICT, + if (!g_uri_split_network (uri, G_URI_FLAGS_NONE, &scheme, &hostname, &port, NULL)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, diff --git a/gio/gproxyresolver.c b/gio/gproxyresolver.c index f72ad2a72..ca346633a 100644 --- a/gio/gproxyresolver.c +++ b/gio/gproxyresolver.c @@ -148,7 +148,7 @@ g_proxy_resolver_lookup (GProxyResolver *resolver, g_return_val_if_fail (G_IS_PROXY_RESOLVER (resolver), NULL); g_return_val_if_fail (uri != NULL, NULL); - if (!g_uri_is_valid (uri, G_URI_FLAGS_PARSE_STRICT, NULL)) + if (!g_uri_is_valid (uri, G_URI_FLAGS_NONE, NULL)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, "Invalid URI ‘%s’", uri); @@ -186,7 +186,7 @@ g_proxy_resolver_lookup_async (GProxyResolver *resolver, g_return_if_fail (G_IS_PROXY_RESOLVER (resolver)); g_return_if_fail (uri != NULL); - if (!g_uri_is_valid (uri, G_URI_FLAGS_PARSE_STRICT, NULL)) + if (!g_uri_is_valid (uri, G_URI_FLAGS_NONE, NULL)) { g_set_error (&error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, "Invalid URI ‘%s’", uri); diff --git a/gio/gsimpleproxyresolver.c b/gio/gsimpleproxyresolver.c index 58368ea4e..0dd3c4fc3 100644 --- a/gio/gsimpleproxyresolver.c +++ b/gio/gsimpleproxyresolver.c @@ -329,7 +329,7 @@ g_simple_proxy_resolver_lookup (GProxyResolver *proxy_resolver, gchar *host = NULL; gint port; - if (g_uri_split_network (uri, G_URI_FLAGS_PARSE_STRICT, NULL, + if (g_uri_split_network (uri, G_URI_FLAGS_NONE, NULL, &host, &port, NULL) && ignore_host (resolver, host, port > 0 ? port : 0)) proxy = "direct://"; diff --git a/glib/guri.c b/glib/guri.c index 87dcc6441..bead318e5 100644 --- a/glib/guri.c +++ b/glib/guri.c @@ -34,16 +34,49 @@ * their components, and build valid URIs from individual components. * * Note that #GUri scope is to help manipulate URIs in various applications, - * following the RFC 3986. In particular, it doesn't intend to cover web browser - * needs, and doesn't implement the WHATWG URL standard. No APIs are provided to - * help prevent homograph attacks. + * following [RFC 3986](https://tools.ietf.org/html/rfc3986). In particular, + * it doesn't intend to cover web browser needs, and doesn't implement the + * [WHATWG URL](https://url.spec.whatwg.org/) standard. No APIs are provided to + * help prevent + * [homograph attacks](https://en.wikipedia.org/wiki/IDN_homograph_attack), so + * #GUri is not suitable for formatting URIs for display to the user for making + * security-sensitive decisions. + * + * ## Relative and absolute URIs # {#relative-absolute-uris} + * + * As defined in [RFC 3986](https://tools.ietf.org/html/rfc3986#section-4), the + * hierarchical nature of URIs means that they can either be ‘relative + * references’ (sometimes referred to as ‘relative URIs’) or ‘URIs’ (for + * clarity, ‘URIs’ are referred to in this documentation as + * ‘absolute URIs’ — although + * [in constrast to RFC 3986](https://tools.ietf.org/html/rfc3986#section-4.3), + * fragment identifiers are always allowed). + * + * Relative references have one or more components of the URI missing. In + * particular, they have no scheme. Any other component, such as hostname, + * query, etc. may be missing, apart from a path, which has to be specified (but + * may be empty). The path may be relative, starting with `./` rather than `/`. + * + * For example, a valid relative reference is `./path?query`, + * `/?query#fragment` or `//example.com`. + * + * Absolute URIs have a scheme specified. Any other components of the URI which + * are missing are specified as explicitly unset in the URI, rather than being + * resolved relative to a base URI using g_uri_parse_relative(). + * + * For example, a valid absolute URI is `file:///home/bob` or + * `https://search.com?query=string`. + * + * A #GUri instance is always an absolute URI. A string may be an absolute URI + * or a relative reference; see the documentation for individual functions as to + * what forms they accept. * * ## Parsing URIs * * The most minimalist APIs for parsing URIs are g_uri_split() and * g_uri_split_with_user(). These split a URI into its component * parts, and return the parts; the difference between the two is that - * g_uri_split() treats the "userinfo" component of the URI as a + * g_uri_split() treats the ‘userinfo’ component of the URI as a * single element, while g_uri_split_with_user() can (depending on the * #GUriFlags you pass) treat it as containing a username, password, * and authentication parameters. Alternatively, g_uri_split_network() @@ -68,20 +101,23 @@ * use g_uri_peek_scheme() on the URI string to check the scheme * first, and use that to decide what flags to parse it with. * + * For example, you might want to use %G_URI_PARAMS_WWW_FORM when parsing the + * params for a web URI, so compare the result of g_uri_peek_scheme() against + * `http` and `https`. + * * ## Building URIs * * g_uri_join() and g_uri_join_with_user() can be used to construct - * valid URI strings from a set of component strings; they are the + * valid URI strings from a set of component strings. They are the * inverse of g_uri_split() and g_uri_split_with_user(). * * Similarly, g_uri_build() and g_uri_build_with_user() can be used to * construct a #GUri from a set of component strings. * * As with the parsing functions, the building functions take a - * #GUriFlags argument; in particular, it is important to keep in mind - * whether the URI components you are using have `%`-encoded - * characters in them or not, and pass the appropriate flags - * accordingly. + * #GUriFlags argument. In particular, it is important to keep in mind + * whether the URI components you are using are already `%`-encoded. If so, + * you must pass the %G_URI_FLAGS_ENCODED flag. * * ## `file://` URIs * @@ -96,10 +132,10 @@ * * Note that there is no `g_uri_equal ()` function, because comparing * URIs usefully requires scheme-specific knowledge that #GUri does - * not have. For example, "`http://example.com/`" and - * "`http://EXAMPLE.COM:80`" have exactly the same meaning according - * to the HTTP specification, and "`data:,foo`" and - * "`data:;base64,Zm9v`" resolve to the same thing according to the + * not have. For example, `http://example.com/` and + * `http://EXAMPLE.COM:80` have exactly the same meaning according + * to the HTTP specification, and `data:,foo` and + * `data:;base64,Zm9v` resolve to the same thing according to the * `data:` URI specification. * * Since: 2.66 @@ -113,13 +149,14 @@ * Since #GUri only represents absolute URIs, all #GUris will have a * URI scheme, so g_uri_get_scheme() will always return a non-%NULL * answer. Likewise, by definition, all URIs have a path component, so - * g_uri_get_path() will always return non-%NULL (though it may return - * the empty string). + * g_uri_get_path() will always return a non-%NULL string (which may be empty). * - * If the URI string has an "authority" component (that is, if the - * scheme is followed by "`://`" rather than just "`:`"), then the - * #GUri will contain a hostname, and possibly a port and "userinfo". - * Additionally, depending on how the #GUri was constructed/parsed, + * If the URI string has an + * [‘authority’ component](https://tools.ietf.org/html/rfc3986#section-3) (that + * is, if the scheme is followed by `://` rather than just `:`), then the + * #GUri will contain a hostname, and possibly a port and ‘userinfo’. + * Additionally, depending on how the #GUri was constructed/parsed (for example, + * using the %G_URI_FLAGS_HAS_PASSWORD and %G_URI_FLAGS_HAS_AUTH_PARAMS flags), * the userinfo may be split out into a username, password, and * additional authorization-related parameters. * @@ -134,14 +171,14 @@ * For example, with the encoded flag: * * |[ - * GUri *uri = g_uri_parse ("http://host/path?query=http%3A%2F%2Fhost%2Fpath%3Fparam%3Dvalue", G_URI_FLAGS_ENCODED, &err); + * g_autoptr(GUri) uri = g_uri_parse ("http://host/path?query=http%3A%2F%2Fhost%2Fpath%3Fparam%3Dvalue", G_URI_FLAGS_ENCODED, &err); * g_assert_cmpstr (g_uri_get_query (uri), ==, "query=http%3A%2F%2Fhost%2Fpath%3Fparam%3Dvalue"); * ]| * * While the default `%`-decoding behaviour would give: * * |[ - * GUri *uri = g_uri_parse ("http://host/path?query=http%3A%2F%2Fhost%2Fpath%3Fparam%3Dvalue", G_URI_FLAGS_NONE, &err); + * g_autoptr(GUri) uri = g_uri_parse ("http://host/path?query=http%3A%2F%2Fhost%2Fpath%3Fparam%3Dvalue", G_URI_FLAGS_NONE, &err); * g_assert_cmpstr (g_uri_get_query (uri), ==, "query=http://host/path?param=value"); * ]| * @@ -149,13 +186,13 @@ * with an error indicating the bad string location: * * |[ - * GUri *uri = g_uri_parse ("http://host/path?query=http%3A%2F%2Fhost%2Fpath%3Fbad%3D%00alue", G_URI_FLAGS_NONE, &err); - * g_assert_error(err, G_URI_ERROR, G_URI_ERROR_BAD_QUERY); + * g_autoptr(GUri) uri = g_uri_parse ("http://host/path?query=http%3A%2F%2Fhost%2Fpath%3Fbad%3D%00alue", G_URI_FLAGS_NONE, &err); + * g_assert_error (err, G_URI_ERROR, G_URI_ERROR_BAD_QUERY); * ]| * * You should pass %G_URI_FLAGS_ENCODED or %G_URI_FLAGS_ENCODED_QUERY if you * need to handle that case manually. In particular, if the query string - * contains '=' characters that are '%'-encoded, you should let + * contains `=` characters that are `%`-encoded, you should let * g_uri_parse_params() do the decoding once of the query. * * #GUri is immutable once constructed, and can safely be accessed from @@ -197,7 +234,8 @@ g_uri_ref (GUri *uri) return g_atomic_rc_box_acquire (uri); } -static void g_uri_clear(GUri *uri) +static void +g_uri_clear (GUri *uri) { g_free (uri->scheme); g_free (uri->userinfo); @@ -268,10 +306,10 @@ uri_decoder (gchar **out, !g_ascii_isxdigit (s[2])) { /* % followed by non-hex or the end of the string; this is an error */ - if (flags & G_URI_FLAGS_PARSE_STRICT) + if (!(flags & G_URI_FLAGS_PARSE_RELAXED)) { g_set_error_literal (error, G_URI_ERROR, parse_error, - /* xgettext: no-c-format */ + /* xgettext: no-c-format */ _("Invalid %-encoding in URI")); g_free (decoded); return -1; @@ -420,7 +458,7 @@ parse_host (const gchar *start, bad_ipv6_literal: g_free (addr); g_set_error (error, G_URI_ERROR, G_URI_ERROR_BAD_HOST, - _("Invalid IPv6 address '%.*s' in URI"), + _("Invalid IPv6 address ‘%.*s’ in URI"), (gint)length, start); return FALSE; } @@ -482,7 +520,7 @@ parse_host (const gchar *start, { g_free (decoded); g_set_error (error, G_URI_ERROR, G_URI_ERROR_BAD_HOST, - _("Illegal encoded IP address '%.*s' in URI"), + _("Illegal encoded IP address ‘%.*s’ in URI"), (gint)length, start); return FALSE; } @@ -516,7 +554,7 @@ parse_port (const gchar *start, if (!g_ascii_isdigit (*start)) { g_set_error (error, G_URI_ERROR, G_URI_ERROR_BAD_PORT, - _("Could not parse port '%.*s' in URI"), + _("Could not parse port ‘%.*s’ in URI"), (gint)length, start); return FALSE; } @@ -528,14 +566,14 @@ parse_port (const gchar *start, if (end != start + length) { g_set_error (error, G_URI_ERROR, G_URI_ERROR_BAD_PORT, - _("Could not parse port '%.*s' in URI"), + _("Could not parse port ‘%.*s’ in URI"), (gint)length, start); return FALSE; } else if (parsed_port > 65535) { g_set_error (error, G_URI_ERROR, G_URI_ERROR_BAD_PORT, - _("Port '%.*s' in URI is out of range"), + _("Port ‘%.*s’ in URI is out of range"), (gint)length, start); return FALSE; } @@ -672,7 +710,7 @@ g_uri_split_internal (const gchar *uri_string, if (fragment) *fragment = NULL; - if (!(flags & G_URI_FLAGS_PARSE_STRICT) && strpbrk (uri_string, " \t\n\r")) + if ((flags & G_URI_FLAGS_PARSE_RELAXED) && strpbrk (uri_string, " \t\n\r")) { cleaned_uri_string = uri_cleanup (uri_string); uri_string = cleaned_uri_string; @@ -707,7 +745,7 @@ g_uri_split_internal (const gchar *uri_string, at = memchr (p, '@', path_start - p); if (at) { - if (!(flags & G_URI_FLAGS_PARSE_STRICT)) + if (flags & G_URI_FLAGS_PARSE_RELAXED) { gchar *next_at; @@ -742,7 +780,7 @@ g_uri_split_internal (const gchar *uri_string, p = at + 1; } - if (!(flags & G_URI_FLAGS_PARSE_STRICT)) + if (flags & G_URI_FLAGS_PARSE_RELAXED) { semi = strchr (p, ';'); if (semi && semi < path_start) @@ -847,9 +885,9 @@ g_uri_split_internal (const gchar *uri_string, * the userinfo, or %NULL * @host: (out) (nullable) (optional) (transfer full): on return, contains the * host, or %NULL - * @port: (out) (nullable) (optional) (transfer full): on return, contains the - * port, or -1 - * @path: (out) (nullable) (optional) (transfer full): on return, contains the + * @port: (out) (optional) (transfer full): on return, contains the + * port, or `-1` + * @path: (out) (not nullable) (optional) (transfer full): on return, contains the * path * @query: (out) (nullable) (optional) (transfer full): on return, contains the * query, or %NULL @@ -857,11 +895,11 @@ g_uri_split_internal (const gchar *uri_string, * the fragment, or %NULL * @error: #GError for error reporting, or %NULL to ignore. * - * Parses @uri_ref (which can be an absolute or relative URI) - * according to @flags, and returns the pieces. Any component that - * doesn't appear in @uri_ref will be returned as %NULL (but note - * that all URIs always have a path component, though it may be the - * empty string). + * Parses @uri_ref (which can be an + * [absolute or relative URI][relative-absolute-uris]) according to @flags, and + * returns the pieces. Any component that doesn't appear in @uri_ref will be + * returned as %NULL (but note that all URIs always have a path component, + * though it may be the empty string). * * If @flags contains %G_URI_FLAGS_ENCODED, then `%`-encoded characters in * @uri_ref will remain encoded in the output strings. (If not, @@ -914,9 +952,9 @@ g_uri_split (const gchar *uri_ref, * the auth_params, or %NULL * @host: (out) (nullable) (optional) (transfer full): on return, contains the * host, or %NULL - * @port: (out) (nullable) (optional) (transfer full): on return, contains the - * port, or -1 - * @path: (out) (nullable) (optional) (transfer full): on return, contains the + * @port: (out) (optional) (transfer full): on return, contains the + * port, or `-1` + * @path: (out) (not nullable) (optional) (transfer full): on return, contains the * path * @query: (out) (nullable) (optional) (transfer full): on return, contains the * query, or %NULL @@ -924,11 +962,11 @@ g_uri_split (const gchar *uri_ref, * the fragment, or %NULL * @error: #GError for error reporting, or %NULL to ignore. * - * Parses @uri_ref (which can be an absolute or relative URI) - * according to @flags, and returns the pieces. Any component that - * doesn't appear in @uri_ref will be returned as %NULL (but note - * that all URIs always have a path component, though it may be the - * empty string). + * Parses @uri_ref (which can be an + * [absolute or relative URI][relative-absolute-uris]) according to @flags, and + * returns the pieces. Any component that doesn't appear in @uri_ref will be + * returned as %NULL (but note that all URIs always have a path component, + * though it may be the empty string). * * See g_uri_split(), and the definition of #GUriFlags, for more * information on the effect of @flags. Note that @password will only @@ -973,12 +1011,12 @@ g_uri_split_with_user (const gchar *uri_ref, * the scheme (converted to lowercase), or %NULL * @host: (out) (nullable) (optional) (transfer full): on return, contains the * host, or %NULL - * @port: (out) (nullable) (optional) (transfer full): on return, contains the - * port, or -1 + * @port: (out) (optional) (transfer full): on return, contains the + * port, or `-1` * @error: #GError for error reporting, or %NULL to ignore. * - * Parses @uri_string (which must be an absolute URI) according to - * @flags, and returns the pieces relevant to connecting to a host. + * Parses @uri_string (which must be an [absolute URI][relative-absolute-uris]) + * according to @flags, and returns the pieces relevant to connecting to a host. * See the documentation for g_uri_split() for more details; this is * mostly a wrapper around that function with simpler arguments. * However, it will return an error if @uri_string is a relative URI, @@ -997,7 +1035,7 @@ g_uri_split_network (const gchar *uri_string, gint *port, GError **error) { - gchar *my_scheme, *my_host; + gchar *my_scheme = NULL, *my_host = NULL; g_return_val_if_fail (uri_string != NULL, FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); @@ -1013,13 +1051,13 @@ g_uri_split_network (const gchar *uri_string, if (!my_scheme) { g_set_error (error, G_URI_ERROR, G_URI_ERROR_BAD_SCHEME, - _("URI '%s' is not an absolute URI"), + _("URI ‘%s’ is not an absolute URI"), uri_string); } else { g_set_error (error, G_URI_ERROR, G_URI_ERROR_BAD_HOST, - _("URI '%s' has no host component"), + _("URI ‘%s’ has no host component"), uri_string); } g_free (my_scheme); @@ -1029,13 +1067,13 @@ g_uri_split_network (const gchar *uri_string, } if (scheme) - *scheme = my_scheme; - else - g_free (my_scheme); + *scheme = g_steal_pointer (&my_scheme); if (host) - *host = my_host; - else - g_free (my_host); + *host = g_steal_pointer (&my_host); + + g_free (my_scheme); + g_free (my_host); + return TRUE; } @@ -1045,13 +1083,16 @@ g_uri_split_network (const gchar *uri_string, * @flags: flags for parsing @uri_string * @error: #GError for error reporting, or %NULL to ignore. * - * Parses @uri_string according to @flags, to determine whether it is valid - * absolute URI. + * Parses @uri_string according to @flags, to determine whether it is a valid + * [absolute URI][relative-absolute-uris], i.e. it does not need to be resolved + * relative to another URI using g_uri_parse_relative(). + * + * If it’s not a valid URI, an error is returned explaining how it’s invalid. * * See g_uri_split(), and the definition of #GUriFlags, for more * information on the effect of @flags. * - * Returns: %TRUE if @uri_string parsed successfully, %FALSE on error. + * Returns: %TRUE if @uri_string is a valid absolute URI, %FALSE on error. * * Since: 2.66 */ @@ -1060,15 +1101,35 @@ g_uri_is_valid (const gchar *uri_string, GUriFlags flags, GError **error) { + gchar *my_scheme = NULL; + g_return_val_if_fail (uri_string != NULL, FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - return g_uri_split_network (uri_string, flags, NULL, NULL, NULL, error); + if (!g_uri_split_internal (uri_string, flags, + &my_scheme, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, + error)) + return FALSE; + + if (!my_scheme) + { + g_set_error (error, G_URI_ERROR, G_URI_ERROR_BAD_SCHEME, + _("URI ‘%s’ is not an absolute URI"), + uri_string); + return FALSE; + } + + g_free (my_scheme); + + return TRUE; } /* This does the "Remove Dot Segments" algorithm from section 5.2.4 of * RFC 3986, except that @path is modified in place. + * + * See https://tools.ietf.org/html/rfc3986#section-5.2.4 */ static void remove_dot_segments (gchar *path) @@ -1136,7 +1197,8 @@ remove_dot_segments (gchar *path) * @error: #GError for error reporting, or %NULL to ignore. * * Parses @uri_string according to @flags. If the result is not a - * valid absolute URI, it will be discarded, and an error returned. + * valid [absolute URI][relative-absolute-uris], it will be discarded, and an + * error returned. * * Return value: (transfer full): a new #GUri. * @@ -1155,14 +1217,15 @@ g_uri_parse (const gchar *uri_string, /** * g_uri_parse_relative: - * @base_uri: (nullable): a base absolute URI + * @base_uri: (nullable) (transfer none): a base absolute URI * @uri_ref: a string representing a relative or absolute URI * @flags: flags describing how to parse @uri_ref * @error: #GError for error reporting, or %NULL to ignore. * - * Parses @uri_ref according to @flags and, if it is a relative - * URI, resolves it relative to @base_uri. If the result is not a - * valid absolute URI, it will be discarded, and an error returned. + * Parses @uri_ref according to @flags and, if it is a + * [relative URI][relative-absolute-uris], resolves it relative to @base_uri. + * If the result is not a valid absolute URI, it will be discarded, and an error + * returned. * * Return value: (transfer full): a new #GUri. * @@ -1195,7 +1258,7 @@ g_uri_parse_relative (GUri *base_uri, if (!uri->scheme && !base_uri) { - g_set_error_literal (error, G_URI_ERROR, G_URI_ERROR_MISC, + g_set_error_literal (error, G_URI_ERROR, G_URI_ERROR_FAILED, _("URI is not absolute, and no base URI was provided")); goto fail; } @@ -1204,6 +1267,8 @@ g_uri_parse_relative (GUri *base_uri, { /* This is section 5.2.2 of RFC 3986, except that we're doing * it in place in @uri rather than copying from R to T. + * + * See https://tools.ietf.org/html/rfc3986#section-5.2.2 */ if (uri->scheme) remove_dot_segments (uri->path); @@ -1241,7 +1306,7 @@ g_uri_parse_relative (GUri *base_uri, newpath = g_strdup_printf ("/%s", uri->path); g_free (uri->path); - uri->path = newpath; + uri->path = g_steal_pointer (&newpath); remove_dot_segments (uri->path); } @@ -1257,7 +1322,7 @@ g_uri_parse_relative (GUri *base_uri, } } - return uri; + return g_steal_pointer (&uri); fail: if (uri) @@ -1272,14 +1337,15 @@ g_uri_parse_relative (GUri *base_uri, * @flags: flags describing how to parse @uri_ref * @error: #GError for error reporting, or %NULL to ignore. * - * Parses @uri_ref according to @flags and, if it is a relative - * URI, resolves it relative to @base_uri_string. If the result is not - * a valid absolute URI, it will be discarded, and an error returned. + * Parses @uri_ref according to @flags and, if it is a + * [relative URI][relative-absolute-uris], resolves it relative to + * @base_uri_string. If the result is not a valid absolute URI, it will be + * discarded, and an error returned. * * (If @base_uri_string is %NULL, this just returns @uri_ref, or * %NULL if @uri_ref is invalid or not absolute.) * - * Return value: the resolved URI string. + * Return value: (transfer full): the resolved URI string. * * Since: 2.66 */ @@ -1314,7 +1380,7 @@ g_uri_resolve_relative (const gchar *base_uri_string, resolved_uri_string = g_uri_to_string (resolved_uri); g_uri_unref (resolved_uri); - return resolved_uri_string; + return g_steal_pointer (&resolved_uri_string); } /* userinfo as a whole can contain sub-delims + ":", but split-out @@ -1453,13 +1519,14 @@ g_uri_join_internal (GUriFlags flags, * @scheme: (nullable): the URI scheme, or %NULL * @userinfo: (nullable): the userinfo component, or %NULL * @host: (nullable): the host component, or %NULL - * @port: the port, or -1 - * @path: the path component + * @port: the port, or `-1` + * @path: (not nullable): the path component * @query: (nullable): the query component, or %NULL * @fragment: (nullable): the fragment, or %NULL * * Joins the given components together according to @flags to create - * an absolute URI string. @path may not be %NULL (though it may be ""). + * an absolute URI string. @path may not be %NULL (though it may be the empty + * string). * * When @host is present, @path must either be empty or begin with a slash (`/`) * character. When @host is not present, @path cannot begin with two slash @@ -1467,9 +1534,12 @@ g_uri_join_internal (GUriFlags flags, * [RFC 3986, section 3](https://tools.ietf.org/html/rfc3986#section-3). * * See also g_uri_join_with_user(), which allows specifying the - * components of the "userinfo" separately. + * components of the ‘userinfo’ separately. * - * Return value: an absolute URI string + * %G_URI_FLAGS_HAS_PASSWORD and %G_URI_FLAGS_HAS_AUTH_PARAMS are ignored if set + * in @flags. + * + * Return value: (transfer full): an absolute URI string * * Since: 2.66 */ @@ -1506,18 +1576,22 @@ g_uri_join (GUriFlags flags, * @auth_params: (nullable): the auth params of the userinfo, or * %NULL * @host: (nullable): the host component, or %NULL - * @port: the port, or -1 - * @path: the path component + * @port: the port, or `-1` + * @path: (not nullable): the path component * @query: (nullable): the query component, or %NULL * @fragment: (nullable): the fragment, or %NULL * * Joins the given components together according to @flags to create - * an absolute URI string. @path may not be %NULL (though it may be ""). + * an absolute URI string. @path may not be %NULL (though it may be the empty + * string). * * In contrast to g_uri_join(), this allows specifying the components - * of the "userinfo" separately. It otherwise behaves the same. + * of the ‘userinfo’ separately. It otherwise behaves the same. * - * Return value: an absolute URI string + * %G_URI_FLAGS_HAS_PASSWORD and %G_URI_FLAGS_HAS_AUTH_PARAMS are ignored if set + * in @flags. + * + * Return value: (transfer full): an absolute URI string * * Since: 2.66 */ @@ -1549,11 +1623,11 @@ g_uri_join_with_user (GUriFlags flags, /** * g_uri_build: * @flags: flags describing how to build the #GUri - * @scheme: the URI scheme + * @scheme: (not nullable): the URI scheme * @userinfo: (nullable): the userinfo component, or %NULL * @host: (nullable): the host component, or %NULL - * @port: the port, or -1 - * @path: the path component + * @port: the port, or `-1` + * @path: (not nullable): the path component * @query: (nullable): the query component, or %NULL * @fragment: (nullable): the fragment, or %NULL * @@ -1592,19 +1666,19 @@ g_uri_build (GUriFlags flags, uri->query = g_strdup (query); uri->fragment = g_strdup (fragment); - return uri; + return g_steal_pointer (&uri); } /** * g_uri_build_with_user: * @flags: flags describing how to build the #GUri - * @scheme: the URI scheme + * @scheme: (not nullable): the URI scheme * @user: (nullable): the user component of the userinfo, or %NULL * @password: (nullable): the password component of the userinfo, or %NULL * @auth_params: (nullable): the auth params of the userinfo, or %NULL * @host: (nullable): the host component, or %NULL - * @port: the port, or -1 - * @path: the path component + * @port: the port, or `-1` + * @path: (not nullable): the path component * @query: (nullable): the query component, or %NULL * @fragment: (nullable): the fragment, or %NULL * @@ -1612,9 +1686,9 @@ g_uri_build (GUriFlags flags, * (%G_URI_FLAGS_HAS_PASSWORD is added unconditionally). The @flags must be * coherent with the passed values, in particular use `%`-encoded values with * %G_URI_FLAGS_ENCODED. - + * * In contrast to g_uri_build(), this allows specifying the components - * of the "userinfo" field separately. Note that @user must be non-%NULL + * of the ‘userinfo’ field separately. Note that @user must be non-%NULL * if either @password or @auth_params is non-%NULL. * * Return value: (transfer full): a new #GUri @@ -1670,7 +1744,7 @@ g_uri_build_with_user (GUriFlags flags, uri->userinfo = g_string_free (userinfo, FALSE); } - return uri; + return g_steal_pointer (&uri); } /** @@ -1686,8 +1760,12 @@ g_uri_build_with_user (GUriFlags flags, * a string which is at least semantically equivalent to the source * URI (according to RFC 3986). * - * Return value: a string representing @uri, which the caller must - * free. + * If @uri might contain sensitive details, such as authentication parameters, + * or private data in its query string, and the returned string is going to be + * logged, then consider using g_uri_to_string_partial() to redact parts. + * + * Return value: (transfer full): a string representing @uri, which the caller + * must free. * * Since: 2.66 */ @@ -1696,7 +1774,7 @@ g_uri_to_string (GUri *uri) { g_return_val_if_fail (uri != NULL, NULL); - return g_uri_to_string_partial (uri, 0); + return g_uri_to_string_partial (uri, G_URI_HIDE_NONE); } /** @@ -1706,9 +1784,9 @@ g_uri_to_string (GUri *uri) * * Returns a string representing @uri, subject to the options in * @flags. See g_uri_to_string() and #GUriHideFlags for more details. - - * Return value: a string representing @uri, which the caller must - * free. + * + * Return value: (transfer full): a string representing @uri, which the caller + * must free. * * Since: 2.66 */ @@ -1719,6 +1797,7 @@ g_uri_to_string_partial (GUri *uri, gboolean hide_user = (flags & G_URI_HIDE_USERINFO); gboolean hide_password = (flags & (G_URI_HIDE_USERINFO | G_URI_HIDE_PASSWORD)); gboolean hide_auth_params = (flags & (G_URI_HIDE_USERINFO | G_URI_HIDE_AUTH_PARAMS)); + gboolean hide_query = (flags & G_URI_HIDE_QUERY); gboolean hide_fragment = (flags & G_URI_HIDE_FRAGMENT); g_return_val_if_fail (uri != NULL, NULL); @@ -1733,7 +1812,7 @@ g_uri_to_string_partial (GUri *uri, uri->host, uri->port, uri->path, - uri->query, + hide_query ? NULL : uri->query, hide_fragment ? NULL : uri->fragment); } @@ -1743,7 +1822,7 @@ g_uri_to_string_partial (GUri *uri, uri->host, uri->port, uri->path, - uri->query, + hide_query ? NULL : uri->query, hide_fragment ? NULL : uri->fragment); } @@ -1774,8 +1853,8 @@ str_ascii_case_equal (gconstpointer v1, * GUriParamsIter: * * Many URI schemes include one or more attribute/value pairs as part of the URI - * value (for example "scheme://server/path?query=string&is=there" has two - * attributes "query=string" and "is=there" in its query part). + * value. For example `scheme://server/path?query=string&is=there` has two + * attributes – `query=string` and `is=there` – in its query part. * * A #GUriParamsIter structure represents an iterator that can be used to * iterate over the attribute/value pairs of a URI query string. #GUriParamsIter @@ -1799,31 +1878,45 @@ G_STATIC_ASSERT (G_ALIGNOF (GUriParamsIter) >= G_ALIGNOF (RealIter)); /** * g_uri_params_iter_init: * @iter: an uninitialized #GUriParamsIter - * @params: a `%`-encoded string containing "attribute=value" + * @params: a `%`-encoded string containing `attribute=value` * parameters - * @length: the length of @params, or -1 if it is NUL-terminated + * @length: the length of @params, or `-1` if it is nul-terminated * @separators: the separator byte character set between parameters. (usually - * "&", but sometimes ";" or both "&;"). Note that this function works on + * `&`, but sometimes `;` or both `&;`). Note that this function works on * bytes not characters, so it can't be used to delimit UTF-8 strings for * anything but ASCII characters. You may pass an empty set, in which case * no splitting will occur. * @flags: flags to modify the way the parameters are handled. * - * Initializes an attribute/value pair iterator. The iterator keeps references - * over the @params and @separators arguments, those variables must thus outlive - * the iterator and not be modified during the iteration. + * Initializes an attribute/value pair iterator. + * + * The iterator keeps pointers to the @params and @separators arguments, those + * variables must thus outlive the iterator and not be modified during the + * iteration. + * + * If %G_URI_PARAMS_WWW_FORM is passed in @flags, `+` characters in the param + * string will be replaced with spaces in the output. For example, `foo=bar+baz` + * will give attribute `foo` with value `bar baz`. This is commonly used on the + * web (the `https` and `http` schemes only), but is deprecated in favour of + * the equivalent of encoding spaces as `%20`. + * + * Unlike with g_uri_parse_params(), %G_URI_PARAMS_CASE_INSENSITIVE has no + * effect if passed to @flags for g_uri_params_iter_init(). The caller is + * responsible for doing their own case-insensitive comparisons. * * |[ * GUriParamsIter iter; * GError *error = NULL; - * gchar *attr, *value; + * gchar *unowned_attr, *unowned_value; * - * g_uri_params_iter_init (&iter, "foo=bar&baz=bar", -1, "&", G_URI_PARAMS_NONE); - * while (g_uri_params_iter_next (&iter, &attr, &value, &error)) + * g_uri_params_iter_init (&iter, "foo=bar&baz=bar&Foo=frob&baz=bar2", -1, "&", G_URI_PARAMS_NONE); + * while (g_uri_params_iter_next (&iter, &unowned_attr, &unowned_value, &error)) * { - * // do something with attr and value - * g_free (attr); - * g_free (value); + * g_autofree gchar *attr = g_steal_pointer (&unowned_attr); + * g_autofree gchar *value = g_steal_pointer (&unowned_value); + * // do something with attr and value; this code will be called 4 times + * // for the params string in this example: once with attr=foo and value=bar, + * // then with baz/bar, then Foo/frob, then baz/bar2. * } * if (error) * // handle parsing error @@ -1869,13 +1962,18 @@ g_uri_params_iter_init (GUriParamsIter *iter, * the value, or %NULL. * @error: #GError for error reporting, or %NULL to ignore. * - * Advances @iter and retrieves the next attribute/value. If %FALSE is returned, - * @attribute and @value are not set, and the iterator becomes invalid. Note - * that the same attribute value may be returned multiple times, since URIs + * Advances @iter and retrieves the next attribute/value. %FALSE is returned if + * an error has occurred (in which case @error is set), or if the end of the + * iteration is reached (in which case @attribute and @value are set to %NULL + * and the iterator becomes invalid). If %TRUE is returned, + * g_uri_params_iter_next() may be called again to receive another + * attribute/value pair. + * + * Note that the same @attribute may be returned multiple times, since URIs * allow repeated attributes. * * Returns: %FALSE if the end of the parameters has been reached or an error was - * encountered. + * encountered. %TRUE otherwise. * * Since: 2.66 */ @@ -1889,13 +1987,23 @@ g_uri_params_iter_next (GUriParamsIter *iter, const gchar *attr_end, *val, *val_end; gchar *decoded_attr, *decoded_value; gboolean www_form = ri->flags & G_URI_PARAMS_WWW_FORM; + GUriFlags decode_flags = G_URI_FLAGS_NONE; g_return_val_if_fail (iter != NULL, FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + /* Pre-clear these in case of failure or finishing. */ + if (attribute) + *attribute = NULL; + if (value) + *value = NULL; + if (ri->attr >= ri->end) return FALSE; + if (ri->flags & G_URI_PARAMS_PARSE_RELAXED) + decode_flags |= G_URI_FLAGS_PARSE_RELAXED; + /* Check if each character in @attr is a separator, by indexing by the * character value into the @sep_table, which has value 1 stored at an * index if that index is a separator. */ @@ -1906,19 +2014,19 @@ g_uri_params_iter_next (GUriParamsIter *iter, attr_end = memchr (ri->attr, '=', val_end - ri->attr); if (!attr_end) { - g_set_error_literal (error, G_URI_ERROR, G_URI_ERROR_MISC, - _("Missing '=' and parameter value")); + g_set_error_literal (error, G_URI_ERROR, G_URI_ERROR_FAILED, + _("Missing ‘=’ and parameter value")); return FALSE; } if (!uri_decode (&decoded_attr, NULL, ri->attr, attr_end - ri->attr, - www_form, G_URI_FLAGS_NONE, G_URI_ERROR_MISC, error)) + www_form, decode_flags, G_URI_ERROR_FAILED, error)) { return FALSE; } val = attr_end + 1; if (!uri_decode (&decoded_value, NULL, val, val_end - val, - www_form, G_URI_FLAGS_NONE, G_URI_ERROR_MISC, error)) + www_form, decode_flags, G_URI_ERROR_FAILED, error)) { g_free (decoded_attr); return FALSE; @@ -1938,11 +2046,11 @@ g_uri_params_iter_next (GUriParamsIter *iter, /** * g_uri_parse_params: - * @params: a `%`-encoded string containing "attribute=value" + * @params: a `%`-encoded string containing `attribute=value` * parameters - * @length: the length of @params, or -1 if it is NUL-terminated + * @length: the length of @params, or `-1` if it is nul-terminated * @separators: the separator byte character set between parameters. (usually - * "&", but sometimes ";" or both "&;"). Note that this function works on + * `&`, but sometimes `;` or both `&;`). Note that this function works on * bytes not characters, so it can't be used to delimit UTF-8 strings for * anything but ASCII characters. You may pass an empty set, in which case * no splitting will occur. @@ -1957,17 +2065,26 @@ g_uri_params_iter_next (GUriParamsIter *iter, * * The @params string is assumed to still be `%`-encoded, but the returned * values will be fully decoded. (Thus it is possible that the returned values - * may contain '=' or @separators, if the value was encoded in the input.) - * Invalid `%`-encoding is treated as with the non-%G_URI_FLAGS_PARSE_STRICT + * may contain `=` or @separators, if the value was encoded in the input.) + * Invalid `%`-encoding is treated as with the %G_URI_FLAGS_PARSE_RELAXED * rules for g_uri_parse(). (However, if @params is the path or query string - * from a #GUri that was parsed with %G_URI_FLAGS_PARSE_STRICT and + * from a #GUri that was parsed without %G_URI_FLAGS_PARSE_RELAXED and * %G_URI_FLAGS_ENCODED, then you already know that it does not contain any * invalid encoding.) * - * Return value: (transfer full) (element-type utf8 utf8): a hash table of - * attribute/value pairs. Both names and values will be fully-decoded. If - * @params cannot be parsed (eg, it contains two @separators characters in a - * row), then %NULL is returned. + * %G_URI_PARAMS_WWW_FORM is handled as documented for g_uri_params_iter_init(). + * + * If %G_URI_PARAMS_CASE_INSENSITIVE is passed to @flags, attributes will be + * compared case-insensitively, so a params string `attr=123&Attr=456` will only + * return a single attribute–value pair, `Attr=456`. Case will be preserved in + * the returned attributes. + * + * If @params cannot be parsed (for example, it contains two @separators + * characters in a row), then @error is set and %NULL is returned. + * + * Return value: (transfer full) (element-type utf8 utf8): A hash table of + * attribute/value pairs, with both names and values fully-decoded; or %NULL + * on error. * * Since: 2.66 */ @@ -2012,7 +2129,7 @@ g_uri_parse_params (const gchar *params, return NULL; } - return hash; + return g_steal_pointer (&hash); } /** @@ -2022,7 +2139,7 @@ g_uri_parse_params (const gchar *params, * Gets @uri's scheme. Note that this will always be all-lowercase, * regardless of the string or strings that @uri was created from. * - * Return value: @uri's scheme. + * Return value: (not nullable): @uri's scheme. * * Since: 2.66 */ @@ -2041,7 +2158,7 @@ g_uri_get_scheme (GUri *uri) * Gets @uri's userinfo, which may contain `%`-encoding, depending on * the flags with which @uri was created. * - * Return value: @uri's userinfo. + * Return value: (nullable): @uri's userinfo. * * Since: 2.66 */ @@ -2057,12 +2174,12 @@ g_uri_get_userinfo (GUri *uri) * g_uri_get_user: * @uri: a #GUri * - * Gets the "username" component of @uri's userinfo, which may contain + * Gets the ‘username’ component of @uri's userinfo, which may contain * `%`-encoding, depending on the flags with which @uri was created. * If @uri was not created with %G_URI_FLAGS_HAS_PASSWORD or * %G_URI_FLAGS_HAS_AUTH_PARAMS, this is the same as g_uri_get_userinfo(). * - * Return value: @uri's user. + * Return value: (nullable): @uri's user. * * Since: 2.66 */ @@ -2082,7 +2199,7 @@ g_uri_get_user (GUri *uri) * the flags with which @uri was created. (If @uri was not created * with %G_URI_FLAGS_HAS_PASSWORD then this will be %NULL.) * - * Return value: @uri's password. + * Return value: (nullable): @uri's password. * * Since: 2.66 */ @@ -2106,7 +2223,7 @@ g_uri_get_password (GUri *uri) * Depending on the URI scheme, g_uri_parse_params() may be useful for * further parsing this information. * - * Return value: @uri's authentication parameters. + * Return value: (nullable): @uri's authentication parameters. * * Since: 2.66 */ @@ -2129,10 +2246,10 @@ g_uri_get_auth_params (GUri *uri) * If @uri contained an IPv6 address literal, this value will be just * that address, without the brackets around it that are necessary in * the string form of the URI. Note that in this case there may also - * be a scope ID attached to the address. Eg, "`fe80::1234%``em1`" (or - * "`fe80::1234%``25em1" if the string is still encoded). + * be a scope ID attached to the address. Eg, `fe80::1234%``em1` (or + * `fe80::1234%``25em1` if the string is still encoded). * - * Return value: @uri's host. + * Return value: (not nullable): @uri's host. * * Since: 2.66 */ @@ -2150,7 +2267,7 @@ g_uri_get_host (GUri *uri) * * Gets @uri's port. * - * Return value: @uri's port, or -1 if no port was specified. + * Return value: @uri's port, or `-1` if no port was specified. * * Since: 2.66 */ @@ -2169,7 +2286,7 @@ g_uri_get_port (GUri *uri) * Gets @uri's path, which may contain `%`-encoding, depending on the * flags with which @uri was created. * - * Return value: @uri's path. + * Return value: (not nullable): @uri's path. * * Since: 2.66 */ @@ -2188,10 +2305,10 @@ g_uri_get_path (GUri *uri) * Gets @uri's query, which may contain `%`-encoding, depending on the * flags with which @uri was created. * - * For queries consisting of a series of "`name=value`" parameters, - * g_uri_parse_params() may be useful. + * For queries consisting of a series of `name=value` parameters, + * #GUriParamsIter or g_uri_parse_params() may be useful. * - * Return value: @uri's query. + * Return value: (nullable): @uri's query. * * Since: 2.66 */ @@ -2210,7 +2327,7 @@ g_uri_get_query (GUri *uri) * Gets @uri's fragment, which may contain `%`-encoding, depending on * the flags with which @uri was created. * - * Return value: @uri's fragment. + * Return value: (nullable): @uri's fragment. * * Since: 2.66 */ @@ -2236,7 +2353,7 @@ g_uri_get_fragment (GUri *uri) GUriFlags g_uri_get_flags (GUri *uri) { - g_return_val_if_fail (uri != NULL, 0); + g_return_val_if_fail (uri != NULL, G_URI_FLAGS_NONE); return uri->flags; } @@ -2288,7 +2405,7 @@ g_uri_unescape_segment (const gchar *escaped_string, illegal_characters, escaped_string, length, FALSE, FALSE, - G_URI_FLAGS_PARSE_STRICT|G_URI_FLAGS_ENCODED, + G_URI_FLAGS_ENCODED, 0, NULL); if (decoded_len < 0) return NULL; @@ -2368,8 +2485,8 @@ g_uri_escape_string (const gchar *unescaped, /** * g_uri_unescape_bytes: * @escaped_string: A URI-escaped string - * @length: the length of @escaped_string to escape, or -1 if it - * is NUL-terminated. + * @length: the length (in bytes) of @escaped_string to escape, or `-1` if it + * is nul-terminated. * @illegal_characters: (nullable): a string of illegal characters * not to be allowed, or %NULL. * @error: #GError for error reporting, or %NULL to ignore. @@ -2377,17 +2494,17 @@ g_uri_escape_string (const gchar *unescaped, * Unescapes a segment of an escaped string as binary data. * * Note that in contrast to g_uri_unescape_string(), this does allow - * `NUL` bytes to appear in the output. + * nul bytes to appear in the output. * - * If any of the characters in @illegal_characters or the NUL - * character appears as an escaped character in @escaped_string, then - * that is an error and %NULL will be returned. This is useful if you - * want to avoid for instance having a slash being expanded in an - * escaped path element, which might confuse pathname handling. + * If any of the characters in @illegal_characters appears as an escaped + * character in @escaped_string, then that is an error and %NULL will be + * returned. This is useful if you want to avoid for instance having a slash + * being expanded in an escaped path element, which might confuse pathname + * handling. * * Returns: (transfer full): an unescaped version of @escaped_string or %NULL on - * error (if decoding failed, using %G_URI_ERROR_MISC error code). The returned - * #GBytes should be unreffed when no longer needed. + * error (if decoding failed, using %G_URI_ERROR_FAILED error code). The + * returned #GBytes should be unreffed when no longer needed. * * Since: 2.66 **/ @@ -2411,8 +2528,8 @@ g_uri_unescape_bytes (const gchar *escaped_string, escaped_string, length, FALSE, FALSE, - G_URI_FLAGS_PARSE_STRICT|G_URI_FLAGS_ENCODED, - G_URI_ERROR_MISC, error); + G_URI_FLAGS_ENCODED, + G_URI_ERROR_FAILED, error); if (unescaped_length == -1) return NULL; @@ -2428,23 +2545,23 @@ g_uri_unescape_bytes (const gchar *escaped_string, * * Escapes arbitrary data for use in a URI. * - * Normally all characters that are not "unreserved" (i.e. ASCII + * Normally all characters that are not ‘unreserved’ (i.e. ASCII * alphanumerical characters plus dash, dot, underscore and tilde) are * escaped. But if you specify characters in @reserved_chars_allowed - * they are not escaped. This is useful for the "reserved" characters + * they are not escaped. This is useful for the ‘reserved’ characters * in the URI specification, since those are allowed unescaped in some * portions of a URI. * - * Though technically incorrect, this will also allow escaping "0" - * bytes as "`%``00`". + * Though technically incorrect, this will also allow escaping nul + * bytes as `%``00`. * - * Returns: an escaped version of @unescaped. The returned string - * should be freed when no longer needed. + * Returns: (transfer full): an escaped version of @unescaped. The returned + * string should be freed when no longer needed. * * Since: 2.66 */ gchar * -g_uri_escape_bytes (const guchar *unescaped, +g_uri_escape_bytes (const guint8 *unescaped, gsize length, const gchar *reserved_chars_allowed) { @@ -2460,7 +2577,7 @@ g_uri_escape_bytes (const guchar *unescaped, return g_string_free (string, FALSE); } -static gint +static gssize g_uri_scheme_length (const gchar *uri) { const gchar *p; @@ -2482,21 +2599,23 @@ g_uri_scheme_length (const gchar *uri) * g_uri_parse_scheme: * @uri: a valid URI. * - * Gets the scheme portion of a URI string. RFC 3986 decodes the scheme as: + * Gets the scheme portion of a URI string. + * [RFC 3986](https://tools.ietf.org/html/rfc3986#section-3) decodes the scheme + * as: * |[ * URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ] * ]| - * Common schemes include "file", "http", "svn+ssh", etc. + * Common schemes include `file`, `https`, `svn+ssh`, etc. * - * Returns: The "scheme" component of the URI, or %NULL on error. - * The returned string should be freed when no longer needed. + * Returns: (transfer full) (nullable): The ‘scheme’ component of the URI, or + * %NULL on error. The returned string should be freed when no longer needed. * * Since: 2.16 **/ gchar * g_uri_parse_scheme (const gchar *uri) { - gint len; + gssize len; g_return_val_if_fail (uri != NULL, NULL); @@ -2508,22 +2627,27 @@ g_uri_parse_scheme (const gchar *uri) * g_uri_peek_scheme: * @uri: a valid URI. * - * Gets the scheme portion of a URI string. RFC 3986 decodes the scheme as: + * Gets the scheme portion of a URI string. + * [RFC 3986](https://tools.ietf.org/html/rfc3986#section-3) decodes the scheme + * as: * |[ * URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ] * ]| - * Common schemes include "file", "http", "svn+ssh", etc. + * Common schemes include `file`, `https`, `svn+ssh`, etc. * - * Returns: The "scheme" component of the URI, or %NULL on error. The - * returned string is normalized to all-lowercase, and interned via - * g_intern_string(), so it does not need to be freed. + * Unlike g_uri_parse_scheme(), the returned scheme is normalized to + * all-lowercase and does not need to be freed. + * + * Returns: (transfer none) (nullable): The ‘scheme’ component of the URI, or + * %NULL on error. The returned string is normalized to all-lowercase, and + * interned via g_intern_string(), so it does not need to be freed. * * Since: 2.66 **/ const gchar * g_uri_peek_scheme (const gchar *uri) { - gint len; + gssize len; gchar *lower_scheme; const gchar *scheme; diff --git a/glib/guri.h b/glib/guri.h index 59f6933c5..3a7bb5c0e 100644 --- a/glib/guri.h +++ b/glib/guri.h @@ -37,15 +37,19 @@ void g_uri_unref (GUri *uri); /** * GUriFlags: - * @G_URI_FLAGS_PARSE_STRICT: Parse the URI strictly according to the RFC - * 3986 grammar, rather than fixing up or ignoring common mistakes. + * @G_URI_FLAGS_NONE: No flags set. + * @G_URI_FLAGS_PARSE_RELAXED: Parse the URI more relaxedly than the + * [RFC 3986](https://tools.ietf.org/html/rfc3986) grammar specifies, + * fixing up or ignoring common mistakes in URIs coming from external + * sources. This is also needed for some obscure URI schemes where `;` + * separates the host from the path. Don’t use this flag unless you need to. * @G_URI_FLAGS_HAS_PASSWORD: The userinfo field may contain a password, - * which will be separated from the username by ':'. + * which will be separated from the username by `:`. * @G_URI_FLAGS_HAS_AUTH_PARAMS: The userinfo may contain additional * authentication-related parameters, which will be separated from - * the username and/or password by ';'. + * the username and/or password by `;`. * @G_URI_FLAGS_NON_DNS: The host component should not be assumed to be a - * DNS hostname or IP address. (Eg, for `smb` URIs with NetBIOS + * DNS hostname or IP address (for example, for `smb` URIs with NetBIOS * hostnames). * @G_URI_FLAGS_ENCODED: When parsing a URI, this indicates that `%`-encoded * characters in the userinfo, path, query, and fragment fields @@ -58,7 +62,6 @@ void g_uri_unref (GUri *uri); * @G_URI_FLAGS_ENCODED_PATH: Same as %G_URI_FLAGS_ENCODED, for the path only. * @G_URI_FLAGS_ENCODED_FRAGMENT: Same as %G_URI_FLAGS_ENCODED, for the * fragment only. - * @G_URI_FLAGS_NONE: No flags set. * * Flags that describe a URI. * @@ -72,7 +75,7 @@ void g_uri_unref (GUri *uri); GLIB_AVAILABLE_TYPE_IN_2_66 typedef enum { G_URI_FLAGS_NONE = 0, - G_URI_FLAGS_PARSE_STRICT = 1 << 0, + G_URI_FLAGS_PARSE_RELAXED = 1 << 0, G_URI_FLAGS_HAS_PASSWORD = 1 << 1, G_URI_FLAGS_HAS_AUTH_PARAMS = 1 << 2, G_URI_FLAGS_ENCODED = 1 << 3, @@ -179,11 +182,12 @@ GUri * g_uri_build_with_user (GUriFlags flags, /** * GUriHideFlags: + * @G_URI_HIDE_NONE: No flags set. * @G_URI_HIDE_USERINFO: Hide the userinfo. * @G_URI_HIDE_PASSWORD: Hide the password. * @G_URI_HIDE_AUTH_PARAMS: Hide the auth_params. + * @G_URI_HIDE_QUERY: Hide the query. * @G_URI_HIDE_FRAGMENT: Hide the fragment. - * @G_URI_HIDE_NONE: No flags set. * * Flags describing what parts of the URI to hide in * g_uri_to_string_partial(). Note that %G_URI_HIDE_PASSWORD and @@ -198,7 +202,8 @@ typedef enum { G_URI_HIDE_USERINFO = 1 << 0, G_URI_HIDE_PASSWORD = 1 << 1, G_URI_HIDE_AUTH_PARAMS = 1 << 2, - G_URI_HIDE_FRAGMENT = 1 << 3, + G_URI_HIDE_QUERY = 1 << 3, + G_URI_HIDE_FRAGMENT = 1 << 4, } GUriHideFlags; GLIB_AVAILABLE_IN_2_66 @@ -233,10 +238,13 @@ GUriFlags g_uri_get_flags (GUri *uri); /** * GUriParamsFlags: * @G_URI_PARAMS_NONE: No flags set. - * @G_URI_PARAMS_CASE_INSENSITIVE: whether parameter names are case insensitive. - * @G_URI_PARAMS_WWW_FORM: replace `+` with space character. + * @G_URI_PARAMS_CASE_INSENSITIVE: Parameter names are case insensitive. + * @G_URI_PARAMS_WWW_FORM: Replace `+` with space character. Only useful for + * URLs on the web, using the `https` or `http` schemas. + * @G_URI_PARAMS_PARSE_RELAXED: See %G_URI_FLAGS_PARSE_RELAXED. * - * Flags modifying the way parameters are handled. + * Flags modifying the way parameters are handled by g_uri_parse_params() and + * #GUriParamsIter. * * Since: 2.66 */ @@ -245,6 +253,7 @@ typedef enum { G_URI_PARAMS_NONE = 0, G_URI_PARAMS_CASE_INSENSITIVE = 1 << 0, G_URI_PARAMS_WWW_FORM = 1 << 1, + G_URI_PARAMS_PARSE_RELAXED = 1 << 2, } GUriParamsFlags; GLIB_AVAILABLE_IN_2_66 @@ -277,6 +286,7 @@ gboolean g_uri_params_iter_next (GUriParamsIter *iter, gchar **attribute, gchar **value, GError **error); + /** * G_URI_ERROR: * @@ -292,23 +302,24 @@ GQuark g_uri_error_quark (void); /** * GUriError: - * @G_URI_ERROR_MISC: miscellaneous error - * @G_URI_ERROR_BAD_SCHEME: the scheme of a URI could not be parsed. - * @G_URI_ERROR_BAD_USER: the user/userinfo of a URI could not be parsed. - * @G_URI_ERROR_BAD_PASSWORD: the password of a URI could not be parsed. - * @G_URI_ERROR_BAD_AUTH_PARAMS: the authentication parameters of a URI could not be parsed. - * @G_URI_ERROR_BAD_HOST: the host of a URI could not be parsed. - * @G_URI_ERROR_BAD_PORT: the port of a URI could not be parsed. - * @G_URI_ERROR_BAD_PATH: the path of a URI could not be parsed. - * @G_URI_ERROR_BAD_QUERY: the query of a URI could not be parsed. - * @G_URI_ERROR_BAD_FRAGMENT: the fragment of a URI could not be parsed. + * @G_URI_ERROR_FAILED: Generic error if no more specific error is available. + * See the error message for details. + * @G_URI_ERROR_BAD_SCHEME: The scheme of a URI could not be parsed. + * @G_URI_ERROR_BAD_USER: The user/userinfo of a URI could not be parsed. + * @G_URI_ERROR_BAD_PASSWORD: The password of a URI could not be parsed. + * @G_URI_ERROR_BAD_AUTH_PARAMS: The authentication parameters of a URI could not be parsed. + * @G_URI_ERROR_BAD_HOST: The host of a URI could not be parsed. + * @G_URI_ERROR_BAD_PORT: The port of a URI could not be parsed. + * @G_URI_ERROR_BAD_PATH: The path of a URI could not be parsed. + * @G_URI_ERROR_BAD_QUERY: The query of a URI could not be parsed. + * @G_URI_ERROR_BAD_FRAGMENT: The fragment of a URI could not be parsed. * * Error codes returned by #GUri methods. * * Since: 2.66 */ typedef enum { - G_URI_ERROR_MISC, + G_URI_ERROR_FAILED, G_URI_ERROR_BAD_SCHEME, G_URI_ERROR_BAD_USER, G_URI_ERROR_BAD_PASSWORD, @@ -323,7 +334,8 @@ typedef enum { /** * G_URI_RESERVED_CHARS_GENERIC_DELIMITERS: * - * Generic delimiters characters as defined in RFC 3986. Includes ":/?#[]@". + * Generic delimiters characters as defined in + * [RFC 3986](https://tools.ietf.org/html/rfc3986). Includes `:/?#[]@`. * * Since: 2.16 **/ @@ -332,7 +344,8 @@ typedef enum { /** * G_URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS: * - * Subcomponent delimiter characters as defined in RFC 3986. Includes "!$&'()*+,;=". + * Subcomponent delimiter characters as defined in + * [RFC 3986](https://tools.ietf.org/html/rfc3986). Includes `!$&'()*+,;=`. * * Since: 2.16 **/ @@ -341,7 +354,7 @@ typedef enum { /** * G_URI_RESERVED_CHARS_ALLOWED_IN_PATH_ELEMENT: * - * Allowed characters in path elements. Includes "!$&'()*+,;=:@". + * Allowed characters in path elements. Includes `!$&'()*+,;=:@`. * * Since: 2.16 **/ @@ -350,7 +363,7 @@ typedef enum { /** * G_URI_RESERVED_CHARS_ALLOWED_IN_PATH: * - * Allowed characters in a path. Includes "!$&'()*+,;=:@/". + * Allowed characters in a path. Includes `!$&'()*+,;=:@/`. * * Since: 2.16 **/ @@ -359,7 +372,8 @@ typedef enum { /** * G_URI_RESERVED_CHARS_ALLOWED_IN_USERINFO: * - * Allowed characters in userinfo as defined in RFC 3986. Includes "!$&'()*+,;=:". + * Allowed characters in userinfo as defined in + * [RFC 3986](https://tools.ietf.org/html/rfc3986). Includes `!$&'()*+,;=:`. * * Since: 2.16 **/ @@ -390,7 +404,7 @@ GBytes * g_uri_unescape_bytes (const char *escaped_string, GError **error); GLIB_AVAILABLE_IN_2_66 -char * g_uri_escape_bytes (const guchar *unescaped, +char * g_uri_escape_bytes (const guint8 *unescaped, gsize length, const char *reserved_chars_allowed); diff --git a/glib/tests/uri.c b/glib/tests/uri.c index 1e8b66c93..adaa4066a 100644 --- a/glib/tests/uri.c +++ b/glib/tests/uri.c @@ -417,7 +417,7 @@ test_uri_unescape_bytes (gconstpointer test_data) if (tests[i].expected_unescaped_len < 0) { g_assert_null (bytes); - g_assert_error (error, G_URI_ERROR, G_URI_ERROR_MISC); + g_assert_error (error, G_URI_ERROR, G_URI_ERROR_FAILED); g_clear_error (&error); } else @@ -443,6 +443,9 @@ test_uri_unescape_segment (void) s = g_uri_unescape_segment (escaped_segment, escaped_segment + 10, NULL); g_assert_cmpstr (s, ==, "+abc O"); g_free (s); + + s = g_uri_unescape_segment ("%2Babc%00cde", NULL, NULL); + g_assert_null (s); } static void @@ -478,6 +481,10 @@ test_uri_scheme (void) g_assert_cmpstr (s, ==, "ftp"); g_free (s); + s = g_uri_parse_scheme ("good-scheme.but+weird:gtk.org"); + g_assert_cmpstr (s, ==, "good-scheme.but+weird"); + g_free (s); + s = g_uri_parse_scheme ("1bad:"); g_assert_null (s); s = g_uri_parse_scheme ("bad"); @@ -512,201 +519,202 @@ typedef struct { typedef struct { const gchar *orig; + GUriFlags flags; const UriParts parts; } UriAbsoluteTest; static const UriAbsoluteTest absolute_tests[] = { - { "foo:", + { "foo:", G_URI_FLAGS_NONE, { "foo", NULL, NULL, -1, "", NULL, NULL } }, - { "file:/dev/null", + { "file:/dev/null", G_URI_FLAGS_NONE, { "file", NULL, NULL, -1, "/dev/null", NULL, NULL } }, - { "file:///dev/null", + { "file:///dev/null", G_URI_FLAGS_NONE, { "file", NULL, "", -1, "/dev/null", NULL, NULL } }, - { "ftp://user@host/path", + { "ftp://user@host/path", G_URI_FLAGS_NONE, { "ftp", "user", "host", -1, "/path", NULL, NULL } }, - { "ftp://user@host:9999/path", + { "ftp://user@host:9999/path", G_URI_FLAGS_NONE, { "ftp", "user", "host", 9999, "/path", NULL, NULL } }, - { "ftp://user:password@host/path", + { "ftp://user:password@host/path", G_URI_FLAGS_NONE, { "ftp", "user:password", "host", -1, "/path", NULL, NULL } }, - { "ftp://user:password@host:9999/path", + { "ftp://user:password@host:9999/path", G_URI_FLAGS_NONE, { "ftp", "user:password", "host", 9999, "/path", NULL, NULL } }, - { "ftp://user:password@host", + { "ftp://user:password@host", G_URI_FLAGS_NONE, { "ftp", "user:password", "host", -1, "", NULL, NULL } }, - { "http://us%65r@host", + { "http://us%65r@host", G_URI_FLAGS_NONE, { "http", "user", "host", -1, "", NULL, NULL } }, - { "http://us%40r@host", + { "http://us%40r@host", G_URI_FLAGS_NONE, { "http", "us@r", "host", -1, "", NULL, NULL } }, - { "http://us%3ar@host", + { "http://us%3ar@host", G_URI_FLAGS_NONE, { "http", "us:r", "host", -1, "", NULL, NULL } }, - { "http://us%2fr@host", + { "http://us%2fr@host", G_URI_FLAGS_NONE, { "http", "us/r", "host", -1, "", NULL, NULL } }, - { "http://us%3fr@host", + { "http://us%3fr@host", G_URI_FLAGS_NONE, { "http", "us?r", "host", -1, "", NULL, NULL } }, - { "http://host?query", + { "http://host?query", G_URI_FLAGS_NONE, { "http", NULL, "host", -1, "", "query", NULL } }, - { "http://host/path?query=http%3A%2F%2Fhost%2Fpath%3Fchildparam%3Dchildvalue¶m=value", + { "http://host/path?query=http%3A%2F%2Fhost%2Fpath%3Fchildparam%3Dchildvalue¶m=value", G_URI_FLAGS_NONE, { "http", NULL, "host", -1, "/path", "query=http://host/path?childparam=childvalue¶m=value", NULL } }, - { "http://control-chars/%01%02%03%04%05%06%07%08%09%0A%0B%0C%0D%0E%0F%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F%7F", + { "http://control-chars/%01%02%03%04%05%06%07%08%09%0A%0B%0C%0D%0E%0F%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F%7F", G_URI_FLAGS_NONE, { "http", NULL, "control-chars", -1, "/\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x7F", NULL, NULL } }, - { "http://space/%20", + { "http://space/%20", G_URI_FLAGS_NONE, { "http", NULL, "space", -1, "/ ", NULL, NULL } }, - { "http://delims/%3C%3E%23%25%22", + { "http://delims/%3C%3E%23%25%22", G_URI_FLAGS_NONE, { "http", NULL, "delims", -1, "/<>#%\"", NULL, NULL } }, - { "http://unwise-chars/%7B%7D%7C%5C%5E%5B%5D%60", + { "http://unwise-chars/%7B%7D%7C%5C%5E%5B%5D%60", G_URI_FLAGS_NONE, { "http", NULL, "unwise-chars", -1, "/{}|\\^[]`", NULL, NULL } }, /* From RFC 2732 */ - { "http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html", + { "http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html", G_URI_FLAGS_NONE, { "http", NULL, "FEDC:BA98:7654:3210:FEDC:BA98:7654:3210", 80, "/index.html", NULL, NULL } }, - { "http://[1080:0:0:0:8:800:200C:417A]/index.html", + { "http://[1080:0:0:0:8:800:200C:417A]/index.html", G_URI_FLAGS_NONE, { "http", NULL, "1080:0:0:0:8:800:200C:417A", -1, "/index.html", NULL, NULL } }, - { "http://[3ffe:2a00:100:7031::1]", + { "http://[3ffe:2a00:100:7031::1]", G_URI_FLAGS_NONE, { "http", NULL, "3ffe:2a00:100:7031::1", -1, "", NULL, NULL } }, - { "http://[1080::8:800:200C:417A]/foo", + { "http://[1080::8:800:200C:417A]/foo", G_URI_FLAGS_NONE, { "http", NULL, "1080::8:800:200C:417A", -1, "/foo", NULL, NULL } }, - { "http://[::192.9.5.5]/ipng", + { "http://[::192.9.5.5]/ipng", G_URI_FLAGS_NONE, { "http", NULL, "::192.9.5.5", -1, "/ipng", NULL, NULL } }, - { "http://[::FFFF:129.144.52.38]:80/index.html", + { "http://[::FFFF:129.144.52.38]:80/index.html", G_URI_FLAGS_NONE, { "http", NULL, "::FFFF:129.144.52.38", 80, "/index.html", NULL, NULL } }, - { "http://[2010:836B:4179::836B:4179]", + { "http://[2010:836B:4179::836B:4179]", G_URI_FLAGS_NONE, { "http", NULL, "2010:836B:4179::836B:4179", -1, "", NULL, NULL } }, /* some problematic URIs that are handled differently in libsoup */ - { "http://host/path with spaces", + { "http://host/path with spaces", G_URI_FLAGS_PARSE_RELAXED, { "http", NULL, "host", -1, "/path with spaces", NULL, NULL } }, - { " http://host/path", + { " http://host/path", G_URI_FLAGS_PARSE_RELAXED, { "http", NULL, "host", -1, "/path", NULL, NULL } }, - { "http://host/path ", + { "http://host/path ", G_URI_FLAGS_PARSE_RELAXED, { "http", NULL, "host", -1, "/path", NULL, NULL } }, - { "http://host ", + { "http://host ", G_URI_FLAGS_PARSE_RELAXED, { "http", NULL, "host", -1, "", NULL, NULL } }, - { "http://host:999 ", + { "http://host:999 ", G_URI_FLAGS_PARSE_RELAXED, { "http", NULL, "host", 999, "", NULL, NULL } }, - { "http://host/pa\nth", + { "http://host/pa\nth", G_URI_FLAGS_PARSE_RELAXED, { "http", NULL, "host", -1, "/path", NULL, NULL } }, - { "http:\r\n//host/path", + { "http:\r\n//host/path", G_URI_FLAGS_PARSE_RELAXED, { "http", NULL, "host", -1, "/path", NULL, NULL } }, - { "http://\thost/path", + { "http://\thost/path", G_URI_FLAGS_PARSE_RELAXED, { "http", NULL, "host", -1, "/path", NULL, NULL } }, /* Bug 594405; 0-length is different from not-present */ - { "http://host/path?", + { "http://host/path?", G_URI_FLAGS_NONE, { "http", NULL, "host", -1, "/path", "", NULL } }, - { "http://host/path#", + { "http://host/path#", G_URI_FLAGS_NONE, { "http", NULL, "host", -1, "/path", NULL, "" }, }, /* Bug 590524; ignore bad %-encoding */ - { "http://host/path%", + { "http://host/path%", G_URI_FLAGS_PARSE_RELAXED, { "http", NULL, "host", -1, "/path%", NULL, NULL } }, - { "http://h%ost/path", + { "http://h%ost/path", G_URI_FLAGS_PARSE_RELAXED, { "http", NULL, "h%ost", -1, "/path", NULL, NULL } }, - { "http://host/path%%", + { "http://host/path%%", G_URI_FLAGS_PARSE_RELAXED, { "http", NULL, "host", -1, "/path%%", NULL, NULL } }, - { "http://host/path%%%", + { "http://host/path%%%", G_URI_FLAGS_PARSE_RELAXED, { "http", NULL, "host", -1, "/path%%%", NULL, NULL } }, - { "http://host/path%/x/", + { "http://host/path%/x/", G_URI_FLAGS_PARSE_RELAXED, { "http", NULL, "host", -1, "/path%/x/", NULL, NULL } }, - { "http://host/path%0x/", + { "http://host/path%0x/", G_URI_FLAGS_PARSE_RELAXED, { "http", NULL, "host", -1, "/path%0x/", NULL, NULL } }, - { "http://host/path%ax", + { "http://host/path%ax", G_URI_FLAGS_PARSE_RELAXED, { "http", NULL, "host", -1, "/path%ax", NULL, NULL } }, /* GUri doesn't %-encode non-ASCII characters */ - { "http://host/p\xc3\xa4th/", + { "http://host/p\xc3\xa4th/", G_URI_FLAGS_NONE, { "http", NULL, "host", -1, "/p\xc3\xa4th/", NULL, NULL } }, - { "HTTP:////////////////", + { "HTTP:////////////////", G_URI_FLAGS_NONE, { "http", NULL, "", -1, "//////////////", NULL, NULL } }, - { "http://@host", + { "http://@host", G_URI_FLAGS_NONE, { "http", "", "host", -1, "", NULL, NULL } }, - { "http://:@host", + { "http://:@host", G_URI_FLAGS_NONE, { "http", ":", "host", -1, "", NULL, NULL } }, - { "scheme://foo%3Abar._webdav._tcp.local", + { "scheme://foo%3Abar._webdav._tcp.local", G_URI_FLAGS_NONE, { "scheme", NULL, "foo:bar._webdav._tcp.local", -1, "", NULL, NULL} }, /* IPv6 scope ID parsing (both correct and incorrect) */ - { "http://[fe80::dead:beef%em1]/", + { "http://[fe80::dead:beef%em1]/", G_URI_FLAGS_NONE, { "http", NULL, "fe80::dead:beef%em1", -1, "/", NULL, NULL } }, - { "http://[fe80::dead:beef%25em1]/", + { "http://[fe80::dead:beef%25em1]/", G_URI_FLAGS_NONE, { "http", NULL, "fe80::dead:beef%em1", -1, "/", NULL, NULL } }, - { "http://[fe80::dead:beef%10]/", + { "http://[fe80::dead:beef%10]/", G_URI_FLAGS_NONE, { "http", NULL, "fe80::dead:beef%10", -1, "/", NULL, NULL } }, /* ".." past top */ - { "http://example.com/..", + { "http://example.com/..", G_URI_FLAGS_NONE, { "http", NULL, "example.com", -1, "/..", NULL, NULL } }, /* scheme parsing */ - { "foo0://host/path", + { "foo0://host/path", G_URI_FLAGS_NONE, { "foo0", NULL, "host", -1, "/path", NULL, NULL } }, - { "f0.o://host/path", + { "f0.o://host/path", G_URI_FLAGS_NONE, { "f0.o", NULL, "host", -1, "/path", NULL, NULL } }, - { "http++://host/path", + { "http++://host/path", G_URI_FLAGS_NONE, { "http++", NULL, "host", -1, "/path", NULL, NULL } }, - { "http-ish://host/path", + { "http-ish://host/path", G_URI_FLAGS_NONE, { "http-ish", NULL, "host", -1, "/path", NULL, NULL } }, /* IPv6 scope ID parsing (both correct and incorrect) */ - { "http://[fe80::dead:beef%em1]/", + { "http://[fe80::dead:beef%em1]/", G_URI_FLAGS_NONE, { "http", NULL, "fe80::dead:beef%em1", -1, "/", NULL, NULL } }, - { "http://[fe80::dead:beef%25em1]/", + { "http://[fe80::dead:beef%25em1]/", G_URI_FLAGS_NONE, { "http", NULL, "fe80::dead:beef%em1", -1, "/", NULL, NULL } }, - { "http://[fe80::dead:beef%10]/", + { "http://[fe80::dead:beef%10]/", G_URI_FLAGS_NONE, { "http", NULL, "fe80::dead:beef%10", -1, "/", NULL, NULL } }, - { "http://[fe80::dead:beef%25]/", + { "http://[fe80::dead:beef%25]/", G_URI_FLAGS_NONE, { "http", NULL, "fe80::dead:beef%25", -1, "/", NULL, NULL } }, }; static int num_absolute_tests = G_N_ELEMENTS (absolute_tests); @@ -722,7 +730,9 @@ test_uri_parsing_absolute (void) GError *error = NULL; GUri *uri; - uri = g_uri_parse (test->orig, G_URI_FLAGS_NONE, &error); + g_test_message ("Test %d: %s", i, test->orig); + + uri = g_uri_parse (test->orig, test->flags, &error); g_assert_no_error (error); g_assert_cmpstr (g_uri_get_scheme (uri), ==, test->parts.scheme); @@ -872,7 +882,7 @@ test_uri_parsing_relative (void) g_assert_cmpstr (resolved, ==, test->resolved); g_free (resolved); } - uri = g_uri_parse_relative (base, "%%", G_URI_FLAGS_PARSE_STRICT, &error); + uri = g_uri_parse_relative (base, "%%", G_URI_FLAGS_NONE, &error); g_assert_null (uri); g_assert_error (error, G_URI_ERROR, G_URI_ERROR_BAD_PATH); g_clear_error (&error); @@ -891,17 +901,17 @@ test_uri_parsing_relative (void) resolved = g_uri_resolve_relative (NULL, "a", G_URI_FLAGS_NONE, &error); g_assert_null (resolved); - g_assert_error (error, G_URI_ERROR, G_URI_ERROR_MISC); + g_assert_error (error, G_URI_ERROR, G_URI_ERROR_FAILED); g_clear_error (&error); resolved = g_uri_resolve_relative ("../b", "a", G_URI_FLAGS_NONE, &error); g_assert_null (resolved); - g_assert_error (error, G_URI_ERROR, G_URI_ERROR_MISC); + g_assert_error (error, G_URI_ERROR, G_URI_ERROR_FAILED); g_clear_error (&error); - resolved = g_uri_resolve_relative ("%%", "a", G_URI_FLAGS_NONE, &error); + resolved = g_uri_resolve_relative ("%%", "a", G_URI_FLAGS_PARSE_RELAXED, &error); g_assert_null (resolved); - g_assert_error (error, G_URI_ERROR, G_URI_ERROR_MISC); + g_assert_error (error, G_URI_ERROR, G_URI_ERROR_FAILED); g_clear_error (&error); } @@ -933,6 +943,9 @@ test_uri_to_string (void) tostring = g_uri_to_string_partial (uri, G_URI_HIDE_USERINFO); g_assert_cmpstr (tostring, ==, "scheme://host:1234/path?query#fragment"); g_free (tostring); + tostring = g_uri_to_string_partial (uri, G_URI_HIDE_QUERY); + g_assert_cmpstr (tostring, ==, "scheme://user:pass;auth@host:1234/path#fragment"); + g_free (tostring); tostring = g_uri_to_string_partial (uri, G_URI_HIDE_FRAGMENT); g_assert_cmpstr (tostring, ==, "scheme://user:pass;auth@host:1234/path?query"); g_free (tostring); @@ -950,6 +963,9 @@ test_uri_to_string (void) tostring = g_uri_to_string_partial (uri, G_URI_HIDE_AUTH_PARAMS); g_assert_cmpstr (tostring, ==, "scheme://us%3Aer:pass@host:1234/path?query#fragment"); g_free (tostring); + tostring = g_uri_to_string_partial (uri, G_URI_HIDE_QUERY); + g_assert_cmpstr (tostring, ==, "scheme://us%3Aer:pass;auth@host:1234/path#fragment"); + g_free (tostring); g_uri_unref (uri); } @@ -1011,6 +1027,12 @@ test_uri_build (void) "/path", "query", "fragment"); g_assert_null (g_uri_get_userinfo (uri)); g_uri_unref (uri); + + uri = g_uri_build_with_user (G_URI_FLAGS_NONE, "scheme", "user", NULL, NULL, + "host", 1234, + "/path", "query", "fragment"); + g_assert_cmpstr (g_uri_get_userinfo (uri), ==, "user"); + g_uri_unref (uri); } static void @@ -1068,7 +1090,7 @@ test_uri_split (void) g_free (host); g_uri_split ("scheme://@@@host:1234/path?query#fragment", - G_URI_FLAGS_ENCODED, + G_URI_FLAGS_ENCODED | G_URI_FLAGS_PARSE_RELAXED, NULL, &userinfo, NULL, @@ -1083,7 +1105,7 @@ test_uri_split (void) g_uri_split ("http://f;oo/", - G_URI_FLAGS_NONE, + G_URI_FLAGS_NONE | G_URI_FLAGS_PARSE_RELAXED, NULL, NULL, NULL, @@ -1263,7 +1285,7 @@ test_uri_split (void) g_clear_error (&error); g_uri_split_with_user ("scheme://user:pa%x0s;auth@host:1234/path?query#fragment", - G_URI_FLAGS_HAS_PASSWORD|G_URI_FLAGS_PARSE_STRICT, + G_URI_FLAGS_HAS_PASSWORD, &scheme, &user, &pass, @@ -1310,8 +1332,8 @@ test_uri_is_valid (void) g_assert_true (g_uri_is_valid ("http://127.127.127.b/", G_URI_FLAGS_NONE, NULL)); g_assert_true (g_uri_is_valid ("http://\xc3\x89XAMPLE.COM/", G_URI_FLAGS_NONE, NULL)); - g_assert_true (g_uri_is_valid (" \r http\t://f oo \t\n ", G_URI_FLAGS_NONE, NULL)); - g_assert_false (g_uri_is_valid (" \r http\t://f oo \t\n ", G_URI_FLAGS_PARSE_STRICT, &error)); + g_assert_true (g_uri_is_valid (" \r http\t://f oo \t\n ", G_URI_FLAGS_PARSE_RELAXED, NULL)); + g_assert_false (g_uri_is_valid (" \r http\t://f oo \t\n ", G_URI_FLAGS_NONE, &error)); g_assert_error (error, G_URI_ERROR, G_URI_ERROR_BAD_SCHEME); g_clear_error (&error); @@ -1349,6 +1371,8 @@ test_uri_is_valid (void) g_assert_false (g_uri_is_valid ("http://host:6553l", G_URI_FLAGS_NONE, &error)); g_assert_error (error, G_URI_ERROR, G_URI_ERROR_BAD_PORT); g_clear_error (&error); + + g_assert_true (g_uri_is_valid ("data:,Hello", G_URI_FLAGS_NONE, &error)); } static const struct @@ -1386,7 +1410,7 @@ static const struct { "p1=foo&P1=bar", "&", G_URI_PARAMS_CASE_INSENSITIVE, 2, { "p1", "foo", "P1", "bar" }, 1, { "p1", "bar", NULL, }}, - { "=%", "&", G_URI_PARAMS_NONE, + { "=%", "&", G_URI_PARAMS_PARSE_RELAXED, 1, { "", "%", NULL, }, 1, { "", "%", NULL, }}, { "=", "&", G_URI_PARAMS_NONE, @@ -1436,6 +1460,19 @@ test_uri_iter_params (gconstpointer test_data) uri = g_memdup (params_tests[i].uri, uri_len); } + /* Run once without extracting the attr or value, just to check the numbers. */ + n = 0; + g_uri_params_iter_init (&iter, params_tests[i].uri, -1, params_tests[i].separators, params_tests[i].flags); + while (g_uri_params_iter_next (&iter, NULL, NULL, &err)) + n++; + g_assert_cmpint (n, ==, params_tests[i].expected_n_iter); + if (err) + { + g_assert_error (err, G_URI_ERROR, G_URI_ERROR_FAILED); + g_clear_error (&err); + } + + /* Run again and check the strings too. */ n = 0; g_uri_params_iter_init (&iter, params_tests[i].uri, -1, params_tests[i].separators, params_tests[i].flags); while (g_uri_params_iter_next (&iter, &attr, &value, &err)) @@ -1449,9 +1486,10 @@ test_uri_iter_params (gconstpointer test_data) g_assert_cmpint (n, ==, params_tests[i].expected_n_iter); if (err) { - g_assert_error (err, G_URI_ERROR, G_URI_ERROR_MISC); + g_assert_error (err, G_URI_ERROR, G_URI_ERROR_FAILED); g_clear_error (&err); } + g_free (uri); } } @@ -1494,7 +1532,7 @@ test_uri_parse_params (gconstpointer test_data) if (params_tests[i].expected_n_params < 0) { g_assert_null (params); - g_assert_error (err, G_URI_ERROR, G_URI_ERROR_MISC); + g_assert_error (err, G_URI_ERROR, G_URI_ERROR_FAILED); g_clear_error (&err); } else