gnetworkaddress: allow IPv6 scope ids in URIs
authorDan Winship <danw@gnome.org>
Mon, 19 Aug 2013 16:14:27 +0000 (12:14 -0400)
committerDan Winship <danw@gnome.org>
Mon, 19 Aug 2013 16:15:36 +0000 (12:15 -0400)
GNetworkAddress was allowing IPv6 scope ids in g_network_address_new()
/ g_network_address_parse(), but not in g_network_address_parse_uri().
Fix that.

Part of https://bugzilla.gnome.org/show_bug.cgi?id=669724

gio/gnetworkaddress.c
gio/tests/inet-address.c
gio/tests/network-address.c

index 394a21a..9586ffa 100644 (file)
@@ -561,6 +561,8 @@ _g_uri_parse_authority (const char  *uri,
   /* If IPv6 or IPvFuture */
   if (*p == '[')
     {
+      gboolean has_scope_id = FALSE, has_bad_scope_id = FALSE;
+
       start++;
       p++;
       while (1)
@@ -570,6 +572,14 @@ _g_uri_parse_authority (const char  *uri,
          if (c == ']')
            break;
 
+          if (c == '%' && !has_scope_id)
+            {
+              has_scope_id = TRUE;
+              if (p[0] != '2' || p[1] != '5')
+                has_bad_scope_id = TRUE;
+              continue;
+            }
+
          /* unreserved /  sub-delims */
          if (!(g_ascii_isalnum (c) ||
                strchr (G_URI_OTHER_UNRESERVED, c) ||
@@ -578,6 +588,16 @@ _g_uri_parse_authority (const char  *uri,
                c == '.'))
            goto error;
        }
+
+      if (host)
+        {
+          if (has_bad_scope_id)
+            *host = g_strndup (start, p - start - 1);
+          else
+            *host = g_uri_unescape_segment (start, p - 1, NULL);
+        }
+
+      c = *p++;
     }
   else
     {
@@ -610,17 +630,14 @@ _g_uri_parse_authority (const char  *uri,
                strchr (G_URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS, c)))
            goto error;
        }
-    }
 
-  if (host)
-    *host = g_uri_unescape_segment (start, p - 1, NULL);
-
-  if (c == ']')
-    c = *p++;
+      if (host)
+        *host = g_uri_unescape_segment (start, p - 1, NULL);
+    }
 
   if (c == ':')
     {
-      /* Decode pot:
+      /* Decode port:
        *  port          = *DIGIT
        */
       guint tmp = 0;
index 7d7fd4f..addcbb4 100644 (file)
@@ -236,60 +236,6 @@ test_socket_address (void)
 }
 
 static void
-test_scope_id (void)
-{
-  GSocketConnectable *addr;
-  GSocketAddressEnumerator *addr_enum;
-  GSocketAddress *saddr;
-  GInetSocketAddress *isaddr;
-  GInetAddress *iaddr;
-  char *str, *tostring;
-  GError *error = NULL;
-  int index;
-#ifdef HAVE_IF_INDEXTONAME
-  char ifname[IF_NAMESIZE] = { 0 };
-#endif
-
-#ifdef HAVE_IF_INDEXTONAME
-  for (index = 1; index < 255; index++) {
-    if (if_indextoname (1, ifname))
-      break;
-  }
-  g_assert_cmpstr (ifname, !=, "");
-  str = g_strdup_printf ("fe80::42%%%s", ifname);
-#else
-  index = 1;
-  str = g_strdup ("fe80::42%1");
-#endif
-
-  addr = g_network_address_new (str, 99);
-  addr_enum = g_socket_connectable_enumerate (addr);
-  saddr = g_socket_address_enumerator_next (addr_enum, NULL, &error);
-  g_assert_no_error (error);
-
-  g_assert (saddr != NULL);
-  g_assert (G_IS_INET_SOCKET_ADDRESS (saddr));
-
-  isaddr = G_INET_SOCKET_ADDRESS (saddr);
-  g_assert_cmpint (g_inet_socket_address_get_scope_id (isaddr), ==, index);
-  g_assert_cmpint (g_inet_socket_address_get_port (isaddr), ==, 99);
-
-  iaddr = g_inet_socket_address_get_address (isaddr);
-  tostring = g_inet_address_to_string (iaddr);
-  g_assert_cmpstr (tostring, ==, "fe80::42");
-  g_free (tostring);
-
-  g_object_unref (saddr);
-  saddr = g_socket_address_enumerator_next (addr_enum, NULL, &error);
-  g_assert_no_error (error);
-  g_assert (saddr == NULL);
-
-  g_object_unref (addr_enum);
-  g_object_unref (addr);
-  g_free (str);
-}
-
-static void
 test_mask_parse (void)
 {
   GInetAddressMask *mask;
@@ -422,7 +368,6 @@ main (int argc, char *argv[])
   g_test_add_func ("/inet-address/bytes", test_bytes);
   g_test_add_func ("/inet-address/property", test_property);
   g_test_add_func ("/socket-address/basic", test_socket_address);
-  g_test_add_func ("/socket-address/scope-id", test_scope_id);
   g_test_add_func ("/address-mask/parse", test_mask_parse);
   g_test_add_func ("/address-mask/property", test_mask_property);
   g_test_add_func ("/address-mask/equal", test_mask_equal);
index 173e659..91648d7 100644 (file)
@@ -1,4 +1,7 @@
+#include "config.h"
+
 #include <gio/gio.h>
+#include <gio/gnetworking.h>
 
 static void
 test_basic (void)
@@ -35,7 +38,11 @@ static ParseTest uri_tests[] = {
   { "ftp://joe~:(*)%46@ftp.gnome.org:2020/start", "ftp", "ftp.gnome.org", 2020, -1 },
   { "ftp://[fec0::abcd]/start", "ftp", "fec0::abcd", 8080, -1 },
   { "ftp://[fec0::abcd]:999/start", "ftp", "fec0::abcd", 999, -1 },
-  { "ftp://joe%x-@ftp.gnome.org:2020/start", NULL, NULL, 0, G_IO_ERROR_INVALID_ARGUMENT }
+  { "ftp://joe%x-@ftp.gnome.org:2020/start", NULL, NULL, 0, G_IO_ERROR_INVALID_ARGUMENT },
+  { "http://[fec0::abcd%em1]/start", "http", "fec0::abcd%em1", 8080, -1 },
+  { "http://[fec0::abcd%25em1]/start", "http", "fec0::abcd%em1", 8080, -1 },
+  { "http://[fec0::abcd%10]/start", "http", "fec0::abcd%10", 8080, -1 },
+  { "http://[fec0::abcd%25em%31]/start", NULL, NULL, 0, G_IO_ERROR_INVALID_ARGUMENT }
 };
 
 static void
@@ -106,6 +113,114 @@ test_parse_host (gconstpointer d)
     g_error_free (error);
 }
 
+#define SCOPE_ID_TEST_ADDR "fe80::42"
+#define SCOPE_ID_TEST_PORT 99
+
+#ifdef HAVE_IF_INDEXTONAME
+static char SCOPE_ID_TEST_IFNAME[IF_NAMESIZE];
+static int SCOPE_ID_TEST_INDEX;
+#else
+#define SCOPE_ID_TEST_IFNAME "1"
+#define SCOPE_ID_TEST_IFINDEX 1
+#endif
+
+static void
+find_ifname_and_index (void)
+{
+  if (SCOPE_ID_TEST_INDEX != 0)
+    return;
+
+#ifdef HAVE_IF_INDEXTONAME
+  for (SCOPE_ID_TEST_INDEX = 1; SCOPE_ID_TEST_INDEX < 255; SCOPE_ID_TEST_INDEX++) {
+    if (if_indextoname (SCOPE_ID_TEST_INDEX, SCOPE_ID_TEST_IFNAME))
+      break;
+  }
+  g_assert_cmpstr (SCOPE_ID_TEST_IFNAME, !=, "");
+#endif
+}
+
+static void
+test_scope_id (GSocketConnectable *addr)
+{
+  GSocketAddressEnumerator *addr_enum;
+  GSocketAddress *saddr;
+  GInetSocketAddress *isaddr;
+  GInetAddress *iaddr;
+  char *tostring;
+  GError *error = NULL;
+
+  addr_enum = g_socket_connectable_enumerate (addr);
+  saddr = g_socket_address_enumerator_next (addr_enum, NULL, &error);
+  g_assert_no_error (error);
+
+  g_assert (saddr != NULL);
+  g_assert (G_IS_INET_SOCKET_ADDRESS (saddr));
+
+  isaddr = G_INET_SOCKET_ADDRESS (saddr);
+  g_assert_cmpint (g_inet_socket_address_get_scope_id (isaddr), ==, SCOPE_ID_TEST_INDEX);
+  g_assert_cmpint (g_inet_socket_address_get_port (isaddr), ==, SCOPE_ID_TEST_PORT);
+
+  iaddr = g_inet_socket_address_get_address (isaddr);
+  tostring = g_inet_address_to_string (iaddr);
+  g_assert_cmpstr (tostring, ==, SCOPE_ID_TEST_ADDR);
+  g_free (tostring);
+
+  g_object_unref (saddr);
+  saddr = g_socket_address_enumerator_next (addr_enum, NULL, &error);
+  g_assert_no_error (error);
+  g_assert (saddr == NULL);
+
+  g_object_unref (addr_enum);
+}
+
+static void
+test_host_scope_id (void)
+{
+  GSocketConnectable *addr;
+  char *str;
+
+  find_ifname_and_index ();
+
+  str = g_strdup_printf ("%s%%%s", SCOPE_ID_TEST_ADDR, SCOPE_ID_TEST_IFNAME);
+  addr = g_network_address_new (str, SCOPE_ID_TEST_PORT);
+  g_free (str);
+
+  test_scope_id (addr);
+  g_object_unref (addr);
+}
+
+static void
+test_uri_scope_id (void)
+{
+  GSocketConnectable *addr;
+  char *uri;
+  GError *error = NULL;
+
+  find_ifname_and_index ();
+
+  uri = g_strdup_printf ("http://[%s%%%s]:%d/foo",
+                         SCOPE_ID_TEST_ADDR,
+                         SCOPE_ID_TEST_IFNAME,
+                         SCOPE_ID_TEST_PORT);
+  addr = g_network_address_parse_uri (uri, 0, &error);
+  g_free (uri);
+  g_assert_no_error (error);
+
+  test_scope_id (addr);
+  g_object_unref (addr);
+
+  uri = g_strdup_printf ("http://[%s%%25%s]:%d/foo",
+                         SCOPE_ID_TEST_ADDR,
+                         SCOPE_ID_TEST_IFNAME,
+                         SCOPE_ID_TEST_PORT);
+  addr = g_network_address_parse_uri (uri, 0, &error);
+  g_free (uri);
+  g_assert_no_error (error);
+
+  test_scope_id (addr);
+  g_object_unref (addr);
+}
+
 int
 main (int argc, char *argv[])
 {
@@ -130,5 +245,8 @@ main (int argc, char *argv[])
       g_free (path);
     }
 
+  g_test_add_func ("/network-address/scope-id", test_host_scope_id);
+  g_test_add_func ("/network-address/uri-scope-id", test_uri_scope_id);
+
   return g_test_run ();
 }