[glib: 1/2] guri: Always prepend `//` to the host when building a URI




commit 623cb10f550f05d2e74acc8b7297735ee9709cd5
Author: Philip Withnall <withnall endlessm com>
Date:   Fri Aug 7 12:43:58 2020 +0100

    guri: Always prepend `//` to the host when building a URI
    
    This is needed to distinguish the host (‘authority’ in the terms of RFC
    3986) from a path if a scheme is not present.
    
    It can be seen from the grammar in RFC 3986
    (https://tools.ietf.org/html/rfc3986#appendix-A) that `authority` only
    ever appears after `"//"`.
    
    Spotted by Simon McVittie in
    https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1606#note_884893.
    
    Signed-off-by: Philip Withnall <withnall endlessm com>

 glib/guri.c      |  3 +--
 glib/tests/uri.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 74 insertions(+), 2 deletions(-)
---
diff --git a/glib/guri.c b/glib/guri.c
index ee10a23eb..d99fa8ead 100644
--- a/glib/guri.c
+++ b/glib/guri.c
@@ -1353,8 +1353,7 @@ g_uri_join_internal (GUriFlags    flags,
 
   if (host)
     {
-      if (scheme)
-        g_string_append (str, "//");
+      g_string_append (str, "//");
 
       if (user)
         {
diff --git a/glib/tests/uri.c b/glib/tests/uri.c
index 982040888..1e8b66c93 100644
--- a/glib/tests/uri.c
+++ b/glib/tests/uri.c
@@ -1527,6 +1527,10 @@ test_uri_join (void)
   g_assert_cmpstr (uri, ==, "/foo?abc");
   g_free (uri);
 
+  uri = g_uri_join (G_URI_FLAGS_NONE, NULL, NULL, "hostname", -1, "/foo", "abc", NULL);
+  g_assert_cmpstr (uri, ==, "//hostname/foo?abc");
+  g_free (uri);
+
   uri = g_uri_join_with_user (G_URI_FLAGS_NONE, "scheme", "user\001", "pass\002", "authparams\003",
                               "host", 9876, "/path", "query", "fragment");
   g_assert_cmpstr (uri, ==, "scheme://user%01:pass%02;authparams%03@host:9876/path?query#fragment");
@@ -1549,6 +1553,74 @@ test_uri_join (void)
   g_free (uri);
 }
 
+static void
+test_uri_join_split_round_trip (void)
+{
+  GUriFlags flags = G_URI_FLAGS_HAS_PASSWORD | G_URI_FLAGS_HAS_AUTH_PARAMS;
+  guint i;
+
+  g_test_summary ("Test that joining different URI components survives a round trip");
+
+  /* Each bit in @i indicates whether the corresponding URI field should be set
+   * or %NULL. */
+  for (i = 0; i < (1 << 8); i++)
+    {
+      gchar *uri = NULL;
+      const gchar *scheme, *user, *password, *auth_params, *host, *path, *query, *fragment;
+      gint port;
+      gchar *scheme_out = NULL, *user_out = NULL, *password_out = NULL;
+      gchar *auth_params_out = NULL, *host_out = NULL, *path_out = NULL;
+      gchar *query_out = NULL, *fragment_out = NULL;
+      gint port_out = -1;
+      gboolean split_success;
+      GError *local_error = NULL;
+
+      g_test_message ("Combination %u", i);
+
+      scheme = (i & (1 << 8)) ? "scheme" : NULL;
+      host = (i & (1 << 4)) ? "host" : NULL;
+      user = (host != NULL && i & (1 << 7)) ? "user" : NULL;  /* only supported if host is also set */
+      password = (host != NULL && user != NULL && i & (1 << 6)) ? "password" : NULL;  /* only supported if 
host and user are also set */
+      auth_params = (host != NULL && user != NULL && i & (1 << 5)) ? "auth_params" : NULL;  /* only 
supported if host and user are also set */
+      port = (host != NULL && i & (1 << 3)) ? 123 : -1;  /* only supported if host is also set */
+      path = (i & (1 << 2)) ? "/path" : "";  /* the only mandatory component */
+      query = (i & (1 << 1)) ? "query" : NULL;
+      fragment = (i & (1 << 0)) ? "fragment" : NULL;
+
+      uri = g_uri_join_with_user (flags, scheme, user, password, auth_params,
+                                  host, port, path, query, fragment);
+      g_assert_nonnull (uri);
+
+      split_success = g_uri_split_with_user (uri, flags, &scheme_out, &user_out,
+                                             &password_out, &auth_params_out,
+                                             &host_out, &port_out, &path_out,
+                                             &query_out, &fragment_out,
+                                             &local_error);
+      g_assert_no_error (local_error);
+      g_assert_true (split_success);
+
+      g_assert_cmpstr (scheme, ==, scheme_out);
+      g_assert_cmpstr (user, ==, user_out);
+      g_assert_cmpstr (password, ==, password_out);
+      g_assert_cmpstr (auth_params, ==, auth_params_out);
+      g_assert_cmpstr (host, ==, host_out);
+      g_assert_cmpint (port, ==, port_out);
+      g_assert_cmpstr (path, ==, path_out);
+      g_assert_cmpstr (query, ==, query_out);
+      g_assert_cmpstr (fragment, ==, fragment_out);
+
+      g_free (uri);
+      g_free (scheme_out);
+      g_free (user_out);
+      g_free (password_out);
+      g_free (auth_params_out);
+      g_free (host_out);
+      g_free (path_out);
+      g_free (query_out);
+      g_free (fragment_out);
+    }
+}
+
 int
 main (int   argc,
       char *argv[])
@@ -1572,6 +1644,7 @@ main (int   argc,
   g_test_add_func ("/uri/is_valid", test_uri_is_valid);
   g_test_add_func ("/uri/to-string", test_uri_to_string);
   g_test_add_func ("/uri/join", test_uri_join);
+  g_test_add_func ("/uri/join-split-round-trip", test_uri_join_split_round_trip);
   g_test_add_data_func ("/uri/iter-params/nul-terminated", GINT_TO_POINTER (TRUE), test_uri_iter_params);
   g_test_add_data_func ("/uri/iter-params/length", GINT_TO_POINTER (FALSE), test_uri_iter_params);
   g_test_add_data_func ("/uri/parse-params/nul-terminated", GINT_TO_POINTER (TRUE), test_uri_parse_params);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]