From 0edcafc518591669f0fa652712f36cc549826a9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Thu, 30 Jul 2020 10:32:42 +0400 Subject: [PATCH 01/11] uri/test: switch to GTest and fix testsuite MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit 2417271df21aa ("client: Ignore everything after first colon in userinfo"), the password field is skipped. Signed-off-by: Marc-André Lureau --- client/test-uri-utils.c | 67 ++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 37 deletions(-) diff --git a/client/test-uri-utils.c b/client/test-uri-utils.c index 4f7e53d6..53c732e3 100644 --- a/client/test-uri-utils.c +++ b/client/test-uri-utils.c @@ -1,59 +1,52 @@ - -#include - +#include #include "gvfsuriutils.h" - typedef struct { const char *uri; + const char *expected_uri; const char *expected_host; - guint expected_port; + int expected_port; } TestURIs; static TestURIs uris[] = { - { "https://[2001:0db8:85a3:08d3:1319:8a2e:0370:7344]:443/", "[2001:0db8:85a3:08d3:1319:8a2e:0370:7344]", 443 }, - { "http://test:443/", "test", 443 }, - { "http://test/", "test", -1 }, - { "http://windows-host:8080/C:/", "windows-host", 8080 }, - { "smb://user:password@192.192.192.192/foobar", "192.192.192.192", -1 }, - { "https://d134w4tst3t.s3.amazonaws.com/a?Signature=6VJ9%2BAdPVZ4Z7NnPShRvtDsLofc%3D&Expires=1249330377&AWSAccessKeyId=0EYZF4DV8A7WM0H73602", "d134w4tst3t.s3.amazonaws.com", -1 }, - { "dav+sd://foo%3Abar._webdav._tcp.local/", "foo:bar._webdav._tcp.local", -1 }, + { "https://[2001:0db8:85a3:08d3:1319:8a2e:0370:7344]:443/", NULL, "[2001:0db8:85a3:08d3:1319:8a2e:0370:7344]", 443 }, + { "http://test:443/", NULL, "test", 443 }, + { "http://test/", NULL, "test", -1 }, + { "http://windows-host:8080/C:/", NULL, "windows-host", 8080 }, + { "smb://user:password@192.192.192.192/foobar", "smb://user@192.192.192.192/foobar", "192.192.192.192", -1 }, + { "https://d134w4tst3t.s3.amazonaws.com/a?Signature=6VJ9%2BAdPVZ4Z7NnPShRvtDsLofc%3D&Expires=1249330377&AWSAccessKeyId=0EYZF4DV8A7WM0H73602", NULL, "d134w4tst3t.s3.amazonaws.com", -1 }, + { "dav+sd://foo%3Abar._webdav._tcp.local/", NULL, "foo:bar._webdav._tcp.local", -1 }, }; -int main (int argc, char **argv) +static void +test_decoded_uri (void) { guint i; for (i = 0; i < G_N_ELEMENTS (uris); i++) { + g_autofree char *encoded = NULL; GDecodedUri *decoded; - char *encoded; decoded = g_vfs_decode_uri (uris[i].uri); - if (decoded == NULL) { - g_warning ("Failed to parse \"%s\"", uris[i].uri); - return 1; - } - if (decoded->host == NULL || strcmp (decoded->host, uris[i].expected_host) != 0) { - g_warning ("Wrong host for \"%s\" (got '%s', expected '%s')", uris[i].uri, decoded->host, uris[i].expected_host); - g_vfs_decoded_uri_free (decoded); - return 1; - } - if (decoded->port != uris[i].expected_port) { - g_warning ("Wrong port for \"%s\"", uris[i].uri); - g_vfs_decoded_uri_free (decoded); - return 1; - } + g_assert_nonnull (decoded); + g_assert_cmpstr (decoded->host, ==, uris[i].expected_host); + g_assert_cmpint (decoded->port, ==, uris[i].expected_port); + encoded = g_vfs_encode_uri (decoded, TRUE); - if (encoded == NULL || strcmp (encoded, uris[i].uri) != 0) { - g_warning ("Failed to re-encode \"%s\" from '%s'", uris[i].uri, encoded); - g_vfs_decoded_uri_free (decoded); - g_free (encoded); - return 1; - } - g_free (encoded); + g_assert_cmpstr (encoded, ==, uris[i].expected_uri ?: uris[i].uri); + g_vfs_decoded_uri_free (decoded); } - - return 0; } +int +main (int argc, char **argv) +{ + setlocale (LC_ALL, ""); + + g_test_init (&argc, &argv, NULL); + + g_test_add_func ("/utils/decoded-uri", test_decoded_uri); + + return g_test_run (); +} -- GitLab From 84750ace9268291a534e37259472d9b5750b1879 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Thu, 30 Jul 2020 10:58:38 +0400 Subject: [PATCH 02/11] utils: rename gvfs_is_ipv6 -> gvfs_has_ipv6_brackets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let's be more specific about what the function is actually checking. We are going to introduce another function to check for IPv6 host. Signed-off-by: Marc-André Lureau --- client/gvfsuriutils.c | 2 +- common/gvfsutils.c | 2 +- common/gvfsutils.h | 2 +- daemon/gvfsbackenddav.c | 4 ++-- daemon/gvfsbackendsmb.c | 2 +- daemon/gvfsbackendsmbbrowse.c | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/client/gvfsuriutils.c b/client/gvfsuriutils.c index b7ddb6d9..a7267fb0 100644 --- a/client/gvfsuriutils.c +++ b/client/gvfsuriutils.c @@ -295,7 +295,7 @@ g_vfs_encode_uri (GDecodedUri *decoded, gboolean allow_utf8) g_string_append_c (uri, '@'); } - if (gvfs_is_ipv6 (decoded->host)) + if (gvfs_has_ipv6_brackets (decoded->host)) { g_string_append (uri, decoded->host); } diff --git a/common/gvfsutils.c b/common/gvfsutils.c index 8e175d8c..355adf67 100644 --- a/common/gvfsutils.c +++ b/common/gvfsutils.c @@ -127,7 +127,7 @@ gvfs_setup_debug_handler (void) } gboolean -gvfs_is_ipv6 (const char *host) +gvfs_has_ipv6_brackets (const char *host) { g_return_val_if_fail (host != NULL, FALSE); diff --git a/common/gvfsutils.h b/common/gvfsutils.h index acaea9d2..ea0ed89c 100644 --- a/common/gvfsutils.h +++ b/common/gvfsutils.h @@ -30,7 +30,7 @@ gboolean gvfs_get_debug (void); void gvfs_set_debug (gboolean debugging); void gvfs_setup_debug_handler (void); -gboolean gvfs_is_ipv6 (const char *host); +gboolean gvfs_has_ipv6_brackets (const char *host); G_END_DECLS diff --git a/daemon/gvfsbackenddav.c b/daemon/gvfsbackenddav.c index 4ac94aca..8d9eb827 100644 --- a/daemon/gvfsbackenddav.c +++ b/daemon/gvfsbackenddav.c @@ -1680,7 +1680,7 @@ g_mount_spec_to_dav_uri (GMountSpec *spec) soup_uri_set_user (uri, user); /* IPv6 host does not include brackets in SoupURI, but GMountSpec host does */ - if (gvfs_is_ipv6 (host)) + if (gvfs_has_ipv6_brackets (host)) uri->host = g_strndup (host + 1, strlen (host) - 2); else soup_uri_set_host (uri, host); @@ -1795,7 +1795,7 @@ dav_uri_from_dns_sd_resolver (GVfsBackendDav *dav_backend) soup_uri_set_port (uri, port); /* IPv6 host does not include brackets in SoupURI, but GVfsDnsSdResolver host does */ - if (gvfs_is_ipv6 (address)) + if (gvfs_has_ipv6_brackets (address)) { /* Link-local addresses require interface to be specified. */ if (g_str_has_prefix (address, "[fe80:") && interface != NULL) diff --git a/daemon/gvfsbackendsmb.c b/daemon/gvfsbackendsmb.c index 01b1de79..fb1ad917 100644 --- a/daemon/gvfsbackendsmb.c +++ b/daemon/gvfsbackendsmb.c @@ -335,7 +335,7 @@ create_smb_uri_string (const char *server, return uri; /* IPv6 server includes brackets in GMountSpec, smbclient doesn't */ - if (gvfs_is_ipv6 (server)) + if (gvfs_has_ipv6_brackets (server)) { g_string_append_uri_escaped (uri, server + 1, NULL, FALSE); g_string_truncate (uri, uri->len - 3); diff --git a/daemon/gvfsbackendsmbbrowse.c b/daemon/gvfsbackendsmbbrowse.c index 3b11883e..933bf648 100644 --- a/daemon/gvfsbackendsmbbrowse.c +++ b/daemon/gvfsbackendsmbbrowse.c @@ -865,7 +865,7 @@ do_mount (GVfsBackend *backend, resolver = g_resolver_get_default (); /* IPv6 server includes brackets in GMountSpec, GResolver doesn't */ - if (gvfs_is_ipv6 (op_backend->server)) + if (gvfs_has_ipv6_brackets (op_backend->server)) server = g_strndup (op_backend->server + 1, strlen (op_backend->server) - 2); else server = g_strdup (op_backend->server); -- GitLab From 8dd8cc7f4c5732a23e59a7a91af9e228e1483c7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Thu, 30 Jul 2020 11:15:50 +0400 Subject: [PATCH 03/11] utils: add a helper function to add ipv6 brackets on host MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GVfs uses ipv6 host with brackets. GUri & SoupURI etc do not. To avoid breaking GVfs inadvertently, let's keep the brackets. Signed-off-by: Marc-André Lureau --- common/gvfsutils.c | 20 ++++++++++++++++++++ common/gvfsutils.h | 1 + 2 files changed, 21 insertions(+) diff --git a/common/gvfsutils.c b/common/gvfsutils.c index 355adf67..7fa60b35 100644 --- a/common/gvfsutils.c +++ b/common/gvfsutils.c @@ -19,6 +19,7 @@ #include +#include #include #include #include @@ -136,3 +137,22 @@ gvfs_has_ipv6_brackets (const char *host) return TRUE; } + +static gboolean +gvfs_is_ipv6 (const char *host) +{ + struct in6_addr result; + + return inet_pton(AF_INET6, host, &result) == 1; +} + +char * +gvfs_add_ipv6_brackets (const char *host) +{ + g_return_val_if_fail (host != NULL, NULL); + + if (!gvfs_has_ipv6_brackets (host) && gvfs_is_ipv6 (host)) + return g_strdup_printf("[%s]", host); + + return g_strdup (host); +} diff --git a/common/gvfsutils.h b/common/gvfsutils.h index ea0ed89c..bca83fb3 100644 --- a/common/gvfsutils.h +++ b/common/gvfsutils.h @@ -31,6 +31,7 @@ void gvfs_set_debug (gboolean debugging void gvfs_setup_debug_handler (void); gboolean gvfs_has_ipv6_brackets (const char *host); +char * gvfs_add_ipv6_brackets (const char *host); G_END_DECLS -- GitLab From e53f34f7568ef00b7f7893a8e44c72714d2c3b21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Thu, 30 Jul 2020 14:59:11 +0400 Subject: [PATCH 04/11] build-sys: bump glib req >= 2.65.1 for GUri MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marc-André Lureau --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 9a772ce1..c76cb3f4 100644 --- a/meson.build +++ b/meson.build @@ -231,7 +231,7 @@ have_version_script = cc.has_link_argument('@0@,@1@'.format(version_script_ldfla gio_dep = dependency('gio-2.0') gio_unix_dep = dependency('gio-unix-2.0') -glib_dep = dependency('glib-2.0', version: '>= 2.57.2') +glib_dep = dependency('glib-2.0', version: '>= 2.65.1') gobject_dep = dependency('gobject-2.0') gsettings_desktop_schemas_dep = dependency('gsettings-desktop-schemas', version: '>= 3.33.0') -- GitLab From 55eaf9a48f42e06829dd0e3e81642d6423004dff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 29 Jul 2020 22:15:38 +0400 Subject: [PATCH 05/11] utils: introduce a g_vfs_join_uri() function around g_uri_join() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The later doesn't provide optional encoding utf8 handling. Let's do it by hand the same way g_vfs_encode_uri () does it. However g_uri_join() takes care of ipv6 brackets. Signed-off-by: Marc-André Lureau --- client/gvfsuriutils.c | 27 +++++++++++++++++++++++++++ client/gvfsuriutils.h | 8 ++++++++ client/test-uri-utils.c | 14 ++++++++++++++ 3 files changed, 49 insertions(+) diff --git a/client/gvfsuriutils.c b/client/gvfsuriutils.c index a7267fb0..e0f9ec77 100644 --- a/client/gvfsuriutils.c +++ b/client/gvfsuriutils.c @@ -330,3 +330,30 @@ g_vfs_encode_uri (GDecodedUri *decoded, gboolean allow_utf8) return g_string_free (uri, FALSE); } + +char * +g_vfs_join_uri (gboolean allow_utf8, + const gchar *scheme, + const gchar *userinfo, + const gchar *host, + gint port, + const gchar *path, + const gchar *query, + const gchar *fragment) +{ + g_autofree char *user = NULL, *h = NULL, *tmp = NULL, *p = NULL; + + if (userinfo) + user = g_uri_escape_string (userinfo, G_URI_RESERVED_CHARS_ALLOWED_IN_USERINFO, allow_utf8); + if (host) + { + tmp = gvfs_has_ipv6_brackets (host) ? g_strndup (host + 1, strlen (host) - 2) : g_strdup (host); + + h = g_hostname_is_ip_address (tmp) ? g_steal_pointer (&tmp) : g_uri_escape_string (tmp, G_URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS, allow_utf8); + } + if (path) + p = g_uri_escape_string (path, G_URI_RESERVED_CHARS_ALLOWED_IN_PATH, allow_utf8); + + return g_uri_join (G_URI_FLAGS_ENCODED, + scheme, user, h, port, p, query, fragment); +} diff --git a/client/gvfsuriutils.h b/client/gvfsuriutils.h index 3d585931..3e8993da 100644 --- a/client/gvfsuriutils.h +++ b/client/gvfsuriutils.h @@ -43,6 +43,14 @@ void g_vfs_decoded_uri_free (GDecodedUri *decoded); GDecodedUri *g_vfs_decode_uri (const char *uri); GDecodedUri *g_vfs_decoded_uri_new (void); +char * g_vfs_join_uri (gboolean allow_utf8, + const gchar *scheme, + const gchar *userinfo, + const gchar *host, + gint port, + const gchar *path, + const gchar *query, + const gchar *fragment); G_END_DECLS diff --git a/client/test-uri-utils.c b/client/test-uri-utils.c index 53c732e3..ccf0fa97 100644 --- a/client/test-uri-utils.c +++ b/client/test-uri-utils.c @@ -25,6 +25,7 @@ test_decoded_uri (void) for (i = 0; i < G_N_ELEMENTS (uris); i++) { g_autofree char *encoded = NULL; + g_autoptr(GUri) uri = NULL; GDecodedUri *decoded; decoded = g_vfs_decode_uri (uris[i].uri); @@ -35,6 +36,19 @@ test_decoded_uri (void) encoded = g_vfs_encode_uri (decoded, TRUE); g_assert_cmpstr (encoded, ==, uris[i].expected_uri ?: uris[i].uri); + uri = g_uri_parse (uris[i].uri, G_URI_FLAGS_HAS_PASSWORD|G_URI_FLAGS_ENCODED_QUERY|G_URI_FLAGS_ENCODED_FRAGMENT, NULL); + g_assert_nonnull (uri); + g_free (encoded); + encoded = g_vfs_join_uri (TRUE, + g_uri_get_scheme (uri), + g_uri_get_user (uri), + g_uri_get_host (uri), + g_uri_get_port (uri), + g_uri_get_path (uri), + g_uri_get_query (uri), + g_uri_get_fragment (uri)); + g_assert_cmpstr (encoded, ==, uris[i].expected_uri ?: uris[i].uri); + g_vfs_decoded_uri_free (decoded); } } -- GitLab From 591e87a6b667251671fa099ac4d8a4d01b7cb860 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 29 Jul 2020 22:16:48 +0400 Subject: [PATCH 06/11] http: switch to GUri MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Special care is taken when setting the "host" spec to add ipv6 brackets. On joining the URI to string, GUri already adds missing brackents. Signed-off-by: Marc-André Lureau --- client/httpuri.c | 104 ++++++++++++++++++++++------------------------- 1 file changed, 48 insertions(+), 56 deletions(-) diff --git a/client/httpuri.c b/client/httpuri.c index 0e65c795..0ce17c6b 100644 --- a/client/httpuri.c +++ b/client/httpuri.c @@ -27,6 +27,7 @@ #include #include +#include #include typedef struct _GVfsUriMapperHttp GVfsUriMapperHttp; @@ -79,16 +80,20 @@ http_from_uri (GVfsUriMapper *mapper, const char *uri_str, char **path) { + g_autoptr(GError) err = NULL; + g_autoptr(GUri) uri = NULL; GMountSpec *spec; gboolean ssl; - GDecodedUri *uri; - - uri = g_vfs_decode_uri (uri_str); + const char *host, *user; + uri = g_uri_parse (uri_str, G_URI_FLAGS_HAS_PASSWORD, &err); if (uri == NULL) - return NULL; + { + g_warning ("Failed to parse http URI: %s", err->message); + return NULL; + } - if (!g_ascii_strncasecmp (uri->scheme, "http", 4)) + if (!g_ascii_strncasecmp (g_uri_get_scheme (uri), "http", 4)) { spec = g_mount_spec_new ("http"); g_mount_spec_set (spec, "uri", uri_str); @@ -96,27 +101,29 @@ http_from_uri (GVfsUriMapper *mapper, else { spec = g_mount_spec_new ("dav"); - ssl = !g_ascii_strcasecmp (uri->scheme, "davs"); + ssl = !g_ascii_strcasecmp (g_uri_get_scheme (uri), "davs"); g_mount_spec_set (spec, "ssl", ssl ? "true" : "false"); - if (uri->host && *uri->host) - g_mount_spec_set (spec, "host", uri->host); + host = g_uri_get_host (uri); + if (host && *host) + { + g_autofree char *h = gvfs_add_ipv6_brackets (host); + g_mount_spec_set (spec, "host", h); + } - if (uri->userinfo && *uri->userinfo) - g_mount_spec_set (spec, "user", uri->userinfo); + user = g_uri_get_user (uri); + if (user && *user) + g_mount_spec_set (spec, "user", user); /* only set the port if it isn't the default port */ - if (uri->port != -1 && ! port_is_default_port (uri->port, ssl)) + if (g_uri_get_port (uri) != -1 && ! port_is_default_port (g_uri_get_port (uri), ssl)) { - char *port = g_strdup_printf ("%d", uri->port); + g_autofree char *port = g_strdup_printf ("%d", g_uri_get_port (uri)); g_mount_spec_set (spec, "port", port); - g_free (port); } } - *path = uri->path; - uri->path = NULL; - g_vfs_decoded_uri_free (uri); + *path = g_strdup (g_uri_get_path (uri)); return spec; } @@ -133,40 +140,36 @@ http_get_mount_spec_for_path (GVfsUriMapper *mapper, if (strcmp (type, "http") == 0) { + g_autoptr(GUri) uri = NULL; + g_autoptr(GError) err = NULL; + g_autofree char *new_uri = NULL; const char *uri_str; - char *new_uri; - GDecodedUri *uri; GMountSpec *new_spec; uri_str = g_mount_spec_get (spec, "uri"); - uri = g_vfs_decode_uri (uri_str); + uri = g_uri_parse (uri_str, G_URI_FLAGS_HAS_PASSWORD, &err); if (uri == NULL) - return NULL; - - if (strcmp (uri->path, new_path) == 0) { - g_vfs_decoded_uri_free (uri); + g_warning ("Failed to parse http URI: %s", err->message); return NULL; } - g_free (uri->path); - uri->path = g_strdup (new_path); - - g_free (uri->query); - uri->query = NULL; - - g_free (uri->fragment); - uri->fragment = NULL; + if (!g_strcmp0 (g_uri_get_path (uri), new_path)) + return NULL; new_spec = g_mount_spec_new ("http"); - new_uri = g_vfs_encode_uri (uri, TRUE); + new_uri = g_vfs_join_uri (TRUE, + g_uri_get_scheme (uri), + g_uri_get_user (uri), + g_uri_get_host (uri), + g_uri_get_port (uri), + new_path, + NULL, + NULL); g_mount_spec_set (new_spec, "uri", new_uri); - g_free (new_uri); - - g_vfs_decoded_uri_free (uri); return new_spec; } @@ -206,33 +209,22 @@ http_to_uri (GVfsUriMapper *mapper, } else { - GDecodedUri *decoded_uri; - int port_num; - - decoded_uri = g_new0 (GDecodedUri, 1); + int port_num; ssl = g_mount_spec_get (spec, "ssl"); host = g_mount_spec_get (spec, "host"); user = g_mount_spec_get (spec, "user"); port = g_mount_spec_get (spec, "port"); - if (ssl && strcmp (ssl, "true") == 0) - decoded_uri->scheme = g_strdup ("davs"); - else - decoded_uri->scheme = g_strdup ("dav"); - - decoded_uri->host = g_strdup (host); - decoded_uri->userinfo = g_strdup (user); - - if (port && (port_num = atoi (port))) - decoded_uri->port = port_num; - else - decoded_uri->port = -1; - - decoded_uri->path = g_strdup (path); - - res = g_vfs_encode_uri (decoded_uri, allow_utf8); - g_vfs_decoded_uri_free (decoded_uri); + port_num = port ? atoi (port) : 0; + res = g_vfs_join_uri (allow_utf8, + !g_strcmp0 (ssl, "true") ? "davs" : "dav", + user, + host, + port_num ? port_num : -1, + path, + NULL, + NULL); } return res; -- GitLab From 3fcbbc191696bd31ef6e9695c14eee99dd150f2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 29 Jul 2020 22:52:52 +0400 Subject: [PATCH 07/11] smb: switch to GUri MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Here as well, special care is taken to add back the ipv6 brackets. Signed-off-by: Marc-André Lureau --- client/smburi.c | 192 ++++++++++++++++++++++++------------------------ 1 file changed, 97 insertions(+), 95 deletions(-) diff --git a/client/smburi.c b/client/smburi.c index 93c17aab..a76dad13 100644 --- a/client/smburi.c +++ b/client/smburi.c @@ -27,6 +27,7 @@ #include #include #include +#include #define DEFAULT_SMB_PORT 445 @@ -81,108 +82,114 @@ smb_from_uri (GVfsUriMapper *mapper, const char *uri_str, char **path) { + g_autoptr(GError) err = NULL; + g_autoptr(GUri) uri = NULL; char *tmp; - const char *p; + const char *p, *host, *userinfo; const char *share, *share_end; - GDecodedUri *uri; GMountSpec *spec; - uri = g_vfs_decode_uri (uri_str); + uri = g_uri_parse (uri_str, G_URI_FLAGS_HAS_PASSWORD, &err); if (uri == NULL) - return NULL; + { + g_warning ("Failed to parse smb URI: %s", err->message); + return NULL; + } - if (uri->host == NULL || strlen (uri->host) == 0) + p = g_uri_get_path (uri); + host = g_uri_get_host (uri); + userinfo = g_uri_get_userinfo (uri); + if (host == NULL || strlen (host) == 0) { /* uri form: smb:/// or smb:///$path */ spec = g_mount_spec_new ("smb-network"); - if (uri->path == NULL || *uri->path == 0) - *path = g_strdup ("/"); + if (p == NULL || *p == 0) + *path = g_strdup ("/"); else - *path = g_strdup (uri->path); + *path = g_strdup (p); } else { + g_autofree char *h = gvfs_add_ipv6_brackets (host); + /* host set */ - p = uri->path; while (p && *p == '/') - p++; + p++; if (p == NULL || *p == 0) - { - /* uri form: smb://$host/ */ - spec = g_mount_spec_new ("smb-server"); - g_mount_spec_take (spec, "server", normalize_smb_name (uri->host, -1)); + { + /* uri form: smb://$host/ */ + spec = g_mount_spec_new ("smb-server"); + g_mount_spec_take (spec, "server", normalize_smb_name (h, -1)); - *path = g_strdup ("/"); - } + *path = g_strdup ("/"); + } else - { - share = p; - share_end = strchr (share, '/'); - if (share_end == NULL) - share_end = share + strlen (share); - - p = share_end; - - while (*p == '/') - p++; - - if (*p == 0) - { - /* uri form: smb://$host/$share/ - * Here we special case smb-server files by adding "._" to the names in the uri */ - if (share[0] == '.' && share[1] == '_') - { - spec = g_mount_spec_new ("smb-server"); - g_mount_spec_take (spec, "server", normalize_smb_name (uri->host, -1)); - - tmp = normalize_smb_name (share + 2, share_end - (share + 2)); - *path = g_strconcat ("/", tmp, NULL); - g_free (tmp); - } - else - { - spec = g_mount_spec_new ("smb-share"); - g_mount_spec_take (spec, "server", normalize_smb_name (uri->host, -1)); + { + share = p; + share_end = strchr (share, '/'); + if (share_end == NULL) + share_end = share + strlen (share); + + p = share_end; + + while (*p == '/') + p++; + + if (*p == 0) + { + /* uri form: smb://$host/$share/ + * Here we special case smb-server files by adding "._" to the names in the uri */ + if (share[0] == '.' && share[1] == '_') + { + spec = g_mount_spec_new ("smb-server"); + g_mount_spec_take (spec, "server", normalize_smb_name (h, -1)); + + tmp = normalize_smb_name (share + 2, share_end - (share + 2)); + *path = g_strconcat ("/", tmp, NULL); + g_free (tmp); + } + else + { + spec = g_mount_spec_new ("smb-share"); + g_mount_spec_take (spec, "server", normalize_smb_name (h, -1)); g_mount_spec_take (spec, "share", normalize_smb_name (share, share_end - share)); - *path = g_strdup ("/"); - } - } - else - { - spec = g_mount_spec_new ("smb-share"); - g_mount_spec_take (spec, "server", normalize_smb_name (uri->host, -1)); + *path = g_strdup ("/"); + } + } + else + { + spec = g_mount_spec_new ("smb-share"); + g_mount_spec_take (spec, "server", normalize_smb_name (h, -1)); g_mount_spec_take (spec, "share", normalize_smb_name (share, share_end - share)); - *path = g_strconcat ("/", p, NULL); - } - } + *path = g_strconcat ("/", p, NULL); + } + } /* only set the port if it isn't the default port */ - if (uri->port != -1 && uri->port != DEFAULT_SMB_PORT) - { - gchar *port = g_strdup_printf ("%d", uri->port); - g_mount_spec_take (spec, "port", port); - } + if (g_uri_get_port (uri) != -1 && g_uri_get_port (uri) != DEFAULT_SMB_PORT) + { + gchar *port = g_strdup_printf ("%d", g_uri_get_port (uri)); + g_mount_spec_take (spec, "port", port); + } } - if (uri->userinfo) + if (userinfo) { - const char *user = uri->userinfo; - p = strchr (uri->userinfo, ';'); + const char *user = userinfo; + p = strchr (userinfo, ';'); if (p) - { - if (p != user) - g_mount_spec_set_with_len (spec, "domain", user, p - user); - user = p + 1; - } + { + if (p != user) + g_mount_spec_set_with_len (spec, "domain", user, p - user); + user = p + 1; + } if (*user != 0) - g_mount_spec_set (spec, "user", user); + g_mount_spec_set (spec, "user", user); } - g_vfs_decoded_uri_free (uri); - return spec; } @@ -204,67 +211,62 @@ smb_to_uri (GVfsUriMapper *mapper, const char *path, gboolean allow_utf8) { + g_autofree char *p = NULL, *userinfo = NULL; const char *type; - const char *server; + const char *host = NULL; const char *share; const char *user; const char *domain; const char *port = NULL; - char *s; int port_num; - GDecodedUri *uri; - uri = g_new0 (GDecodedUri, 1); - type = g_mount_spec_get (spec, "type"); - uri->scheme = g_strdup ("smb"); - if (strcmp (type, "smb-network") == 0) { - uri->path = g_strdup (path); + p = g_strdup (path); } else if (strcmp (type, "smb-server") == 0) { - server = g_mount_spec_get (spec, "server"); - uri->host = g_strdup (server); + host = g_mount_spec_get (spec, "server"); /* Map the mountables in server to ._share because the actual share mount maps to smb://server/share */ if (path && path[0] == '/' && path[1] != 0) - uri->path = g_strconcat ("/._", path + 1, NULL); + p = g_strconcat ("/._", path + 1, NULL); else - uri->path = g_strdup ("/"); + p = g_strdup ("/"); port = g_mount_spec_get (spec, "port"); } else if (strcmp (type, "smb-share") == 0) { - server = g_mount_spec_get (spec, "server"); - uri->host = g_strdup (server); + host = g_mount_spec_get (spec, "server"); share = g_mount_spec_get (spec, "share"); if (path[0] == '/') - uri->path = g_strconcat ("/", share, path, NULL); + p = g_strconcat ("/", share, path, NULL); else - uri->path = g_strconcat ("/", share, "/", path, NULL); + p = g_strconcat ("/", share, "/", path, NULL); user = g_mount_spec_get (spec, "user"); domain = g_mount_spec_get (spec, "domain"); if (user) { if (domain) - uri->userinfo = g_strconcat (domain, ";", user, NULL); + userinfo = g_strconcat (domain, ";", user, NULL); else - uri->userinfo = g_strdup (user); + userinfo = g_strdup (user); } port = g_mount_spec_get (spec, "port"); } - if (port && (port_num = atoi (port))) - uri->port = port_num; - else - uri->port = -1; + port_num = port ? atoi (port) : 0; - s = g_vfs_encode_uri (uri, allow_utf8); - g_vfs_decoded_uri_free (uri); - return s; + return g_vfs_join_uri (allow_utf8, + "smb", + userinfo, + host, + port_num ? port_num : -1, + path, + NULL, + NULL); } static const char * -- GitLab From 84aadfab3059f473e539da11bb549615396266ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 29 Jul 2020 23:42:31 +0400 Subject: [PATCH 08/11] gdaemonvfs: switch to GUri MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Here as well, special care is taken to add back the ipv6 brackets. Signed-off-by: Marc-André Lureau --- client/gdaemonvfs.c | 169 ++++++++++++++++++-------------------------- 1 file changed, 69 insertions(+), 100 deletions(-) diff --git a/client/gdaemonvfs.c b/client/gdaemonvfs.c index bae13eb3..f64b2e33 100644 --- a/client/gdaemonvfs.c +++ b/client/gdaemonvfs.c @@ -178,7 +178,7 @@ get_mountspec_from_uri (GDaemonVfs *vfs, GMountSpec *spec; char *path; GVfsUriMapper *mapper; - char *scheme; + g_autofree char *scheme = NULL; scheme = g_uri_parse_scheme (uri); if (scheme == NULL) @@ -198,68 +198,63 @@ get_mountspec_from_uri (GDaemonVfs *vfs, if (spec == NULL) { - GDecodedUri *decoded; + g_autofree char *type = NULL, *userinfo = NULL, *host = NULL, *query = NULL, *fragment = NULL; MountableInfo *mountable; - char *type; - int l; + int port; + + if (g_uri_split (uri, G_URI_FLAGS_HAS_PASSWORD, + &type, + &userinfo, + &host, + &port, + &path, + &query, + &fragment, + NULL)) + { + mountable = get_mountable_info_for_scheme (vfs, type); + if (mountable) + { + g_free (type); + type = g_strdup (mountable->type); + } - decoded = g_vfs_decode_uri (uri); - if (decoded) - { - mountable = get_mountable_info_for_scheme (vfs, decoded->scheme); - - if (mountable) - type = mountable->type; - else - type = decoded->scheme; - - spec = g_mount_spec_new (type); - - if (decoded->host && *decoded->host) - { - if (mountable && mountable->host_is_inet) - { - /* Convert hostname to lower case */ - str_tolower_inplace (decoded->host); - - /* Remove brackets aroung ipv6 addresses */ - l = strlen (decoded->host); - if (decoded->host[0] == '[' && - decoded->host[l - 1] == ']') - g_mount_spec_set_with_len (spec, "host", decoded->host+1, l - 2); - else - g_mount_spec_set (spec, "host", decoded->host); - } - else - g_mount_spec_set (spec, "host", decoded->host); - } - - if (decoded->userinfo && *decoded->userinfo) - g_mount_spec_set (spec, "user", decoded->userinfo); - - if (decoded->port != -1 && - (mountable == NULL || - mountable->default_port == 0 || - mountable->default_port != decoded->port)) - { - char *port = g_strdup_printf ("%d", decoded->port); - g_mount_spec_set (spec, "port", port); - g_free (port); - } + spec = g_mount_spec_new (type); - if (decoded->query && *decoded->query) - g_mount_spec_set (spec, "query", decoded->query); - if (decoded->fragment && *decoded->fragment) - g_mount_spec_set (spec, "fragment", decoded->fragment); - - path = g_strdup (decoded->path); - - g_vfs_decoded_uri_free (decoded); - } + if (host && *host) + { + g_autofree char *h = gvfs_add_ipv6_brackets (host); + + if (mountable && mountable->host_is_inet) + { + /* Convert hostname to lower case */ + str_tolower_inplace (h); + + g_mount_spec_set (spec, "host", h); + } + else + g_mount_spec_set (spec, "host", h); + } + + if (userinfo && *userinfo) + g_mount_spec_set (spec, "user", userinfo); + + if (port != -1 && + (mountable == NULL || + mountable->default_port == 0 || + mountable->default_port != port)) + { + g_autofree char *p = g_strdup_printf ("%d", port); + g_mount_spec_set (spec, "port", p); + } + + if (query && *query) + g_mount_spec_set (spec, "query", query); + if (fragment && *fragment) + g_mount_spec_set (spec, "fragment", fragment); + } } - g_free (scheme); - if (spec == NULL) return FALSE; @@ -451,7 +446,7 @@ _g_daemon_vfs_get_uri_for_mountspec (GMountSpec *spec, char *path, gboolean allow_utf8) { - char *uri; + char *uri = NULL; const char *type; GVfsUriMapper *mapper; @@ -460,61 +455,35 @@ _g_daemon_vfs_get_uri_for_mountspec (GMountSpec *spec, { GString *string = g_string_new ("unknown://"); if (path) - g_string_append_uri_escaped (string, - path, - "!$&'()*+,;=:@/", - allow_utf8); + g_string_append_uri_escaped (string, + path, + "!$&'()*+,;=:@/", + allow_utf8); return g_string_free (string, FALSE); } - uri = NULL; mapper = g_hash_table_lookup (the_vfs->to_uri_hash, type); if (mapper) uri = g_vfs_uri_mapper_to_uri (mapper, spec, path, allow_utf8); if (uri == NULL) { - GDecodedUri decoded; MountableInfo *mountable; - const char *port; - gboolean free_host; - - memset (&decoded, 0, sizeof (decoded)); - decoded.port = -1; + const char *port, *scheme; mountable = get_mountable_info_for_type (the_vfs, type); - - if (mountable) - decoded.scheme = mountable->scheme; - else - decoded.scheme = (char *)type; - decoded.host = (char *)g_mount_spec_get (spec, "host"); - free_host = FALSE; - if (mountable && mountable->host_is_inet && decoded.host != NULL && strchr (decoded.host, ':') != NULL) - { - free_host = TRUE; - decoded.host = g_strconcat ("[", decoded.host, "]", NULL); - } - - decoded.userinfo = (char *)g_mount_spec_get (spec, "user"); + scheme = mountable ? mountable->scheme : type; port = g_mount_spec_get (spec, "port"); - if (port != NULL) - decoded.port = atoi (port); - - if (path == NULL) - decoded.path = "/"; - else - decoded.path = path; - - decoded.query = (char *)g_mount_spec_get (spec, "query"); - decoded.fragment = (char *)g_mount_spec_get (spec, "fragment"); - - uri = g_vfs_encode_uri (&decoded, FALSE); - - if (free_host) - g_free (decoded.host); - } + uri = g_vfs_join_uri (FALSE, + scheme, + g_mount_spec_get (spec, "user"), + g_mount_spec_get (spec, "host"), + port ? atoi (port) : -1, + path ? path : "/", + g_mount_spec_get (spec, "query"), + g_mount_spec_get (spec, "fragment")); + } return uri; } -- GitLab From 4d8c19f6dd0c8b5f7709dd12434f5b4fa8c7b8d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Thu, 30 Jul 2020 00:06:35 +0400 Subject: [PATCH 09/11] afp: switch to GUri MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Here as well, special care is taken to add ipv6 brackets. Signed-off-by: Marc-André Lureau --- client/afpuri.c | 176 ++++++++++++++++++++++-------------------------- 1 file changed, 81 insertions(+), 95 deletions(-) diff --git a/client/afpuri.c b/client/afpuri.c index 7fa0f327..545db1ea 100644 --- a/client/afpuri.c +++ b/client/afpuri.c @@ -29,6 +29,7 @@ #include #include #include +#include typedef struct _GVfsUriMapperAfp GVfsUriMapperAfp; typedef struct _GVfsUriMapperAfpClass GVfsUriMapperAfpClass; @@ -68,35 +69,37 @@ afp_from_uri (GVfsUriMapper *mapper, const char *uri_str, char **path) { - const char *p; - GDecodedUri *uri; + g_autoptr(GError) err = NULL; + g_autoptr(GUri) uri = NULL; + g_autofree char *h = NULL; + const char *p, *host; GMountSpec *spec; - uri = g_vfs_decode_uri (uri_str); - if (uri == NULL) - return NULL; + uri = g_uri_parse (uri_str, G_URI_FLAGS_HAS_PASSWORD, &err); + if (!uri) + { + g_warning ("Failed to parse afp URI: %s", err->message); + return NULL; + } - if (uri->host == NULL || strlen (uri->host) == 0) - { - g_vfs_decoded_uri_free (uri); + host = g_uri_get_host (uri); + if (host == NULL || *host == 0) return NULL; - } - else - { - /* host set */ - p = uri->path; - while (p && *p == '/') - p++; - if (p == NULL || *p == 0) + h = gvfs_add_ipv6_brackets (host); + p = g_uri_get_path (uri); + while (p && *p == '/') + p++; + + if (p == NULL || *p == 0) { /* uri form: afp://$host/ */ - spec = g_mount_spec_new ("afp-server"); + spec = g_mount_spec_new ("afp-server"); - g_mount_spec_set (spec, "host", uri->host); - *path = g_strdup ("/"); + g_mount_spec_set (spec, "host", h); + *path = g_strdup ("/"); } - else + else { const char *volume, *volume_end; @@ -111,52 +114,48 @@ afp_from_uri (GVfsUriMapper *mapper, p++; if (*p == 0) - { - /* uri form: afp://$host/$volume/ - * Here we special case afp-server files by adding "._" to the names in the uri */ - if (volume[0] == '.' && volume[1] == '_') { - char *tmp; - - spec = g_mount_spec_new ("afp-server"); - g_mount_spec_set (spec, "host", uri->host); - - tmp = g_strndup (volume + 2, volume_end - (volume + 2)); - *path = g_strconcat ("/", tmp, NULL); - g_free (tmp); + /* uri form: afp://$host/$volume/ + * Here we special case afp-server files by adding "._" to the names in the uri */ + if (volume[0] == '.' && volume[1] == '_') + { + g_autofree char *tmp; + + spec = g_mount_spec_new ("afp-server"); + g_mount_spec_set (spec, "host", h); + + tmp = g_strndup (volume + 2, volume_end - (volume + 2)); + *path = g_strconcat ("/", tmp, NULL); + } + else + { + char *tmp; + + spec = g_mount_spec_new ("afp-volume"); + g_mount_spec_set (spec, "host", h); + + tmp = g_strndup (volume, volume_end - volume); + g_mount_spec_take (spec, "volume", tmp); + + *path = g_strdup ("/"); + } } - else + else { char *tmp; spec = g_mount_spec_new ("afp-volume"); - g_mount_spec_set (spec, "host", uri->host); + g_mount_spec_set (spec, "host", h); tmp = g_strndup (volume, volume_end - volume); g_mount_spec_take (spec, "volume", tmp); - *path = g_strdup ("/"); + *path = g_strconcat ("/", p, NULL); } - } - else - { - char *tmp; - - spec = g_mount_spec_new ("afp-volume"); - g_mount_spec_set (spec, "host", uri->host); - - tmp = g_strndup (volume, volume_end - volume); - g_mount_spec_take (spec, "volume", tmp); - - *path = g_strconcat ("/", p, NULL); - } } - } - if (uri->userinfo) - g_mount_spec_set (spec, "user", uri->userinfo); - - g_vfs_decoded_uri_free (uri); + if (g_uri_get_user (uri)) + g_mount_spec_set (spec, "user", g_uri_get_user (uri)); return spec; } @@ -178,53 +177,40 @@ afp_to_uri (GVfsUriMapper *mapper, const char *path, gboolean allow_utf8) { - const char *type; - const char *host; - const char *port; - const char *user; - char *s; - GDecodedUri *uri; - - uri = g_new0 (GDecodedUri, 1); + g_autofree char *p = NULL; + const char *type, *volume; + int port = -1; type = g_mount_spec_get (spec, "type"); - uri->scheme = g_strdup ("afp"); - - host = g_mount_spec_get (spec, "host"); - uri->host = g_strdup (host); - - port = g_mount_spec_get (spec, "port"); - if (port) - uri->port = atoi (port); - else - uri->port = -1; - - user = g_mount_spec_get (spec, "user"); - uri->userinfo = g_strdup (user); - if (strcmp (type, "afp-server") == 0) - { - /* Map the mountables in server to ._share because the actual share mount maps to afp://host/share */ - if (path && path[0] == '/' && path[1] != 0) - uri->path = g_strconcat ("/._", path + 1, NULL); - else - uri->path = g_strdup ("/"); - } + { + /* Map the mountables in server to ._share because the actual share mount maps to afp://host/share */ + if (path && path[0] == '/' && path[1] != 0) + p = g_strconcat ("/._", path + 1, NULL); + else + p = g_strdup ("/"); + } else if (strcmp (type, "afp-volume") == 0) - { - const char *volume; - - volume = g_mount_spec_get (spec, "volume"); - if (path[0] == '/') - uri->path = g_strconcat ("/", volume, path, NULL); - else - uri->path = g_strconcat ("/", volume, "/", path, NULL); - } - - s = g_vfs_encode_uri (uri, allow_utf8); - g_vfs_decoded_uri_free (uri); - return s; + { + volume = g_mount_spec_get (spec, "volume"); + if (path[0] == '/') + p = g_strconcat ("/", volume, path, NULL); + else + p = g_strconcat ("/", volume, "/", path, NULL); + } + + if (g_mount_spec_get (spec, "port")) + port = atoi (g_mount_spec_get (spec, "port")); + + return g_vfs_join_uri (allow_utf8, + "afp", + g_mount_spec_get (spec, "user"), + g_mount_spec_get (spec, "host"), + port, + p, + NULL, + NULL); } static const char * -- GitLab From 1fe120b054d35b12cd1eaa59d6e2426845b68763 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Thu, 30 Jul 2020 14:34:07 +0400 Subject: [PATCH 10/11] afp: simplify, set the host in one place MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marc-André Lureau --- client/afpuri.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/client/afpuri.c b/client/afpuri.c index 545db1ea..583b2cfc 100644 --- a/client/afpuri.c +++ b/client/afpuri.c @@ -71,7 +71,6 @@ afp_from_uri (GVfsUriMapper *mapper, { g_autoptr(GError) err = NULL; g_autoptr(GUri) uri = NULL; - g_autofree char *h = NULL; const char *p, *host; GMountSpec *spec; @@ -86,7 +85,6 @@ afp_from_uri (GVfsUriMapper *mapper, if (host == NULL || *host == 0) return NULL; - h = gvfs_add_ipv6_brackets (host); p = g_uri_get_path (uri); while (p && *p == '/') p++; @@ -95,8 +93,6 @@ afp_from_uri (GVfsUriMapper *mapper, { /* uri form: afp://$host/ */ spec = g_mount_spec_new ("afp-server"); - - g_mount_spec_set (spec, "host", h); *path = g_strdup ("/"); } else @@ -122,8 +118,6 @@ afp_from_uri (GVfsUriMapper *mapper, g_autofree char *tmp; spec = g_mount_spec_new ("afp-server"); - g_mount_spec_set (spec, "host", h); - tmp = g_strndup (volume + 2, volume_end - (volume + 2)); *path = g_strconcat ("/", tmp, NULL); } @@ -132,11 +126,8 @@ afp_from_uri (GVfsUriMapper *mapper, char *tmp; spec = g_mount_spec_new ("afp-volume"); - g_mount_spec_set (spec, "host", h); - tmp = g_strndup (volume, volume_end - volume); g_mount_spec_take (spec, "volume", tmp); - *path = g_strdup ("/"); } } @@ -145,15 +136,14 @@ afp_from_uri (GVfsUriMapper *mapper, char *tmp; spec = g_mount_spec_new ("afp-volume"); - g_mount_spec_set (spec, "host", h); - tmp = g_strndup (volume, volume_end - volume); g_mount_spec_take (spec, "volume", tmp); - *path = g_strconcat ("/", p, NULL); } } + g_mount_spec_take (spec, "host", gvfs_add_ipv6_brackets (host)); + if (g_uri_get_user (uri)) g_mount_spec_set (spec, "user", g_uri_get_user (uri)); -- GitLab From 5fdbe04e0130a3ad024952b056f0d34a46c20a84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Thu, 30 Jul 2020 00:17:07 +0400 Subject: [PATCH 11/11] utils: remove GDecodedUri code --- client/gvfsuriutils.c | 307 ---------------------------------------- client/gvfsuriutils.h | 16 --- client/test-uri-utils.c | 21 +-- 3 files changed, 7 insertions(+), 337 deletions(-) diff --git a/client/gvfsuriutils.c b/client/gvfsuriutils.c index e0f9ec77..0502010e 100644 --- a/client/gvfsuriutils.c +++ b/client/gvfsuriutils.c @@ -23,313 +23,6 @@ #include #include "gvfsuriutils.h" #include "gvfsutils.h" -#include -#include - -void -g_vfs_decoded_uri_free (GDecodedUri *decoded) -{ - if (decoded == NULL) - return; - - g_free (decoded->scheme); - g_free (decoded->query); - g_free (decoded->fragment); - g_free (decoded->userinfo); - g_free (decoded->host); - g_free (decoded->path); - g_free (decoded); -} - -GDecodedUri * -g_vfs_decoded_uri_new (void) -{ - GDecodedUri *uri; - - uri = g_new0 (GDecodedUri, 1); - uri->port = -1; - - return uri; -} - -GDecodedUri * -g_vfs_decode_uri (const char *uri) -{ - GDecodedUri *decoded; - const char *p, *in, *hier_part_start, *hier_part_end, *query_start, *fragment_start; - char *out; - char c; - - /* From RFC 3986 Decodes: - * URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ] - */ - - p = uri; - - /* Decode scheme: - scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) - */ - - if (!g_ascii_isalpha (*p)) - return NULL; - - while (1) - { - c = *p++; - - if (c == ':') - break; - - if (!(g_ascii_isalnum(c) || - c == '+' || - c == '-' || - c == '.')) - return NULL; - } - - decoded = g_vfs_decoded_uri_new (); - - decoded->scheme = g_malloc (p - uri); - out = decoded->scheme; - for (in = uri; in < p - 1; in++) - *out++ = g_ascii_tolower (*in); - *out = 0; - - hier_part_start = p; - - query_start = strchr (p, '?'); - if (query_start) - { - hier_part_end = query_start++; - fragment_start = strchr (query_start, '#'); - if (fragment_start) - { - decoded->query = g_strndup (query_start, fragment_start - query_start); - decoded->fragment = g_strdup (fragment_start+1); - } - else - { - decoded->query = g_strdup (query_start); - decoded->fragment = NULL; - } - } - else - { - /* No query */ - decoded->query = NULL; - fragment_start = strchr (p, '#'); - if (fragment_start) - { - hier_part_end = fragment_start++; - decoded->fragment = g_strdup (fragment_start); - } - else - { - hier_part_end = p + strlen (p); - decoded->fragment = NULL; - } - } - - /* 3: - hier-part = "//" authority path-abempty - / path-absolute - / path-rootless - / path-empty - - */ - - if (hier_part_start[0] == '/' && - hier_part_start[1] == '/') - { - const char *authority_start, *authority_end; - const char *userinfo_start, *userinfo_end; - const char *host_start, *host_end; - const char *port_start; - - authority_start = hier_part_start + 2; - /* authority is always followed by / or nothing */ - authority_end = memchr (authority_start, '/', hier_part_end - authority_start); - if (authority_end == NULL) - authority_end = hier_part_end; - - /* 3.2: - authority = [ userinfo "@" ] host [ ":" port ] - */ - - /* Look for the last so that any multiple @ signs are put in the username part. - * This is not quite correct, as @ should be escaped here, but this happens - * in practice, so lets handle it the "nicer" way at least. */ - userinfo_end = g_strrstr_len (authority_start, - authority_end - authority_start, "@"); - if (userinfo_end) - { - char *p; - - host_start = userinfo_end + 1; - userinfo_start = authority_start; - - /* Applications should not render as clear text any data - * after the first colon (":") character found within a userinfo - * subcomponent unless the data after the colon is the empty string - * (indicating no password). Applications may choose to ignore or - * reject such data when it is received as part of a reference and - * should reject the storage of such data in unencrypted form. - * See https://tools.ietf.org/html/rfc3986 - */ - p = memchr (userinfo_start, ':', userinfo_end - userinfo_start); - if (p != NULL) - userinfo_end = p; - - decoded->userinfo = g_uri_unescape_segment (userinfo_start, userinfo_end, NULL); - if (decoded->userinfo == NULL) - { - g_vfs_decoded_uri_free (decoded); - return NULL; - } - } - else - host_start = authority_start; - - /* We should handle hostnames in brackets, as those are used by IPv6 URIs - * See http://tools.ietf.org/html/rfc2732 */ - if (*host_start == '[') - { - char *s; - - port_start = NULL; - host_end = memchr (host_start, ']', authority_end - host_start); - if (host_end == NULL) - { - g_vfs_decoded_uri_free (decoded); - return NULL; - } - - /* Look for the start of the port, - * And we sure we don't have it start somewhere - * in the path section */ - s = (char *) host_end; - while (1) - { - if (*s == '/') - { - port_start = NULL; - break; - } - else if (*s == ':') - { - port_start = s; - break; - } - else if (*s == '\0') - { - break; - } - - s++; - } - } - else - { - port_start = memchr (host_start, ':', authority_end - host_start); - } - - if (port_start) - { - host_end = port_start++; - - decoded->port = atoi(port_start); - } - else - { - host_end = authority_end; - decoded->port = -1; - } - - /* Let's use the IPv6 address without unescaping. This is needed in order - * to prevent g_uri_unescape_segment failures when zone identifier - * separated by the bare % as it is defined by RFC 4007 is used here. The - * zone identifier should contain just ASCII characters as per RFC 4007, - * so it doesn't need to be unescaped. I intentionally don't support here - * what is suggested by RFC 6874, which changes the separator to %25 and - * at the same time, it suggests that the bare % sign should still be - * accepted in user interfaces. Such a thing would make this too complex - * and lead to various problems (e.g. it would not be clear what separator - * should be used for g_file_get_uri function)... - */ - if (*host_start == '[') - decoded->host = g_strndup (host_start, host_end - host_start); - else - decoded->host = g_uri_unescape_segment (host_start, host_end, NULL); - - hier_part_start = authority_end; - } - - decoded->path = g_uri_unescape_segment (hier_part_start, hier_part_end, "/"); - - if (decoded->path == NULL) - { - g_vfs_decoded_uri_free (decoded); - return NULL; - } - - return decoded; -} - -char * -g_vfs_encode_uri (GDecodedUri *decoded, gboolean allow_utf8) -{ - GString *uri; - - uri = g_string_new (NULL); - - g_string_append (uri, decoded->scheme); - g_string_append (uri, "://"); - - if (decoded->host != NULL) - { - if (decoded->userinfo) - { - /* userinfo = *( unreserved / pct-encoded / sub-delims / ":" ) */ - g_string_append_uri_escaped (uri, decoded->userinfo, - G_URI_RESERVED_CHARS_ALLOWED_IN_USERINFO, allow_utf8); - g_string_append_c (uri, '@'); - } - - if (gvfs_has_ipv6_brackets (decoded->host)) - { - g_string_append (uri, decoded->host); - } - else - { - g_string_append_uri_escaped (uri, decoded->host, - /* Allowed unescaped in hostname / ip address */ - G_URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS, - allow_utf8); - } - - if (decoded->port != -1) - { - g_string_append_c (uri, ':'); - g_string_append_printf (uri, "%d", decoded->port); - } - } - - g_string_append_uri_escaped (uri, decoded->path, G_URI_RESERVED_CHARS_ALLOWED_IN_PATH, allow_utf8); - - if (decoded->query) - { - g_string_append_c (uri, '?'); - g_string_append (uri, decoded->query); - } - - if (decoded->fragment) - { - g_string_append_c (uri, '#'); - g_string_append (uri, decoded->fragment); - } - - return g_string_free (uri, FALSE); -} char * g_vfs_join_uri (gboolean allow_utf8, diff --git a/client/gvfsuriutils.h b/client/gvfsuriutils.h index 3e8993da..1f20bad0 100644 --- a/client/gvfsuriutils.h +++ b/client/gvfsuriutils.h @@ -27,22 +27,6 @@ G_BEGIN_DECLS -typedef struct { - char *scheme; - char *userinfo; - char *host; - int port; /* -1 => not in uri */ - char *path; - char *query; - char *fragment; -} GDecodedUri; - -char * g_vfs_encode_uri (GDecodedUri *decoded, - gboolean allow_utf8); -void g_vfs_decoded_uri_free (GDecodedUri *decoded); -GDecodedUri *g_vfs_decode_uri (const char *uri); -GDecodedUri *g_vfs_decoded_uri_new (void); - char * g_vfs_join_uri (gboolean allow_utf8, const gchar *scheme, const gchar *userinfo, diff --git a/client/test-uri-utils.c b/client/test-uri-utils.c index ccf0fa97..48dbcec0 100644 --- a/client/test-uri-utils.c +++ b/client/test-uri-utils.c @@ -1,5 +1,6 @@ #include #include "gvfsuriutils.h" +#include "gvfsutils.h" typedef struct { const char *uri; @@ -24,32 +25,24 @@ test_decoded_uri (void) guint i; for (i = 0; i < G_N_ELEMENTS (uris); i++) { - g_autofree char *encoded = NULL; + g_autofree char *encoded = NULL, *host = NULL; g_autoptr(GUri) uri = NULL; - GDecodedUri *decoded; - - decoded = g_vfs_decode_uri (uris[i].uri); - g_assert_nonnull (decoded); - g_assert_cmpstr (decoded->host, ==, uris[i].expected_host); - g_assert_cmpint (decoded->port, ==, uris[i].expected_port); - - encoded = g_vfs_encode_uri (decoded, TRUE); - g_assert_cmpstr (encoded, ==, uris[i].expected_uri ?: uris[i].uri); uri = g_uri_parse (uris[i].uri, G_URI_FLAGS_HAS_PASSWORD|G_URI_FLAGS_ENCODED_QUERY|G_URI_FLAGS_ENCODED_FRAGMENT, NULL); g_assert_nonnull (uri); - g_free (encoded); + host = gvfs_add_ipv6_brackets (g_uri_get_host (uri)); + g_assert_cmpstr (host, ==, uris[i].expected_host); + g_assert_cmpint (g_uri_get_port (uri), ==, uris[i].expected_port); + encoded = g_vfs_join_uri (TRUE, g_uri_get_scheme (uri), g_uri_get_user (uri), - g_uri_get_host (uri), + host, g_uri_get_port (uri), g_uri_get_path (uri), g_uri_get_query (uri), g_uri_get_fragment (uri)); g_assert_cmpstr (encoded, ==, uris[i].expected_uri ?: uris[i].uri); - - g_vfs_decoded_uri_free (decoded); } } -- GitLab