g_uri_build() does not split userinfo with G_URI_FLAGS_HAS_PASSWORD
A code snippet to demonstrate the issue:
#include <stdio.h>
#include <glib.h>
int main() {
GUri *uri, *uri2, *uri3;
const char *uris = "http://foouser:barpw@foo.com/bar/baz";
uri = g_uri_parse(uris, G_URI_FLAGS_ENCODED | G_URI_FLAGS_HAS_PASSWORD, NULL);
uri2 = g_uri_build(
g_uri_get_flags(uri), g_uri_get_scheme(uri), g_uri_get_userinfo(uri),
g_uri_get_host(uri), -1,g_uri_get_path(uri), g_uri_get_query(uri),
g_uri_get_fragment(uri)
);
uri3 = g_uri_build_with_user(
g_uri_get_flags(uri), g_uri_get_scheme(uri), g_uri_get_user(uri),
g_uri_get_password(uri), g_uri_get_auth_params(uri), g_uri_get_host(uri),
-1, g_uri_get_path(uri), g_uri_get_query(uri), g_uri_get_fragment(uri)
);
printf("%s\n", g_uri_to_string(uri)); // http://foouser:barpw@foo.com/bar/baz
printf("%s\n", g_uri_to_string(uri2)); // http://foo.com/bar/baz
printf("%s\n", g_uri_get_userinfo(uri2)); // foouser:barpw
printf("%s\n", g_uri_to_string(uri3)); // http://foouser:barpw@foo.com/bar/baz
}
Basically, the GUri
internally contains separate fields for password
and user
in addition to the combined userinfo
; when building the URI with g_uri_build
, the given userinfo
is not split (i.e. the password and user are not filled), so when using g_uri_build
with G_URI_FLAGS_HAS_PASSWORD
and similar, the userinfo
will be ignored when serializing the URIs.
You can see the serialize behavior here: https://gitlab.gnome.org/GNOME/glib/-/blob/main/glib/guri.c#L2025
If G_URI_FLAGS_HAS_PASSWORD
or G_URI_FLAGS_HAS_AUTH_PARAMS
is used, the user
and password
fields are used unconditionally. However, g_uri_build
does not split the given userinfo
: https://gitlab.gnome.org/GNOME/glib/-/blob/main/glib/guri.c#L1864
The g_uri_build_with_user
API on the other hand takes the given user, password and auth params and combines them: https://gitlab.gnome.org/GNOME/glib/-/blob/main/glib/guri.c#L1951
This basically means that using G_URI_FLAGS_HAS_PASSWORD
and similar with plain g_uri_build
is always unsafe, even when non-null userinfo
is passed. The documentation does not say anything about this, and I would say it's not the intuitive behavior users of the API would generally expect.