From c069c51db5767ae0973e3bbbfd9f3a1d2b2320a3 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Mon, 19 Aug 2013 12:14:27 -0400 Subject: [PATCH] gnetworkaddress: allow IPv6 scope ids in URIs 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 | 31 +++++++++--- gio/tests/inet-address.c | 55 -------------------- gio/tests/network-address.c | 120 +++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 143 insertions(+), 63 deletions(-) diff --git a/gio/gnetworkaddress.c b/gio/gnetworkaddress.c index 394a21a..9586ffa 100644 --- a/gio/gnetworkaddress.c +++ b/gio/gnetworkaddress.c @@ -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; diff --git a/gio/tests/inet-address.c b/gio/tests/inet-address.c index 7d7fd4f..addcbb4 100644 --- a/gio/tests/inet-address.c +++ b/gio/tests/inet-address.c @@ -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); diff --git a/gio/tests/network-address.c b/gio/tests/network-address.c index 173e659..91648d7 100644 --- a/gio/tests/network-address.c +++ b/gio/tests/network-address.c @@ -1,4 +1,7 @@ +#include "config.h" + #include +#include 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 (); } -- 2.7.4