From ff60d2ebf542104ab82e47c71f9bd7c5f767f0a4 Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Thu, 6 Aug 2020 13:53:31 +0100 Subject: [PATCH 01/14] guri: Various minor documentation tweaks and improvements Signed-off-by: Philip Withnall --- glib/guri.c | 380 ++++++++++++++++++++++++++++++++-------------------- glib/guri.h | 57 ++++---- 2 files changed, 267 insertions(+), 170 deletions(-) diff --git a/glib/guri.c b/glib/guri.c index 87dcc6441..3f1297685 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 @@ -847,9 +884,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 +894,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 +951,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 +961,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 +1010,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, @@ -1045,13 +1082,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 */ @@ -1136,7 +1176,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 +1196,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. * @@ -1272,14 +1314,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 */ @@ -1453,13 +1496,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 +1511,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 +1553,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 +1600,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 * @@ -1598,13 +1649,13 @@ g_uri_build (GUriFlags flags, /** * 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 +1663,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 @@ -1686,8 +1737,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 */ @@ -1706,9 +1761,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 */ @@ -1774,8 +1829,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 +1854,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 +1938,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 */ @@ -1938,11 +2012,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 +2031,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.) + * 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 * 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 * %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 */ @@ -2022,7 +2105,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 +2124,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 +2140,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 +2165,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 +2189,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 +2212,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 +2233,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 +2252,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 +2271,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 +2293,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 */ @@ -2368,8 +2451,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 +2460,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 **/ @@ -2428,18 +2511,18 @@ 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 */ @@ -2482,14 +2565,16 @@ 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 **/ @@ -2508,15 +2593,20 @@ 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 **/ diff --git a/glib/guri.h b/glib/guri.h index 59f6933c5..9cbbb5b8f 100644 --- a/glib/guri.h +++ b/glib/guri.h @@ -37,15 +37,17 @@ 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_STRICT: Parse the URI strictly according to the + * [RFC 3986](https://tools.ietf.org/html/rfc3986) grammar, rather than + * fixing up or ignoring common mistakes. * @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 +60,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. * @@ -179,11 +180,11 @@ 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_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 @@ -233,10 +234,12 @@ 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. * - * Flags modifying the way parameters are handled. + * Flags modifying the way parameters are handled by g_uri_parse_params() and + * #GUriParamsIter. * * Since: 2.66 */ @@ -292,16 +295,17 @@ 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_MISC: 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. * @@ -323,7 +327,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 +337,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 +347,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 +356,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 +365,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 **/ From 1f1efbbb05160af9709943fb387aa3bf76a7cfce Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Thu, 6 Aug 2020 13:57:06 +0100 Subject: [PATCH 02/14] guri: Rename G_URI_ERROR_MISC to G_URI_ERROR_FAILED MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This brings its naming in line with the ‘generic’ error codes in other error domains. This is not an API break since `GUriError` hasn’t been in a release yet. Signed-off-by: Philip Withnall --- glib/guri.c | 10 +++++----- glib/guri.h | 4 ++-- glib/tests/uri.c | 12 ++++++------ 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/glib/guri.c b/glib/guri.c index 3f1297685..bf2775ff1 100644 --- a/glib/guri.c +++ b/glib/guri.c @@ -1237,7 +1237,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; } @@ -1980,19 +1980,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, + 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, G_URI_FLAGS_NONE, 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, G_URI_FLAGS_NONE, G_URI_ERROR_FAILED, error)) { g_free (decoded_attr); return FALSE; @@ -2495,7 +2495,7 @@ g_uri_unescape_bytes (const gchar *escaped_string, FALSE, FALSE, G_URI_FLAGS_PARSE_STRICT|G_URI_FLAGS_ENCODED, - G_URI_ERROR_MISC, error); + G_URI_ERROR_FAILED, error); if (unescaped_length == -1) return NULL; diff --git a/glib/guri.h b/glib/guri.h index 9cbbb5b8f..0fc48a17f 100644 --- a/glib/guri.h +++ b/glib/guri.h @@ -295,7 +295,7 @@ GQuark g_uri_error_quark (void); /** * GUriError: - * @G_URI_ERROR_MISC: Generic error if no more specific error is available. + * @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. @@ -312,7 +312,7 @@ GQuark g_uri_error_quark (void); * 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, diff --git a/glib/tests/uri.c b/glib/tests/uri.c index 1e8b66c93..71e3150ff 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 @@ -891,17 +891,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); 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); } @@ -1449,7 +1449,7 @@ 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 +1494,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 From de0ebf8a5f54769157da8fa46365211fc7d1eb24 Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Thu, 6 Aug 2020 13:58:33 +0100 Subject: [PATCH 03/14] guri: Minor code formatting fixes Signed-off-by: Philip Withnall --- glib/guri.c | 5 +++-- glib/guri.h | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/glib/guri.c b/glib/guri.c index bf2775ff1..fa7d622a1 100644 --- a/glib/guri.c +++ b/glib/guri.c @@ -234,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); @@ -308,7 +309,7 @@ uri_decoder (gchar **out, if (flags & G_URI_FLAGS_PARSE_STRICT) { 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; diff --git a/glib/guri.h b/glib/guri.h index 0fc48a17f..832bf5d3d 100644 --- a/glib/guri.h +++ b/glib/guri.h @@ -280,6 +280,7 @@ gboolean g_uri_params_iter_next (GUriParamsIter *iter, gchar **attribute, gchar **value, GError **error); + /** * G_URI_ERROR: * From 40873f845227a4a127657c6524b7e497fa5ab4d2 Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Thu, 6 Aug 2020 13:59:24 +0100 Subject: [PATCH 04/14] guri: Use g_steal_pointer() to make ownership transfer clearer This introduces no functional changes, just makes the code a bit easier to read. Signed-off-by: Philip Withnall --- glib/guri.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/glib/guri.c b/glib/guri.c index fa7d622a1..bcb16e83d 100644 --- a/glib/guri.c +++ b/glib/guri.c @@ -1035,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); @@ -1067,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; } @@ -1284,7 +1284,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); } @@ -1300,7 +1300,7 @@ g_uri_parse_relative (GUri *base_uri, } } - return uri; + return g_steal_pointer (&uri); fail: if (uri) @@ -1358,7 +1358,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 @@ -1644,7 +1644,7 @@ g_uri_build (GUriFlags flags, uri->query = g_strdup (query); uri->fragment = g_strdup (fragment); - return uri; + return g_steal_pointer (&uri); } /** @@ -1722,7 +1722,7 @@ g_uri_build_with_user (GUriFlags flags, uri->userinfo = g_string_free (userinfo, FALSE); } - return uri; + return g_steal_pointer (&uri); } /** @@ -2096,7 +2096,7 @@ g_uri_parse_params (const gchar *params, return NULL; } - return hash; + return g_steal_pointer (&hash); } /** From ae6a0ef8b8cf27cbdaf6a36524364045e8c9defa Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Thu, 6 Aug 2020 14:01:26 +0100 Subject: [PATCH 05/14] guri: Tweak quotes in error strings Use nice curly Unicode quotes. Signed-off-by: Philip Withnall --- glib/guri.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/glib/guri.c b/glib/guri.c index bcb16e83d..9f575f8b1 100644 --- a/glib/guri.c +++ b/glib/guri.c @@ -458,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; } @@ -520,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; } @@ -554,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; } @@ -566,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; } @@ -1051,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); @@ -1982,7 +1982,7 @@ g_uri_params_iter_next (GUriParamsIter *iter, if (!attr_end) { g_set_error_literal (error, G_URI_ERROR, G_URI_ERROR_FAILED, - _("Missing '=' and parameter value")); + _("Missing ‘=’ and parameter value")); return FALSE; } if (!uri_decode (&decoded_attr, NULL, ri->attr, attr_end - ri->attr, From f873b88f8966a9b476f6b87145a04cd870e30ad3 Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Thu, 6 Aug 2020 14:02:21 +0100 Subject: [PATCH 06/14] guri: Add G_URI_HIDE_QUERY Sometimes there are sensitive details in URI query components, so we should provide the option for hiding them too. Signed-off-by: Philip Withnall --- glib/guri.c | 5 +++-- glib/guri.h | 4 +++- glib/tests/uri.c | 3 +++ 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/glib/guri.c b/glib/guri.c index 9f575f8b1..c7edf137b 100644 --- a/glib/guri.c +++ b/glib/guri.c @@ -1775,6 +1775,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); @@ -1789,7 +1790,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); } @@ -1799,7 +1800,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); } diff --git a/glib/guri.h b/glib/guri.h index 832bf5d3d..a85fd9e4b 100644 --- a/glib/guri.h +++ b/glib/guri.h @@ -184,6 +184,7 @@ GUri * g_uri_build_with_user (GUriFlags flags, * @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. * * Flags describing what parts of the URI to hide in @@ -199,7 +200,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 diff --git a/glib/tests/uri.c b/glib/tests/uri.c index 71e3150ff..85d2eb19d 100644 --- a/glib/tests/uri.c +++ b/glib/tests/uri.c @@ -950,6 +950,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); } From 41a21c35660da18e905dd2c7a6a489a19cd12681 Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Thu, 6 Aug 2020 14:02:51 +0100 Subject: [PATCH 07/14] guri: Add links to RFC 3986 in code comments This should make the RFC easier to refer to in future. Signed-off-by: Philip Withnall --- glib/guri.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/glib/guri.c b/glib/guri.c index c7edf137b..62e8bbf49 100644 --- a/glib/guri.c +++ b/glib/guri.c @@ -1110,6 +1110,8 @@ g_uri_is_valid (const gchar *uri_string, /* 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) @@ -1247,6 +1249,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); From 83597b9e579b3e3b5d897be32b8e3b18720b74c3 Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Thu, 6 Aug 2020 14:03:27 +0100 Subject: [PATCH 08/14] guri: Use NONE values of flags rather than 0 This introduces no functional changes, but makes the code a little easier to read. Signed-off-by: Philip Withnall --- glib/guri.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/glib/guri.c b/glib/guri.c index 62e8bbf49..f0944a050 100644 --- a/glib/guri.c +++ b/glib/guri.c @@ -1756,7 +1756,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); } /** @@ -2325,7 +2325,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; } From ceda9755dea78a74422aac06fdf3d83ea151dd46 Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Thu, 6 Aug 2020 14:03:54 +0100 Subject: [PATCH 09/14] guri: Clear return values on error from g_uri_params_iter_next() This reduces the chance of the caller accidentally double-freeing or use-after-free-ing something. Signed-off-by: Philip Withnall --- glib/guri.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/glib/guri.c b/glib/guri.c index f0944a050..905130255 100644 --- a/glib/guri.c +++ b/glib/guri.c @@ -1973,6 +1973,12 @@ g_uri_params_iter_next (GUriParamsIter *iter, 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; From e446c3487b6027203fbebcdfdd6dd8564bfbd5f7 Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Thu, 6 Aug 2020 14:04:38 +0100 Subject: [PATCH 10/14] guri: Change type of g_uri_escape_bytes() to use guint8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `guint8` is the conventional way in modern GLib APIs to represent ‘a byte which could contain arbitrary binary’. `guchar` is not advised for that (even though it’s equivalent) because it could be misread as `gchar`. Signed-off-by: Philip Withnall --- glib/guri.c | 2 +- glib/guri.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/glib/guri.c b/glib/guri.c index 905130255..ec8658e68 100644 --- a/glib/guri.c +++ b/glib/guri.c @@ -2539,7 +2539,7 @@ g_uri_unescape_bytes (const gchar *escaped_string, * 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) { diff --git a/glib/guri.h b/glib/guri.h index a85fd9e4b..c5c74704f 100644 --- a/glib/guri.h +++ b/glib/guri.h @@ -400,7 +400,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); From b5c59cc3fc030080acc16c7f54e03cdb3e85a052 Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Thu, 6 Aug 2020 14:05:40 +0100 Subject: [PATCH 11/14] guri: Use gssize for array/string lengths This reduces the possibility for overflow, and makes the code a little more conventional to read. Signed-off-by: Philip Withnall --- glib/guri.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/glib/guri.c b/glib/guri.c index ec8658e68..508fd69e4 100644 --- a/glib/guri.c +++ b/glib/guri.c @@ -2555,7 +2555,7 @@ g_uri_escape_bytes (const guint8 *unescaped, return g_string_free (string, FALSE); } -static gint +static gssize g_uri_scheme_length (const gchar *uri) { const gchar *p; @@ -2593,7 +2593,7 @@ g_uri_scheme_length (const gchar *uri) gchar * g_uri_parse_scheme (const gchar *uri) { - gint len; + gssize len; g_return_val_if_fail (uri != NULL, NULL); @@ -2625,7 +2625,7 @@ g_uri_parse_scheme (const gchar *uri) const gchar * g_uri_peek_scheme (const gchar *uri) { - gint len; + gssize len; gchar *lower_scheme; const gchar *scheme; From 943b1e45ab3134e9028f7eb3c89b13de84f7ebf4 Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Thu, 6 Aug 2020 15:03:18 +0100 Subject: [PATCH 12/14] =?UTF-8?q?guri:=20Don=E2=80=99t=20fail=20g=5Furi=5F?= =?UTF-8?q?is=5Fvalid()=20if=20URI=20is=20missing=20a=20hostname?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to my reading of https://tools.ietf.org/html/rfc3986#section-4, the only requirement for a URI to be ‘absolute’ (actually, not a relative reference) is for the scheme to be specified. A hostname doesn’t have to be specified: see any of the options in the `hier-part` production in https://tools.ietf.org/html/rfc3986#appendix-A which don’t include `authority`. Signed-off-by: Philip Withnall --- glib/guri.c | 20 +++++++++++++++++++- glib/tests/uri.c | 2 ++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/glib/guri.c b/glib/guri.c index 508fd69e4..bcbce6021 100644 --- a/glib/guri.c +++ b/glib/guri.c @@ -1101,10 +1101,28 @@ 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; } diff --git a/glib/tests/uri.c b/glib/tests/uri.c index 85d2eb19d..cb765ea3c 100644 --- a/glib/tests/uri.c +++ b/glib/tests/uri.c @@ -1352,6 +1352,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 From b654eb1846aaccf54805f836f654e9f3e8be63df Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Thu, 6 Aug 2020 15:14:26 +0100 Subject: [PATCH 13/14] guri: Make G_URI_FLAGS_PARSE_STRICT the default Make `G_URI_FLAGS_PARSE_RELAXED` available instead, for the implementations which need to handle user-provided or incorrect URIs. The default should nudge people towards being compliant with RFC 3986. This required also adding a new `G_URI_PARAMS_PARSE_RELAXED` flag, as previously parsing param strings *always* used relaxed mode and there was no way to control it. Now it defaults to using strict mode, and the new flag allows for relaxed mode to be enabled if needed. Signed-off-by: Philip Withnall Fixes: #2149 --- fuzzing/fuzz_uri_parse.c | 2 +- gio/gnetworkaddress.c | 2 +- gio/gproxyresolver.c | 4 +- gio/gsimpleproxyresolver.c | 2 +- glib/guri.c | 24 ++++--- glib/guri.h | 12 ++-- glib/tests/uri.c | 141 +++++++++++++++++++------------------ 7 files changed, 99 insertions(+), 88 deletions(-) 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 bcbce6021..bead318e5 100644 --- a/glib/guri.c +++ b/glib/guri.c @@ -306,7 +306,7 @@ 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 */ @@ -710,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; @@ -745,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; @@ -780,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) @@ -1987,6 +1987,7 @@ 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); @@ -2000,6 +2001,9 @@ g_uri_params_iter_next (GUriParamsIter *iter, 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. */ @@ -2015,14 +2019,14 @@ g_uri_params_iter_next (GUriParamsIter *iter, return FALSE; } if (!uri_decode (&decoded_attr, NULL, ri->attr, attr_end - ri->attr, - www_form, G_URI_FLAGS_NONE, G_URI_ERROR_FAILED, 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_FAILED, error)) + www_form, decode_flags, G_URI_ERROR_FAILED, error)) { g_free (decoded_attr); return FALSE; @@ -2062,9 +2066,9 @@ 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 + * 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.) * @@ -2401,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; @@ -2524,7 +2528,7 @@ g_uri_unescape_bytes (const gchar *escaped_string, escaped_string, length, FALSE, FALSE, - G_URI_FLAGS_PARSE_STRICT|G_URI_FLAGS_ENCODED, + G_URI_FLAGS_ENCODED, G_URI_ERROR_FAILED, error); if (unescaped_length == -1) return NULL; diff --git a/glib/guri.h b/glib/guri.h index c5c74704f..3a7bb5c0e 100644 --- a/glib/guri.h +++ b/glib/guri.h @@ -38,9 +38,11 @@ void g_uri_unref (GUri *uri); /** * GUriFlags: * @G_URI_FLAGS_NONE: No flags set. - * @G_URI_FLAGS_PARSE_STRICT: Parse the URI strictly according to the - * [RFC 3986](https://tools.ietf.org/html/rfc3986) grammar, rather than - * fixing up or ignoring common mistakes. + * @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 `:`. * @G_URI_FLAGS_HAS_AUTH_PARAMS: The userinfo may contain additional @@ -73,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, @@ -239,6 +241,7 @@ GUriFlags g_uri_get_flags (GUri *uri); * @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 by g_uri_parse_params() and * #GUriParamsIter. @@ -250,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 diff --git a/glib/tests/uri.c b/glib/tests/uri.c index cb765ea3c..8c99bc127 100644 --- a/glib/tests/uri.c +++ b/glib/tests/uri.c @@ -512,201 +512,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 +723,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 +875,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); @@ -899,7 +902,7 @@ test_uri_parsing_relative (void) 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_FAILED); g_clear_error (&error); @@ -1071,7 +1074,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, @@ -1086,7 +1089,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, @@ -1266,7 +1269,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, @@ -1313,8 +1316,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); @@ -1391,7 +1394,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, From cacf9c292688006e072566a0de2f2fd87e242dcd Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Thu, 6 Aug 2020 15:56:08 +0100 Subject: [PATCH 14/14] guri: Add various small new tests to increase branch coverage Nothing particularly interesting or major. Signed-off-by: Philip Withnall --- glib/tests/uri.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/glib/tests/uri.c b/glib/tests/uri.c index 8c99bc127..adaa4066a 100644 --- a/glib/tests/uri.c +++ b/glib/tests/uri.c @@ -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"); @@ -936,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); @@ -1017,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 @@ -1444,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)) @@ -1460,6 +1489,7 @@ test_uri_iter_params (gconstpointer test_data) g_assert_error (err, G_URI_ERROR, G_URI_ERROR_FAILED); g_clear_error (&err); } + g_free (uri); } }