diff --git a/client/afpuri.c b/client/afpuri.c index 7fa0f327b617d47afe2a4605d9daed1d53232cd3..583b2cfcaf08f8447c2902445b40da3bc6d6a2a4 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,33 @@ 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; + 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) + 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"); - - g_mount_spec_set (spec, "host", uri->host); - *path = g_strdup ("/"); + spec = g_mount_spec_new ("afp-server"); + *path = g_strdup ("/"); } - else + else { const char *volume, *volume_end; @@ -111,52 +110,42 @@ 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"); + tmp = g_strndup (volume + 2, volume_end - (volume + 2)); + *path = g_strconcat ("/", tmp, NULL); + } + else + { + char *tmp; + + spec = g_mount_spec_new ("afp-volume"); + 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); - 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_mount_spec_take (spec, "host", gvfs_add_ipv6_brackets (host)); - 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 +167,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 * diff --git a/client/gdaemonvfs.c b/client/gdaemonvfs.c index bae13eb36af04e210e347f87ec5b7ae2018e54f8..f64b2e3328d8eea1720c9aa588a7dbe50cb10aba 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; } diff --git a/client/gvfsuriutils.c b/client/gvfsuriutils.c index b7ddb6d93a6e68b4875aaf7503bda34ef312bab4..0502010eeb088d5bf5d1281c0f3db44058970456 100644 --- a/client/gvfsuriutils.c +++ b/client/gvfsuriutils.c @@ -23,310 +23,30 @@ #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) +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) { - GString *uri; - - uri = g_string_new (NULL); + g_autofree char *user = NULL, *h = NULL, *tmp = NULL, *p = NULL; - g_string_append (uri, decoded->scheme); - g_string_append (uri, "://"); - - if (decoded->host != NULL) + if (userinfo) + user = g_uri_escape_string (userinfo, G_URI_RESERVED_CHARS_ALLOWED_IN_USERINFO, allow_utf8); + if (host) { - 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_is_ipv6 (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); - } - } + tmp = gvfs_has_ipv6_brackets (host) ? g_strndup (host + 1, strlen (host) - 2) : g_strdup (host); - 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); + 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_string_free (uri, FALSE); + 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 3d5859318762dcfe378ee4ebf25f7eadbe5a3dfb..1f20bad089cccdadd52b10dffd72e6935583636c 100644 --- a/client/gvfsuriutils.h +++ b/client/gvfsuriutils.h @@ -27,22 +27,14 @@ 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, + const gchar *host, + gint port, + const gchar *path, + const gchar *query, + const gchar *fragment); G_END_DECLS diff --git a/client/httpuri.c b/client/httpuri.c index 0e65c7952753f32121545e0ef5bc2d96e0c92964..0ce17c6b93d4bfab43d743077e0dd6453f2248eb 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; diff --git a/client/smburi.c b/client/smburi.c index 93c17aab5c09e184273f23935958c751802238ff..a76dad130022ed300f060a9b4f21843090e3f0c5 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 * diff --git a/client/test-uri-utils.c b/client/test-uri-utils.c index 4f7e53d6c1b205f7144ad737ef3972391856acf7..48dbcec0a5637db583c4cdb923a20b6fea70cf9c 100644 --- a/client/test-uri-utils.c +++ b/client/test-uri-utils.c @@ -1,59 +1,59 @@ - -#include - +#include #include "gvfsuriutils.h" - +#include "gvfsutils.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++) { - 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; - } - 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_vfs_decoded_uri_free (decoded); + g_autofree char *encoded = NULL, *host = NULL; + g_autoptr(GUri) uri = NULL; + + 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); + 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), + 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); } - - 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 (); +} diff --git a/common/gvfsutils.c b/common/gvfsutils.c index 8e175d8cecece3cb6420f91f79ce696d9b21322d..7fa60b35a50cae1df2cae9101d96608bced6153e 100644 --- a/common/gvfsutils.c +++ b/common/gvfsutils.c @@ -19,6 +19,7 @@ #include +#include #include #include #include @@ -127,7 +128,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); @@ -136,3 +137,22 @@ gvfs_is_ipv6 (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 acaea9d203e5ef298031f1f29a841f25056cbf1d..bca83fb37eb043d8ce2cfa141f667364c7f7d5e2 100644 --- a/common/gvfsutils.h +++ b/common/gvfsutils.h @@ -30,7 +30,8 @@ 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); +char * gvfs_add_ipv6_brackets (const char *host); G_END_DECLS diff --git a/daemon/gvfsbackenddav.c b/daemon/gvfsbackenddav.c index 4ac94acafd7d331209009eb8e282961cd009c227..8d9eb8270c97b0ac803ecd446ec357bc06837d17 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 01b1de792474d04b3825d00e623edff8a9d07e9f..fb1ad9173667458c90aec283dd676d52cc233d31 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 3b11883e8722b22976fb1ebe3069162f91cc8f82..933bf648a0b6071c7450af3585b63a7535cb4934 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); diff --git a/meson.build b/meson.build index 9a772ce1adde57dad9a3a8328202773aaca1d022..c76cb3f44c29b63d381ed3d4d45cadba07a2edda 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')