From 7bee36b4fff561c623ff74d49de57631b974a8ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Thu, 2 Jul 2020 16:16:27 +0400 Subject: [PATCH] uri: add G_FLAGS_ENCODED_QUERY MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A query string may have some '=' characters '%'-encoded that could be split by g_uri_parse_params() incorrectly. Instead, callers should leave the query part encoded, and let g_uri_parse_params() do the decoding. Signed-off-by: Marc-André Lureau --- glib/guri.c | 10 +++++++--- glib/guri.h | 3 +++ glib/tests/uri.c | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/glib/guri.c b/glib/guri.c index 1d7ad57a9..e34cbd9d9 100644 --- a/glib/guri.c +++ b/glib/guri.c @@ -148,7 +148,10 @@ * g_assert_error(err, G_URI_ERROR, G_URI_ERROR_BAD_QUERY); * ]| * - * (you should pass %G_URI_FLAGS_ENCODED if you need to handle that case manually). + * 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 + * g_uri_parse_params() do the decoding once of the query. * * #GUri is immutable once constructed, and can safely be accessed from * multiple threads. Its reference counting is atomic. @@ -784,7 +787,8 @@ g_uri_split_internal (const gchar *uri_string, question = memchr (p, '?', end - p); if (question) { - if (!uri_normalize (query, question + 1, end - (question + 1), flags, + if (!uri_normalize (query, question + 1, end - (question + 1), + flags | (flags & G_URI_FLAGS_ENCODED_QUERY ? G_URI_FLAGS_ENCODED : 0), G_URI_ERROR_BAD_QUERY, error)) goto fail; end = question; @@ -1399,7 +1403,7 @@ g_uri_join_internal (GUriFlags flags, if (query) { g_string_append_c (str, '?'); - if (encoded) + if (encoded || flags & G_URI_FLAGS_ENCODED_QUERY) g_string_append (str, query); else g_string_append_uri_escaped (str, query, QUERY_ALLOWED_CHARS, TRUE); diff --git a/glib/guri.h b/glib/guri.h index b9f49792e..4ceb04df4 100644 --- a/glib/guri.h +++ b/glib/guri.h @@ -53,6 +53,8 @@ void g_uri_unref (GUri *uri); * %G_URI_FLAGS_NON_DNS is also set.) When building a URI, it indicates * that you have already `%`-encoded the components, and so #GUri * should not do any encoding itself. + * @G_URI_FLAGS_ENCODED_QUERY: Same as %G_URI_FLAGS_ENCODED, for the query + * field only. * @G_URI_FLAGS_NONE: No flags set. * * Flags that describe a URI. @@ -72,6 +74,7 @@ typedef enum { G_URI_FLAGS_HAS_AUTH_PARAMS = 1 << 2, G_URI_FLAGS_ENCODED = 1 << 3, G_URI_FLAGS_NON_DNS = 1 << 4, + G_URI_FLAGS_ENCODED_QUERY = 1 << 5, } GUriFlags; GLIB_AVAILABLE_IN_2_66 diff --git a/glib/tests/uri.c b/glib/tests/uri.c index fd131a6fb..c25fd7607 100644 --- a/glib/tests/uri.c +++ b/glib/tests/uri.c @@ -1070,6 +1070,38 @@ test_uri_split (void) g_assert_cmpstr (path, ==, ";oo/"); g_free (path); + g_uri_split ("http://h%01st/path?saisons=%C3%89t%C3%A9%2Bhiver", + G_URI_FLAGS_NONE, + NULL, + NULL, + &host, + NULL, + NULL, + &query, + NULL, + &error); + g_assert_no_error (error); + g_assert_cmpstr (host, ==, "h\001st"); + g_assert_cmpstr (query, ==, "saisons=Été+hiver"); + g_free (host); + g_free (query); + + g_uri_split ("http://h%01st/path?saisons=%C3%89t%C3%A9%2Bhiver", + G_URI_FLAGS_ENCODED_QUERY, + NULL, + NULL, + &host, + NULL, + NULL, + &query, + NULL, + &error); + g_assert_no_error (error); + g_assert_cmpstr (host, ==, "h\001st"); + g_assert_cmpstr (query, ==, "saisons=%C3%89t%C3%A9%2Bhiver"); + g_free (host); + g_free (query); + g_uri_split_with_user ("scheme://user:pass;auth@host:1234/path?query#fragment", G_URI_FLAGS_HAS_AUTH_PARAMS|G_URI_FLAGS_HAS_PASSWORD, NULL,